/* ============================================================
   Manager Dashboard — any restaurant
   Built for a busy pass: big targets, high contrast, no hunting.
   ============================================================ */
:root{
  /* ============================================================
     THE STAFF APP'S VISUAL SYSTEM (Nov 2026, second pass)
     ------------------------------------------------------------
     Brief, in Stu's words: premium, professional, luxury, minimalist,
     easy to use — a lot of features that must stop looking jumbled.

       1. Room. Generous padding, a 4px spacing scale used in big steps,
          and type set at 15px+ with real weight. Nothing is cramped.
       2. Few things at once. The rail shows ten rows, not seventeen;
          categories open in place. Each screen has one primary action.
       3. Soft, quiet surfaces. White sheets lifted off a pale ground by a
          faint shadow, not boxed in by lines. Lines only divide rows.
       4. Colour means something. The restaurant's colour on the main
          action and focus; status colours only for status.
     ============================================================ */
  --font:"Plus Jakarta Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;

  --bg:#f5f5f4;                       /* the ground: warm-neutral, barely there */
  --rail:#ffffff;
  --panel:#ffffff;
  --panel-2:#fafaf9;                  /* a well inside a sheet: board columns */
  --panel-solid:#ffffff;
  --card:#ffffff;
  --ink:#18181b;
  --ink-2:#3f3f46;
  --muted:#6b6b74;                    /* 5.2:1 on white */
  --faint:#a1a1aa;                    /* decoration only */

  --line:#ececec;
  --line-2:#f1f1f1;
  --line-3:#dcdcdf;
  --hover:#f6f6f5;
  --sunken:#f3f3f2;
  --edge:#ececec;
  --lift:0 0 0 0 transparent;
  --blur:none;
  --glass-line:#ececec;

  --brand:#1f2328;
  --brand-dk:#000000;
  --brand-ink:#ffffff;                /* always white — see Theme.dashboardVars */
  --brand-text:#1f2328;
  --brand-on-dark:#c9ccd2;
  --brand-ring:rgba(24,24,27,.14);
  --sel-ring:rgba(24,24,27,.08);
  --chart:#e4e4e7;

  --green:#2c7a4e;   --green-lt:#ecf6f0; --green-edge:#cfe7d9;
  --amber:#85600a;   --amber-lt:#fbf4e4; --amber-edge:#efdfb4;
  --red:#b6372b;     --red-lt:#fcefed;   --red-edge:#f3cdc8;
  --blue:#3556ad;    --blue-lt:#eef2fb;  --blue-edge:#d2dcf2;

  --status-success:var(--green);--status-success-bg:var(--green-lt);--status-success-edge:var(--green-edge);
  --status-warning:var(--amber);--status-warning-bg:var(--amber-lt);--status-warning-edge:var(--amber-edge);
  --status-danger:var(--red);--status-danger-bg:var(--red-lt);--status-danger-edge:var(--red-edge);
  --status-info:var(--blue);--status-info-bg:var(--blue-lt);--status-info-edge:var(--blue-edge);
  --status-neutral:#5f5f68;--status-neutral-bg:#f2f2f1;--status-neutral-edge:#e2e2e1;
  --focus:var(--brand);--focus-ring:0 0 0 3px var(--brand-ring);

  --motion-fast:120ms;--motion-base:200ms;--motion-slow:340ms;
  --ease-standard:cubic-bezier(.2,0,0,1);
  --ease-out:cubic-bezier(.16,1,.3,1);

  --r:8px;
  /* A sheet sits on the ground with a whisper of shadow; things that
     float (modals, menus, toasts) get a real one. */
  --shadow:0 1px 2px rgba(24,24,27,.04),0 1px 1px rgba(24,24,27,.02);
  --shadow-soft:0 1px 2px rgba(24,24,27,.04),0 4px 16px rgba(24,24,27,.04);
  --shadow-float:0 2px 6px rgba(24,24,27,.06),0 18px 48px rgba(24,24,27,.14);
  --shadow-lift:var(--shadow-float);
  --elevation-1:var(--shadow);--elevation-2:var(--shadow-soft);--elevation-3:var(--shadow-float);

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;

  /* ---- corners ----
     TWO radius systems, never merged:
       --r        the RESTAURANT's radius, from their theme (Appearance).
       --radius-* the OPERATIONAL scale for our own chrome. */
  --radius-sm:8px;      /* thumbs, swatches, tags */
  --radius-md:12px;     /* buttons, inputs, selects, rows */
  --radius-lg:18px;     /* sheets, cards, modals */
  --radius-pill:9999px; /* chips, counts, badges */
  --r-sm:var(--radius-sm); --r-md:var(--radius-md);
  --r-lg:var(--radius-lg); --r-pill:var(--radius-pill);

  /* Type, on a 16px root. */
  --t-micro:.78rem;   /* 12.5px: badges, captions */
  --t-small:.875rem;  /* 14px: secondary text, labels */
  --t-body:.9375rem;  /* 15px: default UI text */
  --t-lead:1.0625rem; /* 17px: card titles */
  --t-h2:1.125rem;    /* 18px: sheet headings */
  --t-h1:1.875rem;    /* 30px: page headings */
  --t-num:2rem;       /* 32px: the figure on a stat */

  --icon-sm:15px;--icon-md:18px;--icon-lg:21px;
  --ic:var(--icon-md);
}
/* Figures: times, references, counts, money. Same family, heavier, and
   tabular so columns of numbers line up. */
.fig,.stat .num,.tk-time,.tk-ref,.ref,.kds-ref,.kds-timer b,.floor-clock b,.col-head .n,
.tbl td.time,.diary-time,.t-time{
  font-family:var(--font);font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em
}
*{box-sizing:border-box;margin:0;padding:0}
body{
  font-family:var(--font);
  color:var(--ink);font-size:var(--t-body);font-weight:450;line-height:1.55;
  -webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;
  /* Fixed, so the wash belongs to the window rather than scrolling with
     the content — panes then move over a still ground, which is what
     makes them read as panes.

     The ground has to keep some actual tone. The first attempt washed it
     almost to white, and a 72%-white pane over near-white is just a white
     box: there was nothing for the translucency to be translucent
     against. Roughly eight points of lightness between ground and pane is
     enough to read as glass and still quiet enough to work in front of
     all day. */
  background:var(--bg);
  background-attachment:fixed
}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
a{color:inherit;text-decoration:none}
.spacer{margin-left:auto}

/* ============================================================
   ZERO-LAYOUT-SHIFT STATUS CONTRACT
   ------------------------------------------------------------
   Dynamic feedback owns a fixed slot before it exists. The child is
   taken out of flow and may animate only opacity and transform, so a
   state change can never alter a grid track, flex line or row height.

   Usage:
     <span class="status-slot" style="--status-slot-inline:8rem">
       <span class="fade-badge is-visible">Saved</span>
     </span>

   Do not add display toggles, intrinsic padding or auto dimensions to
   these two primitives. A new status component must size the slot, not
   the message inside it.
   ============================================================ */
.status-slot{
  --status-slot-inline:8rem;--status-slot-block:2rem;
  position:relative;display:inline-block;
  inline-size:var(--status-slot-inline);block-size:var(--status-slot-block);
  min-inline-size:var(--status-slot-inline);min-block-size:var(--status-slot-block);
  flex:0 0 var(--status-slot-inline);contain:layout paint;overflow:hidden
}
.fade-badge{
  position:absolute;inset:0;display:inline-flex;align-items:center;justify-content:flex-start;
  inline-size:100%;block-size:100%;box-sizing:border-box;overflow:hidden;
  opacity:0;transform:translateY(2px);pointer-events:none;
  transition:opacity var(--motion-base) var(--ease-standard),
    transform var(--motion-base) var(--ease-standard)
}
.fade-badge.is-visible{opacity:1;transform:translateY(0);pointer-events:auto}
.count-slot{
  inline-size:24px;min-inline-size:24px;block-size:20px;flex:0 0 24px;
  display:inline-grid;place-items:center;overflow:hidden;font-variant-numeric:tabular-nums;
  opacity:0;transform:scale(.92);pointer-events:none;
  transition:opacity var(--motion-base) var(--ease-standard),
    transform var(--motion-base) var(--ease-standard)
}
.count-slot.is-visible{opacity:1;transform:scale(1)}
@media (prefers-reduced-motion:reduce){.fade-badge{transition:none;transform:none}}
@media (prefers-reduced-motion:reduce){.count-slot{transition:none;transform:none}}

/* ============================================================
   BUTTONS — one system, consistent optical centring.
   min-height + line-height:1 keeps glyphs on the same baseline
   whether or not the label contains an emoji or a descender.
   ============================================================ */
.b{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:42px;padding:0 18px;border-radius:var(--radius-md);
  font-size:.9rem;font-weight:600;line-height:1;letter-spacing:0;
  white-space:nowrap;transition:background var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard),color var(--motion-fast) var(--ease-standard),
    transform var(--motion-fast) var(--ease-standard);
  border:1px solid transparent;vertical-align:middle;text-align:center
}
.b:active{transform:translateY(1px)}
.b:focus-visible{outline:none;box-shadow:var(--focus-ring)}
.b-sm{min-height:36px;padding:0 14px;font-size:.85rem;border-radius:var(--radius-md);gap:6px}
.b-lg{min-height:50px;padding:0 24px;font-size:.95rem}
.b-icon{padding:0;width:42px}
.b-icon.b-sm{width:36px}

/* The one filled colour on a screen: the action that moves the work on. */
.b-pri{background:var(--brand);color:var(--brand-ink)}   /* --brand-ink is white, always */
.b-pri:hover{background:var(--brand-dk)}
.b-dark{background:var(--ink);color:#fff}
.b-dark:hover{background:#000}
/* Secondary actions are quiet: a hairline and the ink colour. */
.b-out{border-color:var(--line-3);background:var(--panel);color:var(--ink);box-shadow:var(--shadow)}
.b-out:hover{border-color:var(--line-3);background:var(--hover)}
.b-green{background:var(--green);color:#fff}
.b-green:hover{background:#246340}
/* A destructive action is said by its word and its colour, not by a
   pink box on every row. */
.b-red{background:transparent;color:var(--red);border-color:transparent}
.b-red:not(:hover){box-shadow:none}
.b-red:hover{background:var(--red);color:#fff;border-color:var(--red)}
.b:disabled{opacity:.4;cursor:not-allowed;transform:none}

/* ============================================================
   ICONS
   ------------------------------------------------------------
   One stroke set, drawn once as <symbol>s at the top of the page and
   referenced with <use>. They inherit currentColor, so the same icon is
   white in the dark sidebar, grey on an outline button and red in an
   alert chip without a second copy existing anywhere.

   This replaced emoji. Emoji are a font, and a different font on every
   platform: the sidebar rendered in full colour on a Mac, flat glyphs on
   Windows and a third weight again on an Android till. Nothing that
   varies by operating system can carry a product's visual identity.
   ============================================================ */
.ic{
  width:var(--ic);height:var(--ic);flex:0 0 var(--ic);display:block;
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;vertical-align:middle
}
.b .ic{width:var(--icon-sm);height:var(--icon-sm);flex-basis:var(--icon-sm)}
/* The shared icon scale. Nothing in the markup reaches for these three
   by name today, but they are the sizes everything else is derived from
   and suite-09 pins them as the contract — so they stay named rather
   than becoming three magic numbers scattered through the file. */
.icon-sm{width:var(--icon-sm);height:var(--icon-sm);flex-basis:var(--icon-sm)}
.icon-md{width:var(--icon-md);height:var(--icon-md);flex-basis:var(--icon-md)}
.icon-lg{width:var(--icon-lg);height:var(--icon-lg);flex-basis:var(--icon-lg)}
.b-lg .ic{width:var(--icon-md);height:var(--icon-md);flex-basis:var(--icon-md)}
:where(button,a,input,select,textarea,[tabindex]):focus-visible{
  outline:2px solid var(--focus);outline-offset:2px
}

/* Any cluster of buttons in a row/cell */
.acts{display:flex;align-items:center;gap:6px;justify-content:flex-end;flex-wrap:nowrap}

/* ============================================================
   LOGIN
   ============================================================ */
.login{min-height:100vh;display:grid;place-items:center;background:var(--bg);padding:20px}
.login-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);padding:48px 44px;width:100%;max-width:420px;text-align:left;box-shadow:var(--shadow-soft)}
.login-card h1,.login-card h2{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;line-height:1.25}
.login-mark{width:48px;height:48px;border-radius:var(--radius-md);margin:0 0 24px;background:var(--brand);color:var(--brand-ink);display:grid;place-items:center;font-weight:800;font-size:1rem}
.auth-form{display:grid;gap:14px;margin-top:24px;text-align:left}
.auth-form .fld{margin:0}
.auth-form>.b{width:100%;margin-top:2px}
.password-field{position:relative}
.password-field .in{width:100%;padding-right:46px}
.password-toggle{position:absolute;right:4px;top:50%;width:38px;height:38px;transform:translateY(-50%);display:grid;place-items:center;color:var(--muted);border-radius:var(--radius-sm)}
.password-toggle:hover,.password-toggle:focus-visible{color:var(--ink);background:var(--sunken)}
.auth-message{
  font-size:.83rem;color:var(--red);margin-top:12px;height:2.8em;overflow:auto;
  text-align:left;contain:layout
}
.auth-hint{font-size:.76rem;color:var(--muted);margin-top:12px;line-height:1.6;text-align:left}
.auth-form .in[aria-invalid="true"]{border-color:var(--red);box-shadow:0 0 0 3px var(--red-lt)}

/* ============================================================
   SHELL
   ============================================================ */
.shell{display:grid;grid-template-columns:272px 1fr;min-height:100vh}
body.sidebar-collapsed .shell{grid-template-columns:1fr}
body.sidebar-collapsed .side{display:none}
/* min-width:0 on both grid children is load-bearing: a grid item's
   min-content width would otherwise push the document wider than the
   screen. */
.side{
  background:var(--rail);color:var(--ink-2);padding:24px 16px 20px;border-right:1px solid var(--line);
  display:flex;flex-direction:column;gap:4px;
  position:sticky;top:0;height:100vh;min-width:0;z-index:90
}
.side .logo{display:flex;align-items:center;gap:12px;color:var(--ink);font-weight:700;font-size:1rem;letter-spacing:-.01em;line-height:1.25;padding:0 10px 24px}
.side .logo .m{width:36px;height:36px;border-radius:var(--radius-md);background:var(--brand);color:var(--brand-ink);display:grid;place-items:center;font-size:.8rem;font-weight:800;flex:0 0 36px}
.side nav{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;margin:0 -6px;padding:0 6px 12px;scrollbar-width:thin}
.side nav button{
  display:flex;align-items:center;gap:12px;width:100%;min-height:42px;flex:0 0 auto;padding:0 12px;border-radius:var(--radius-md);
  font-size:.9375rem;font-weight:500;line-height:1.2;color:var(--ink-2);transition:background var(--motion-fast),color var(--motion-fast);text-align:left
}
.side nav button .ic{color:var(--muted);width:19px;height:19px;flex-basis:19px}
.side nav button:hover{background:var(--hover);color:var(--ink)}
.side nav button:focus-visible{outline:none;box-shadow:var(--focus-ring)}
/* Where you are is said by fill and weight, not by a bar down the left. */
.side nav button.on{background:var(--sunken);color:var(--ink);font-weight:650}
.side nav button.on .ic{color:var(--ink)}
.side nav .badge{margin-left:auto;background:var(--red);color:#fff;border-radius:var(--radius-pill);font-size:.72rem;font-weight:700;line-height:1;text-align:center}

/* A category: a row that opens in place. The screens inside are
   indented to sit under its label, without icons of their own. */
.nav-group{display:flex;flex-direction:column}
.nav-heading .nav-chev{width:16px;height:16px;flex-basis:16px;transition:transform var(--motion-base) var(--ease-out)}
.nav-group.open>.nav-heading .nav-chev{transform:rotate(180deg)}
.nav-group.has-active>.nav-heading{color:var(--ink);font-weight:600}
.nav-group.has-active>.nav-heading .ic{color:var(--ink)}
.nav-items{display:none;flex-direction:column;gap:2px;padding:2px 0 6px}
.nav-group.open>.nav-items{display:flex}
.side nav .nav-items button{min-height:38px;padding-left:43px;font-size:.9rem}
/* A shut category still says something is waiting inside it. */
.nav-heading>span{flex:1;min-width:0}
.nav-heading .nav-chev{order:4;color:var(--faint)!important}
.nav-group:not(.open):has(.badge.is-visible)>.nav-heading::after{
  content:"";width:8px;height:8px;border-radius:50%;background:var(--faint);flex:0 0 8px;order:3
}
.nav-group:not(.open):has(#kitBadge.is-visible)>.nav-heading::after{background:var(--red)}

/* Counts that mean work is waiting now are red. A job for later
   (allergens, messages, sign-ups, stock) is grey. */
#algBadge,#subBadge,#msgBadge,#stockBadge{background:var(--sunken)!important;color:var(--ink-2)!important}
/* Settings stands apart from the categories above it. */
.side nav>.nav-solo:last-child{margin-top:12px}
.side .foot{margin-top:auto;flex:0 0 auto;font-size:.875rem;color:var(--muted);padding:16px 12px 0;border-top:1px solid var(--line);line-height:1.5}
.side .foot a{color:var(--ink-2)}
.side .foot a:hover{color:var(--ink);text-decoration:underline}
.who-name{color:var(--ink);font-weight:650}
.who-role{color:var(--muted)}
.who-acts{display:flex;gap:16px;margin-top:8px}
/* The drawer's backdrop: only on a phone or a tablet, only when open. */
.nav-scrim{display:none}

.main{padding:0 48px 80px;max-width:none;min-width:0}
/* Every screen sits in one centred column, so a wide monitor gets
   margins rather than a sprawl. The order boards are allowed wider. */
.main>.view{max-width:1360px;margin-left:auto;margin-right:auto}
.main>#v-kitchen,.main>#v-orders{max-width:1680px}
.global-tools{
  display:flex;align-items:center;gap:4px;height:68px;margin:0 -48px 40px;padding:0 48px;
  position:sticky;top:0;z-index:70;background:rgba(245,245,244,.92);border-bottom:1px solid var(--line);
  -webkit-backdrop-filter:saturate(160%) blur(12px);backdrop-filter:saturate(160%) blur(12px)
}
.workspace-context{display:flex;align-items:baseline;gap:10px;margin-left:12px;min-width:0}
.workspace-context span{color:var(--muted);font-size:.9rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.workspace-context b{font-size:.9rem;font-weight:650;padding-left:12px;border-left:1px solid var(--line-3);white-space:nowrap}
.tool-icon{
  width:42px;height:42px;display:inline-grid;place-items:center;position:relative;
  border:1px solid transparent;border-radius:var(--radius-md);background:transparent;color:var(--ink-2);box-shadow:none
}
.tool-icon:hover,.tool-icon[aria-expanded="true"]{border-color:var(--line-3);color:var(--ink);background:var(--hover)}
.tool-count{
  position:absolute;top:-5px;right:-5px;width:18px;height:18px;place-items:center;border:2px solid var(--bg);
  border-radius:50%;background:var(--red);color:#fff;font-size:.64rem;font-weight:800;line-height:1
}
.global-tasks{position:relative}
.tool-clock{font-weight:650;font-variant-numeric:tabular-nums;font-size:.95rem;color:var(--ink-2);margin-right:12px}
.tool-link{display:inline-flex;align-items:center;gap:8px;height:42px;padding:0 14px;border-radius:var(--radius-md);color:var(--ink-2);font-size:.9rem;font-weight:550}
.tool-link .ic{width:14px;height:14px;flex-basis:14px}
.tool-link:hover{background:var(--hover);color:var(--ink)}
.task-popover{
  position:absolute;right:0;top:calc(100% + 8px);width:min(390px,calc(100vw - 24px));max-height:70vh;overflow:auto;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel-solid);
  box-shadow:var(--shadow-lift);
  opacity:0;visibility:hidden;transform:translateY(-5px);pointer-events:none;transition:.14s
}
.task-popover.open{opacity:1;visibility:visible;transform:translateY(0);pointer-events:auto}
.task-popover-head{display:flex;align-items:baseline;justify-content:space-between;padding:13px 14px;border-bottom:1px solid var(--line)}
.task-popover-head span{font-size:var(--t-small);color:var(--muted)}
.task-popover-row{display:flex;width:100%;gap:var(--s3);align-items:center;text-align:left;padding:13px 14px;border-bottom:1px solid var(--line-2)}
.task-popover-row:hover{background:var(--hover)}
.task-popover-row>span{flex:1;min-width:0}
.task-popover-row b,.task-popover-row small{display:block;line-height:1.4}
.task-popover-row b{font-size:var(--t-body)}
.task-popover-row small{margin-top:2px;color:var(--muted);font-size:var(--t-small)}
.task-popover-row strong{font-size:var(--t-small);color:var(--brand-text);white-space:nowrap}
.task-popover-empty{padding:24px 14px;text-align:center;color:var(--muted);font-size:var(--t-small)}
.topbar{display:flex;align-items:flex-end;gap:12px;margin-bottom:32px;flex-wrap:wrap}
.topbar h1{font-size:var(--t-h1);font-weight:700;letter-spacing:-.025em;line-height:1.15}
.topbar .sub{color:var(--muted);font-size:1rem;margin-top:8px;max-width:62ch;line-height:1.5}
/* Said only when the calendar and the service have parted company —
   between midnight and the rollover hour. The rest of the time it is
   hidden, because a line explaining the obvious is noise. */
.service-note{color:var(--amber);font-weight:600;margin-top:3px}
.settings-tabs{
  display:flex;gap:32px;margin-bottom:32px;padding:0;border-bottom:1px solid var(--line);
  border-radius:0;background:transparent;overflow-x:auto
}
.settings-tabs button{min-height:48px;padding:0 1px;border-radius:0;color:var(--muted);font-size:.95rem;font-weight:550;white-space:nowrap;border-bottom:2px solid transparent;margin-bottom:-1px}
.settings-tabs button:hover{color:var(--ink)}
.settings-tabs button.on{color:var(--ink);font-weight:650;background:transparent;border-bottom-color:var(--ink)}
[data-settings-section][hidden]{display:none!important}

/* ============================================================
   STATS
   ============================================================ */
/* Figures as their own quiet cards. Columns are balanced by count, so
   six stats are 3 + 3 and never 4 + 2 with an orphaned pair. */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:40px}
.stats:has(>:nth-child(5)){grid-template-columns:repeat(5,minmax(0,1fr))}
.stats:has(>:nth-child(6)){grid-template-columns:repeat(3,minmax(0,1fr))}
.stats:has(>:nth-child(7)){grid-template-columns:repeat(4,minmax(0,1fr))}
.stats:has(>:nth-child(9)){grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);padding:20px 24px;box-shadow:var(--shadow);min-width:0;display:flex;flex-direction:column}
.stat .lbl{order:1;font-size:.9rem;color:var(--muted);font-weight:550;line-height:1.3}
.stat .num{order:2;font-size:var(--t-num);line-height:1.1;margin-top:8px}
.stat .sub{order:3;font-size:.875rem;color:var(--muted);margin-top:4px;line-height:1.4}
.stat.accent{background:var(--panel);color:var(--ink)}
.stat.accent .lbl{color:var(--muted)}
.stat.accent .sub{color:var(--muted)}
.stat.warn{background:var(--panel)}
.stat.warn .num{color:var(--amber)}

/* A standing chore: says what is outstanding, why it matters, and gives
   one way to deal with it. Deliberately quiet — these are not alerts. */
.task-card{
  display:flex;align-items:center;gap:var(--s3);justify-content:space-between;
  border:1px solid var(--line);background:var(--panel);border-radius:var(--radius-lg);
  padding:18px 22px;box-shadow:var(--shadow)
}
.task-card b{display:block;font-size:var(--t-body);line-height:1.3}
.task-card span{display:block;color:var(--muted);font-size:var(--t-small);line-height:1.4;margin-top:2px}
.task-card .b{flex:0 0 auto}
.task-card.done{border-color:var(--green-edge);background:var(--green-lt)}
/* ============================================================
   PANELS
   ============================================================ */
/* min-width:0 for the same reason the shell needs it: a panel is
   regularly a grid or flex item, and its min-content width is set by
   whatever table is inside it. Without this, a 560px table in a .g2
   column pushed the whole Insights page to 574px inside a 390px phone
   — the table has its own scroller, but the panel around it was never
   allowed to be narrower than the thing it was supposed to be clipping. */
.panel{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);
  margin-bottom:32px;min-width:0;box-shadow:var(--shadow-soft)
}
.panel-head{padding:20px 28px;border-bottom:1px solid var(--line-2);display:flex;align-items:center;gap:14px;flex-wrap:wrap;min-height:72px}
.panel-head h2{font-size:var(--t-h2);font-weight:700;line-height:1.3;letter-spacing:-.015em}
.panel-head .sub{color:var(--muted);font-size:.9rem}
.panel-body{padding:28px}
.panel-body.flush{padding:0}

/* ============================================================
   KANBAN
   ============================================================ */
/* Six stages: table service has a served-but-open-check stage and
   deliveries have "On the road". Driven
   from the COLS array's length so adding a stage never leaves an orphan
   column squeezed off the end of the board. */
.kanban{
  --col-rail:60px;
  display:flex;align-items:stretch;gap:16px;min-width:0;
  contain:layout paint
}
.col{
  --stage:var(--status-neutral);--stage-bg:var(--status-neutral-bg);
  flex:1 1 0;flex-grow:var(--col-weight,1);min-width:0;min-height:200px;overflow:hidden;
  background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--radius-lg);
  display:flex;flex-direction:column;
  transition:flex-grow var(--motion-slow) var(--ease-out),
    flex-basis var(--motion-slow) var(--ease-out),
    border-color var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard)
}
.col-danger{--stage:var(--status-danger);--stage-bg:var(--status-danger-bg)}
.col-warning{--stage:var(--status-warning);--stage-bg:var(--status-warning-bg)}
.col-success{--stage:var(--status-success);--stage-bg:var(--status-success-bg)}
.col-info{--stage:var(--status-info);--stage-bg:var(--status-info-bg)}
.col-neutral{--stage:var(--status-neutral);--stage-bg:var(--status-neutral-bg)}
.col.is-folded{flex-grow:0;flex-shrink:0;flex-basis:var(--col-rail)}
.col-head{
  width:100%;min-height:64px;padding:14px 16px;border-bottom:1px solid var(--line-2);
  display:grid;grid-template-columns:28px minmax(0,1fr) auto 14px;align-items:center;gap:var(--s2);
  font-weight:650;font-size:.95rem;line-height:1.2;
  cursor:pointer;user-select:none;border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  text-align:left;transition:background var(--motion-fast) var(--ease-standard)
}
.col-head:hover{background:var(--hover)}
.col-head:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}

/* ---------- a folded stage ----------
   Down to a rail: the icon, and the count under it. Nothing is hidden —
   you can still see four are on the road while you work the pass — and
   the width it gives up goes to the stages that have food in them. */
.col.is-folded .col-head{
  min-height:100%;display:flex;flex-direction:column;gap:7px;padding:var(--s3) 0;
  border-bottom:0;justify-content:flex-start
}
.col.is-folded .col-head .n{margin-left:0}
.col-content{
  min-width:0;display:flex;flex-direction:column;flex:1;opacity:1;visibility:visible;
  transition:opacity var(--motion-fast) var(--ease-standard) var(--motion-fast),
    visibility 0s linear 0s
}
.col.is-folded .col-content{
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity 80ms linear,visibility 0s linear 80ms
}
.col-label{min-width:0;white-space:normal;overflow-wrap:break-word;word-break:normal;hyphens:manual}
.col.is-folded .col-label{display:none}
/* The stage is identified by its icon, drawn in the sidebar's stroke
   weight and carrying the stage colour. The label is kept for screen
   readers and as the hover title — removed from the eye, not from the
   page. */
.col-icon{
  width:28px;height:28px;flex:0 0 28px;border-radius:var(--r-sm);
  display:grid;place-items:center;background:transparent;color:var(--stage)
}
.col-ic{width:16px;height:16px;flex-basis:16px;stroke-width:1.8}
.col-fold-icon{
  width:14px;height:14px;flex:0 0 14px;color:var(--muted);
  transform:rotate(180deg);transition:transform var(--motion-base) var(--ease-out)
}
.col.is-folded .col-fold-icon{transform:rotate(0)}
.col.is-folded .col-icon{background:transparent}
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
    clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
/* The count is the whole point of a collapsed stage: how many are
   sitting in here. Give it the weight of a notification rather than a
   footnote, and let an empty stage recede. */
.col-head .n{
  margin-left:auto;min-width:22px;text-align:center;
  background:var(--stage-bg);color:var(--stage);
  border-radius:var(--radius-pill);padding:4px 8px;font-size:.86rem;line-height:1
}
.col-head .n.is-zero{background:transparent;color:var(--muted)}
.col-body{padding:14px;display:flex;flex-direction:column;gap:12px;flex:1;min-width:0}
.col-head.limit-bump{animation:limit-bump 280ms var(--ease-out)}
@keyframes limit-bump{
  0%,100%{background:transparent}
  45%{background:var(--status-warning-bg);box-shadow:inset 3px 0 0 var(--status-warning)}
}

/* ============================================================
   A SAVE THAT DID NOT HAPPEN
   ------------------------------------------------------------
   Loud on purpose, and above everything else on the screen, because the
   alternative is somebody working for an hour on a version of the truth
   the server never accepted. It does not dismiss on a timer.
   ============================================================ */
/* `display:flex` beats the browser's own [hidden] rule, so without this
   the bar paints as an empty red strip on every load. */
.save-bar[hidden]{display:none}
.save-bar{
  display:flex;align-items:flex-start;gap:var(--s3);
  margin:0 0 var(--s3);padding:var(--s3) var(--s4);
  border:1px solid var(--red-edge);background:var(--red-lt);
  border-radius:var(--r);color:var(--ink)
}
.save-bar > .ic{width:18px;height:18px;flex:0 0 18px;margin-top:2px;color:var(--red)}
.save-bar-text{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.save-bar-text b{font-size:var(--t-body);color:var(--red)}
.save-bar-text span{font-size:var(--t-small);color:var(--ink-2)}
.save-bar-text small{font-size:var(--t-small);color:var(--muted)}
.save-bar .b{flex:0 0 auto;align-self:center;background:var(--panel-solid)}
/* A queued change is a delay, not a loss — amber, not red. */
.save-offline{border-color:var(--amber-edge);background:var(--amber-lt)}
.save-offline > .ic,.save-offline .save-bar-text b{color:var(--amber)}
@media(max-width:700px){
  .save-bar{flex-wrap:wrap}
  .save-bar .b{width:100%;align-self:stretch}
}
/* ============================================================
   ORDER TICKET
   ------------------------------------------------------------
   A ticket is read at a glance by somebody holding a pan. It carries
   five things and nothing else: who, when, what, what it is worth, and
   the one action that moves it along. Everything that used to compete
   with those — a permanent amber allergen block, a phone number set at
   the same weight as the customer's name, and three equally-sized
   buttons stacked at the foot — has been demoted or removed.
   ============================================================ */
.ticket{
  border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:var(--shadow);
  padding:16px;background:var(--panel);transition:border-color .14s,box-shadow .14s;
  container-type:inline-size;container-name:order-ticket
}
.ticket:hover{border-color:var(--line-3);box-shadow:var(--shadow-soft)}
/* Late is said by the clock turning red (.tk-time.warn) and by the whole
   card warming, not by a stripe. */
/* A blocked ticket. Loud on purpose and at the TOP of the card, because
   it is the only thing on it that matters until somebody deals with it —
   and because the alternative is a red count on a button that front of
   house has to think to press. */
.tk-blocked,.tk-action{border-color:var(--red-edge)}
.tk-block{
  display:flex;flex-direction:column;gap:var(--s2);
  /* No bottom margin: .tk-detail supplies the gap between card sections.
     Carrying one here as well doubled it, and the extra band of card
     background inside the tinted block read as an empty element. */
  margin:0 calc(var(--s3) * -1);
  padding:var(--s3);border-bottom:1px solid var(--red-edge);
  background:var(--red-lt);color:var(--red);line-height:1.45
}
.tk-block-head{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.tk-block-head .ic{width:15px;height:15px;flex-basis:15px}
.tk-block-head b{
  font-size:var(--t-micro);font-weight:800;
  white-space:nowrap
}
.tk-block-when{
  margin-left:auto;font-size:var(--t-micro);font-weight:700;opacity:.8;
  font-variant-numeric:tabular-nums
}
.tk-block-why{font-size:var(--t-small);margin:0;overflow-wrap:anywhere}
.tk-block-why b,.tk-block-why span{display:block}
.tk-block-why b{font-weight:700;color:var(--red)}
.tk-block-why span{margin-top:2px;color:var(--ink-2)}
/* Who raised it and how to reach them: the answer to the second
   question, on its own line, quieter than the first. */
.tk-block-meta{
  margin:0;font-size:var(--t-micro);opacity:.8;font-variant-numeric:tabular-nums;
  overflow-wrap:anywhere
}
.tk-block-meta:empty{display:none}
.tk-block-contact{
  margin:0;font-size:var(--t-micro);font-weight:650;color:var(--ink-2);
  font-variant-numeric:tabular-nums
}
/* One full-width button that does the thing, and says only that. */
.tk-block-do{width:100%;justify-content:center;margin-top:2px}
.tk-block-more{align-self:flex-start;border:0;background:transparent;color:var(--red);font-size:var(--t-micro);font-weight:700;padding:0;text-decoration:underline}
/* ---------- the accordion ----------
   Hidden with CSS rather than left out of the markup: the detail stays
   in the DOM so it is still findable by the browser's own search and by
   a screen reader that wants it, and so re-rendering the board every
   eight seconds cannot lose it. */
.ticket.is-shut .tk-detail{display:none}
.ticket.has-action.is-shut .tk-brief{display:none}
/* One gap, set once, down the open card. Every part used to carry its
   own margin-top, so no two gaps matched and none of them agreed with
   the padding around the outside. The parts stop needing to know about
   each other. */
.ticket.is-open .tk-detail{display:flex;flex-direction:column;gap:var(--s3);min-width:0}
/* The condensed summary and the full detail are mutually exclusive. */
.ticket.is-open .tk-brief{display:none}
.tk-brief{
  display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:baseline;gap:var(--s1) var(--s2);
  font-size:var(--t-small);color:var(--ink-2);min-width:0
}
.tk-brief b{color:var(--ink);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tk-brief-tot{margin-left:auto;font-weight:700;color:var(--ink);white-space:nowrap}
.tk-brief-flag{
  flex-basis:100%;font-weight:600;color:var(--red)
}
.tk-brief-stock{
  grid-column:1/-1;color:var(--amber);font-size:var(--t-micro);font-weight:700;
  line-height:1.35;white-space:normal
}
/* The chevron belongs to the header, which is now the control. */
.tk-chev{width:14px;height:14px;flex-basis:14px;transition:transform .15s;opacity:.55}
.ticket.is-open .tk-chev{transform:rotate(180deg)}
.tk-top:hover .tk-chev{opacity:1}
.tk-top:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:var(--r-sm)}
/* A small marker so a condensed card still admits it needs somebody. */
.tk-flag{display:inline-flex;align-items:center;color:var(--red)}
.tk-flag .ic{width:14px;height:14px;flex-basis:14px}
/* Two actions on one row is what made them cramped at 250px. Below that
   they stack. */
@media(max-width:1500px){
  .kanban .tk-acts-row{grid-auto-flow:row;grid-auto-columns:auto}
}

.tk-item-off{color:var(--red);text-decoration:line-through;text-decoration-color:rgba(184,69,58,.5)}
.ticket.late{border-color:var(--red-edge)}

/* The whole row is the control, so it gets the affordances of one:
   a pointer, a hover ground, and room for the chevron at the end. */
.tk-top{
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:var(--s2);
  margin:calc(var(--s1) * -1) calc(var(--s2) * -1) 0;
  padding:var(--s2);border-radius:var(--r-sm);cursor:pointer;user-select:none
}
.tk-top:hover{background:var(--hover)}
.ticket.is-open .tk-top{margin-bottom:var(--s2)}
.tk-ident{display:flex;align-items:center;align-content:center;gap:6px;flex-wrap:wrap;min-width:0}
.tk-schedule{display:flex;align-items:center;gap:6px;white-space:nowrap;min-height:22px}
.tk-ref{font-size:1.02rem;line-height:1;white-space:nowrap}
/* Same size as the clock it shares the row with. At --t-micro it read as
   a footnote next to a number set two steps larger. */
.tk-mode{
  font-size:var(--t-small);font-weight:560;
  padding:3px 7px;border-radius:var(--radius-sm);line-height:1;background:var(--sunken);color:var(--ink-2)
}
.m-col,.m-del,.m-table{background:var(--sunken);color:var(--ink-2)}
/* `font:inherit` here was the shorthand, which resets size, weight,
   family, style and line-height together — and it sits after .tk-mode
   at equal specificity, so it undid every one of them. A dine-in chip
   is a <button> and a collection chip is a <span>, so "TABLE T2" came
   out at the inherited 14px/400 beside "COLLECT" at 12.64px/700: the
   same component in two sizes depending on whether it happened to be
   clickable. The reset a button actually needs is already applied
   globally at the top of this file, at a specificity .tk-mode beats. */
.tk-mode-btn{border:0;cursor:pointer;white-space:nowrap}
.tk-mode-btn:hover{text-decoration:underline}
.tk-time{margin-left:auto;font-size:1.02rem;color:var(--ink);line-height:1}
.tk-time.warn{color:var(--red)}

/* The card responds to its own width, not the browser width. Five live
   stages can make a ticket narrow even on a large monitor; in that case
   the due time becomes a second deliberate row instead of being clipped
   off the right edge. */
@container order-ticket (max-width:255px){
  .ticket .tk-top{grid-template-columns:1fr}
  .ticket .tk-schedule{
    width:100%;justify-content:space-between;padding-top:var(--s2);
    border-top:1px solid var(--line)
  }
  .ticket .tk-time{margin-left:0}
  .ticket .tk-brief{grid-template-columns:minmax(0,1fr) auto}
  .ticket .tk-brief b{grid-column:1/-1;white-space:normal;overflow-wrap:anywhere}
  .ticket .tk-brief-tot{margin-left:0}
}

/* Name and phone are one block: the name is the identity, the number is
   only ever needed once and does not deserve equal weight. */
.tk-who{font-weight:600;font-size:var(--t-body);line-height:1.3}
.tk-who span{display:block;font-weight:400;font-size:var(--t-small);color:var(--muted)}

.tk-items{font-size:var(--t-small);color:var(--ink-2);line-height:1.45}
.tk-items li{list-style:none;display:flex;gap:var(--s2);padding:1px 0}
.tk-items li b{flex:0 0 16px;color:var(--ink);font-variant-numeric:tabular-nums}
.tk-items li span{min-width:0;overflow-wrap:anywhere}

.tk-addr{
  font-size:var(--t-small);color:var(--muted);
  display:flex;gap:6px;align-items:flex-start;line-height:1.35
}
.tk-addr .ic{width:14px;height:14px;flex-basis:14px;margin-top:1px}

/* Allergens: three states, one of them loud. See allergenLine(). */
.tk-alg{
  display:flex;gap:var(--s2);align-items:flex-start;
  background:var(--amber-lt);border-radius:var(--r-sm);padding:var(--s2);
  color:var(--amber);line-height:1.35
}
.tk-alg .ic{width:15px;height:15px;flex-basis:15px;margin-top:1px}
.tk-alg b{display:block;font-size:var(--t-micro)}
.tk-alg span{display:block;font-size:var(--t-small)}
.tk-alg.urgent{background:var(--red-lt);color:var(--red)}
/* Not an alert. A dish nobody has checked yet is a fact worth stating
   once, in the same voice as the rest of the card. */
.tk-alg-quiet{font-size:var(--t-micro);color:var(--muted)}

.tk-note{
  padding:6px var(--s2);border-radius:var(--r-sm);
  background:var(--line-2);color:var(--ink-2);font-size:var(--t-small);line-height:1.4
}

/* The money line. Wraps rather than overflowing — a long total plus a
   "Refunded" pill plus a driver's name will not fit one line in a
   column one-fifth of the board wide. */
.tk-foot{
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  border-top:1px solid var(--line);padding-top:var(--s3)
}
.tk-foot .tot{font-weight:700;font-size:var(--t-body)}
.tk-driver{
  font-size:var(--t-micro);font-weight:700;color:var(--green);
  background:var(--green-lt);padding:3px var(--s2);border-radius:var(--r-pill);line-height:1.4
}

/* One action carries the ticket forward and gets the full width. The
   rest are secondary and share a row — they used to be three identical
   full-width buttons, which made "Reject" look like as ordinary a thing
   to do as "Accept", and cost 114px of height on every card. */
.tk-acts{display:grid;gap:6px}
.tk-acts .b{width:100%;min-height:34px;font-size:var(--t-small)}
.tk-acts-row{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:6px}
.tk-acts .b-sm{min-height:30px}
.tk-reject{color:var(--muted)}
.tk-reject:hover{border-color:var(--red);color:var(--red)}
.foh-course-spine{
  min-height:128px;padding:10px;border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--sunken);
  display:grid;grid-template-rows:36px 44px;gap:10px;box-sizing:border-box
}
.foh-course-rail{height:36px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px;overflow:hidden}
.foh-course-rail::-webkit-scrollbar{display:none}
.foh-course-pill{
  height:36px;min-width:0;padding:0 5px;border-radius:var(--radius-pill)!important;
  display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;box-sizing:border-box;
  background:var(--panel-solid);border:1px solid var(--line);white-space:nowrap;font-size:var(--t-micro)
}
.foh-course-pill b{max-width:100%;font-size:.65rem;line-height:1;white-space:nowrap}
.foh-course-pill span{max-width:100%;color:var(--muted);font-size:.54rem;font-weight:800;line-height:1;white-space:nowrap}
.foh-course-pill.is-fired,.foh-course-pill.is-cooking{background:var(--amber-lt);border-color:var(--amber)}
.foh-course-pill.is-ready{background:var(--green-lt);border-color:var(--green)}
.foh-course-pill.is-served{background:var(--blue-lt);border-color:var(--blue)}
.foh-course-command{height:44px;display:flex;align-items:stretch;min-width:0}
.foh-course-action{width:100%;min-height:44px}
.foh-course-wait{
  width:100%;height:44px;padding:0 12px;border-radius:var(--radius-pill)!important;
  display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;
  background:var(--panel-solid);border:1px solid var(--line);white-space:normal;text-align:center;line-height:1.15;
  overflow-wrap:anywhere;color:var(--muted);font-size:var(--t-micro);font-weight:700
}
.foh-course-wait.is-served{background:var(--green-lt);color:var(--green);border-color:var(--green)}

.pill{font-size:.68rem;font-weight:700;padding:4px 8px;border-radius:var(--radius-pill);line-height:1;white-space:nowrap}
.p-paid{background:var(--green-lt);color:var(--green)}
.p-due{background:var(--amber-lt);color:var(--amber)}
.empty{color:var(--muted);font-size:.83rem;text-align:center;padding:26px 10px}
.col-foot{
  display:block;width:100%;padding:11px 14px;border-top:1px solid var(--line);
  font-size:.79rem;font-weight:600;color:var(--muted);text-align:left;transition:.14s;
  border-radius:0 0 var(--r) var(--r)
}
.col-foot:hover{background:var(--hover);color:var(--ink)}

/* ============================================================
   TABLES — sticky headers, calmer rules
   ============================================================ */
.tbl-scroll{overflow:auto;max-height:620px}
table{width:100%;border-collapse:separate;border-spacing:0}
th{
  text-align:left;font-size:.85rem;color:var(--muted);
  font-weight:550;padding:14px 20px;background:var(--panel-solid);border-bottom:1px solid var(--line-2);
  white-space:nowrap;position:sticky;top:0;z-index:2
}
td{padding:18px 20px;border-bottom:1px solid var(--line-2);vertical-align:middle}
th:first-child,td:first-child{padding-left:28px}
th:last-child,td:last-child{padding-right:28px}
tbody tr:last-child td{border-bottom:none}
tbody tr:hover{background:var(--hover)}
td.num{font-weight:700}
td.right{text-align:right}
.who{font-weight:600;line-height:1.3}
.small{font-size:.875rem;color:var(--muted);line-height:1.5}
.st{font-size:.7rem;font-weight:700;padding:4px 9px;border-radius:var(--radius-pill);white-space:nowrap;line-height:1;display:inline-block}
.st::first-letter{text-transform:uppercase}
.st-confirmed{background:var(--blue-lt);color:var(--blue)}
.st-seated{background:var(--green-lt);color:var(--green)}
.st-finished{background:var(--sunken);color:var(--muted)}
.st-cancelled,.st-no_show{background:var(--red-lt);color:var(--red)}
.note-flag{background:var(--red-lt);padding:6px 10px;border-radius:var(--r-sm);font-size:.78rem;margin-top:5px;color:var(--red);font-weight:560;line-height:1.4}
.note-guest{margin-top:4px;font-size:.8rem;color:var(--ink-2);line-height:1.4}
.note-guest::before{content:"Note: ";color:var(--muted)}
.tag-unalloc{background:var(--red-lt);color:var(--red);font-size:.7rem;font-weight:700;padding:4px 8px;border-radius:var(--radius-sm);line-height:1;display:inline-block}
.tag-table{background:var(--sunken);color:var(--ink);font-size:.78rem;font-weight:700;padding:4px 9px;border-radius:var(--radius-sm);line-height:1;display:inline-block}

/* ============================================================
   FLOOR PLAN
   ============================================================ */
.floor-toolbar{
  display:flex;align-items:center;gap:14px;background:var(--panel);
  
  border:1px solid var(--line);border-top-color:var(--edge);
  border-radius:var(--r);padding:12px 16px;margin-bottom:14px;box-shadow:var(--lift),var(--shadow-soft);flex-wrap:wrap
}
.floor-clock{display:flex;align-items:baseline;gap:8px;min-width:130px}
.floor-clock .t{font-size:1.6rem;font-weight:700;letter-spacing:-.02em;line-height:1}
.floor-clock .d{font-size:.79rem;color:var(--muted)}
.scrub{flex:1;min-width:220px;display:flex;align-items:center;gap:10px}
.scrub input[type=range]{
  flex:1;-webkit-appearance:none;appearance:none;height:6px;border-radius:var(--radius-pill);
  background:linear-gradient(90deg,var(--brand) var(--pct,0%),var(--line) var(--pct,0%));outline:none
}
.scrub input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;width:20px;height:20px;border-radius:50%;background:#fff;
  border:3px solid var(--brand);cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,.2)
}
.scrub input[type=range]::-moz-range-thumb{
  width:20px;height:20px;border-radius:50%;background:#fff;border:3px solid var(--brand);cursor:pointer
}
.occ-bar{display:flex;align-items:center;gap:9px;min-width:150px}
.occ-track{flex:1;height:7px;border-radius:var(--radius-pill);background:var(--line);overflow:hidden}
.occ-fill{height:100%;border-radius:var(--radius-pill);background:var(--green);transition:width .2s}
.occ-fill.mid{background:var(--amber)}
.occ-fill.high{background:var(--red)}

.floor-wrap{display:grid;grid-template-columns:1fr 292px;gap:16px;align-items:start}

/* ============================================================
   THE ROOM
   ------------------------------------------------------------
   .floor-view is the window; .floor is the room, and it is drawn at
   whatever scale the zoom is set to.

   The room used to be exactly the size of the window, which quietly
   assumed every restaurant has about a dozen tables in one rectangle.
   A larger or zoned room simply did not fit: tables are sized in pixels,
   so past a certain count they overlap and the plan stops being
   readable. Zooming out shrinks the furniture rather than the room, so
   more of it fits in the same window; zooming in makes a crowded corner
   workable. Positions stay in percentages, so nothing has to be
   re-saved and the drag arithmetic is untouched — the scaled room
   covers the window exactly, so a point 30% across one is 30% across
   the other.
   ============================================================ */
.floor-view{
  position:relative;height:540px;overflow:hidden;
  border:1px solid var(--line);border-top-color:var(--edge);border-radius:var(--r);
  background:var(--panel-solid);box-shadow:var(--lift),var(--shadow)
}
.floor{
  position:absolute;left:0;top:0;
  width:calc(100% / var(--zoom,1));height:calc(100% / var(--zoom,1));
  transform:scale(var(--zoom,1));transform-origin:0 0;
  background:
    radial-gradient(circle,rgba(22,24,27,.13) 1px,transparent 1.2px),
    var(--panel-solid);
  background-size:24px 24px
}
.floor-zoom{display:flex;align-items:center;gap:4px}
.floor-zoom .lvl{
  min-width:46px;text-align:center;font-size:var(--t-small);font-weight:700;
  color:var(--muted);font-variant-numeric:tabular-nums
}

.tbl{
  position:absolute;transform:translate(-50%,-50%);cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;
  border:1.5px solid var(--line-3);background:var(--panel-solid);
  transition:box-shadow .14s,border-color .14s,background .14s;padding:4px;overflow:hidden
}
.tbl.sq{border-radius:var(--radius-md)}
.tbl.rd{border-radius:50%}
.tbl.lg{border-radius:var(--radius-md)}
.tbl:hover{box-shadow:var(--shadow-lift);border-color:var(--ink-2);z-index:6}
.tbl .tid{font-weight:700;font-size:.98rem;line-height:1.05}
.tbl .tcap{font-size:.68rem;color:var(--muted);line-height:1.05;font-weight:500}
.tbl .tgst{font-size:.66rem;font-weight:700;line-height:1.15;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px}
.tbl .ttime{font-size:.62rem;line-height:1.05;opacity:.75;font-weight:600}

/* Free is the absence of anything: a plain table. Colour is spent only on
   a table somebody is coming to (booked) or sitting at (seated). */
.tbl.free{border-color:var(--line-3);background:var(--panel-solid)}
.tbl.free .tid{color:var(--ink)}
.tbl.booked{border-color:var(--blue-edge);background:var(--blue-lt)}
.tbl.booked .tid,.tbl.booked .tgst{color:var(--blue)}
.tbl.seated{border-color:var(--green);background:var(--green-lt)}
.tbl.seated .tid,.tbl.seated .tgst{color:var(--green)}
.tbl.sel{border-color:var(--ink);box-shadow:0 0 0 4px var(--sel-ring)}

/* Chairs drawn around the table edge */
.chairs{position:absolute;left:0;right:0;pointer-events:none}
.chairs.top{top:-7px}
.chairs.bot{bottom:-7px}
.chairs span{position:absolute;width:13px;height:5px;border-radius:var(--radius-sm);background:var(--line-3);transform:translateX(-50%)}
.tbl.free .chairs span{background:var(--line-3)}
.tbl.booked .chairs span{background:var(--blue-edge)}
.tbl.seated .chairs span{background:var(--green)}

/* Drag & drop states */
.tbl.drop-ok{border-color:var(--green);background:#dff5e9;box-shadow:0 0 0 5px rgba(31,138,82,.2);z-index:8}
.tbl.drop-warn{border-color:var(--amber);background:var(--amber-lt);box-shadow:0 0 0 5px rgba(196,125,6,.2);z-index:8}
.tbl.drop-bad{border-color:var(--red);background:var(--red-lt);box-shadow:0 0 0 5px rgba(204,59,48,.18);z-index:8}
.floor.dragging .tbl.free{border-style:dashed}
.tbl.ghost{opacity:.35}

.drop-hint{
  position:absolute;left:50%;bottom:12px;transform:translateX(-50%);background:var(--ink);color:#fff;
  padding:8px 16px;border-radius:var(--radius-pill);font-size:.8rem;font-weight:600;line-height:1;
  box-shadow:var(--shadow-lift);pointer-events:none;opacity:0;transition:opacity .15s;white-space:nowrap;z-index:20
}
.drop-hint.show{opacity:1}

.legend{display:flex;gap:15px;flex-wrap:wrap;font-size:.78rem;color:var(--muted);margin-top:11px;align-items:center}
.legend i{width:12px;height:12px;border-radius:var(--radius-sm);display:inline-block;margin-right:6px;vertical-align:-2px;border:1.5px solid}
.lg-free{background:var(--panel-solid);border-color:var(--line-3)}
.lg-booked{background:var(--blue-lt);border-color:var(--blue-edge)}
.lg-seated{background:var(--green-lt);border-color:var(--green)}

/* Unallocated rail — the drag source */
.rail{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);margin-bottom:14px;overflow:hidden}
.rail-head{padding:11px 14px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px;min-height:46px}
.rail-head h3{font-size:.86rem;font-weight:700;line-height:1.2}
.rail-head .n{background:var(--red);color:#fff;border-radius:var(--radius-pill);font-size:.7rem;font-weight:700;padding:3px 8px;line-height:1}
.rail-head.clear{background:var(--green-lt);border-bottom-color:#c6e7d4}
.rail-head.clear h3{color:var(--green)}
.rail-body{padding:10px;display:flex;flex-direction:column;gap:8px;max-height:210px;overflow-y:auto}

.chip-bk{
  display:flex;align-items:center;gap:9px;padding:9px 11px;border:1.5px solid var(--line);
  border-radius:var(--radius-md);background:#fff;cursor:grab;transition:.14s;user-select:none
}
.chip-bk:hover{border-color:var(--line-3);background:var(--hover)}
.chip-bk:active{cursor:grabbing}
.chip-bk.drag{opacity:.4;border-style:dashed}
.chip-bk.picked{border-color:var(--ink);background:var(--hover);box-shadow:0 0 0 3px var(--sel-ring)}
.chip-bk:focus-visible,.tbl:focus-visible{outline:3px solid var(--brand);outline-offset:2px}
.tbl .tgst{cursor:pointer}

/* Touch targets on the plan need to be finger-sized, and the browser
   must not hijack the gesture as a scroll while a table is being moved. */
@media (pointer:coarse){
  .tbl{min-width:64px;min-height:56px}
  .chip-bk{padding:12px}
  .floor.editing .tbl{touch-action:none}
}
.chip-bk .grip{color:var(--muted);font-size:.9rem;line-height:1;letter-spacing:-2px;flex:0 0 auto}
.chip-bk .bk-t{font-weight:800;font-size:.83rem;line-height:1;flex:0 0 42px}
.chip-bk .bk-n{flex:1;min-width:0;font-size:.83rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chip-bk .bk-p{background:var(--sunken);border-radius:var(--radius-sm);padding:3px 7px;font-size:.72rem;font-weight:700;line-height:1;color:var(--ink-2)}

/* Table detail card */
.detail-top{display:flex;align-items:center;gap:11px;margin-bottom:13px}
.detail-top .tid{font-size:1.35rem;font-weight:800;letter-spacing:-.02em;line-height:1}
.mini-head{font-size:.7rem;font-weight:700;color:var(--muted);margin-bottom:8px}
.slot-card{border-radius:var(--radius-md);padding:11px;margin-bottom:14px}
.slot-card.busy{background:var(--blue-lt)}
.slot-card.busy.seated{background:var(--green-lt)}
.slot-card.free{background:var(--green-lt);color:#1c6f44;font-size:.82rem}
.svc-row{display:flex;gap:9px;align-items:center;padding:8px 0;border-bottom:1px solid var(--line-2)}
.svc-row:last-child{border-bottom:none}
.svc-row .t{font-weight:700;width:44px;flex:0 0 44px;font-size:.83rem}
.svc-row .n{flex:1;min-width:0;font-size:.83rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ============================================================
   FORMS
   ============================================================ */
/* `hidden` means hidden. Any rule that sets display (.fld, .b, a flex
   row) otherwise beats the browser's own [hidden] rule, and the element
   shows anyway: "Ways to split" and "Gift card number" on every checkout,
   the New order button on the kitchen's screen. */
[hidden]{display:none!important}
.fld{margin-bottom:20px;min-width:0;display:flex;flex-direction:column;align-items:stretch}
/* A field CAPTION — the words above a control — and nothing else.
   Without the :not([class]) this rule read as "every label anywhere
   inside a field", which is every checkbox in the product: an allergen
   box, a dietary toggle, a menu section row. At (0,1,1) it outranked
   the component's own (0,1,0) class, so .alg-box{display:flex} lost to
   display:block and the box and its words fell back to inline layout on
   a shared baseline — the checkbox 5px above the middle of its own
   label, with no gap but the whitespace in the markup. The gap and the
   centring were both in the stylesheet and neither had ever applied.

   Every caption in this codebase is an unclassed <label>; every label
   that carries a class is a control with its own layout. So that is the
   line the selector draws, and it stays true as long as that holds. */
.fld label:not([class]){display:block;font-size:.9rem;font-weight:600;margin-bottom:8px;color:var(--ink);line-height:1.4}
.in{
  width:100%;min-height:46px;padding:0 16px;border:1px solid var(--line-3);border-radius:var(--radius-md);
  background:var(--panel-solid);outline:none;font-size:.95rem;line-height:1.4;
  transition:border-color var(--motion-fast),box-shadow var(--motion-fast)
}
/* iOS zooms any input under 16px on focus — keep touch inputs at 16 */
@media(max-width:900px){ .in{font-size:16px;min-height:44px} }
textarea.in{padding:12px 16px;min-height:96px;resize:vertical;line-height:1.55}
select.in[multiple]{padding:6px;min-height:auto}
select.in:not([multiple]){
  appearance:none;padding-right:38px;background-color:var(--panel-solid);
  background-image:linear-gradient(45deg,transparent 50%,#74777d 50%),linear-gradient(135deg,#74777d 50%,transparent 50%);
  background-position:calc(100% - 17px) 50%,calc(100% - 12px) 50%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat
}
.in:hover{border-color:#b9bec5}
.in:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-ring)}
.booking-status{min-width:132px;width:auto;height:40px;min-height:40px;padding:0 9px;text-transform:capitalize;font-size:var(--t-small);font-weight:600}
.booking-status.st-confirmed{background:var(--blue-lt);border-color:var(--blue-edge);color:var(--blue)}
.booking-status.st-seated,.booking-status.st-finished{background:var(--green-lt);border-color:var(--green-edge);color:var(--green)}
.booking-status.st-no_show,.booking-status.st-cancelled{background:var(--red-lt);border-color:var(--red-edge);color:var(--red)}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.g4{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.g2>.fld>label:not([class]),.g3>.fld>label:not([class]),.g4>.fld>label:not([class]){min-height:22px;display:flex;align-items:flex-end}

.switch{display:flex;align-items:center;gap:12px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--panel);margin-bottom:10px}
.switch .tx{flex:1}
.switch .tx b{display:block;font-size:.88rem;line-height:1.35}
.switch .tx span{font-size:.78rem;color:var(--muted);line-height:1.4}
.tog{width:46px;height:26px;border-radius:var(--radius-pill);background:var(--line-3);position:relative;transition:.18s;flex:0 0 46px;cursor:pointer}
.tog::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:.18s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.tog.on{background:var(--green)}
.tog.on::after{transform:translateX(20px)}

/* Menu manager: fixed width stops the column jittering as labels change */
.avail-btn{min-width:118px}
.dish-media-choice{
  display:flex;align-items:center;gap:var(--s3);min-height:76px;padding:var(--s2);
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--line-2)
}
.dish-media-choice>img{width:60px;height:60px;object-fit:cover;border-radius:var(--radius-sm);border:1px solid var(--line)}
.dish-media-choice>div{flex:1;min-width:0}
.dish-media-choice b,.dish-media-choice span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dish-media-picker{
  grid-template-columns:repeat(auto-fill,minmax(76px,1fr));gap:7px;max-height:250px;overflow:auto;
  margin-top:var(--s2);padding:var(--s2);border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel)
}
.dish-media-picker button{aspect-ratio:1;border:1px solid transparent;border-radius:var(--radius-sm);overflow:hidden;background:var(--line-2)}
.dish-media-picker button:hover{border-color:var(--line-3)}
.dish-media-picker img{width:100%;height:100%;object-fit:cover;display:block}
.customer-link{font-weight:700;color:var(--brand-text);text-align:left}
.customer-link:hover{text-decoration:underline}
.customer-summary{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2);margin:var(--s2) 0 var(--s4)}
.customer-summary .stat{padding:var(--s3);box-shadow:none;margin:0}
.customer-summary .stat .num{font-size:1.25rem}
.customer-history{border-top:1px solid var(--line);padding-top:var(--s3)}
.customer-history h4{margin-bottom:var(--s2);font-size:var(--t-small);color:var(--muted)}
.customer-history>div{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s3);padding:9px 0;border-bottom:1px solid var(--line-2)}
.customer-history>div>span:last-child{text-align:right}
.customer-history b,.customer-history small{display:block}
.customer-history small{color:var(--muted);font-size:var(--t-small)}
.price-in{width:96px;min-height:34px;text-align:right;padding:0 10px}
.dish-thumb{width:44px;height:44px;border-radius:var(--r-sm);object-fit:cover;background:var(--sunken);display:block;flex:0 0 44px}
.dish-cell{display:flex;gap:11px;align-items:center}
.flags{display:flex;gap:4px;flex-wrap:wrap;margin-top:4px}
.flag{font-size:.63rem;font-weight:800;padding:2px 6px;border-radius:var(--radius-sm);line-height:1.3}
.f-v{background:var(--green-lt);color:var(--green)}
.f-gf{background:var(--sunken);color:var(--ink-2)}
.f-pop{background:var(--sunken);color:var(--ink-2)}
.f-s{background:var(--red-lt);color:var(--red)}
.f-alg{background:var(--amber-lt);color:var(--amber)}
.f-alg-none{background:var(--red-lt);color:var(--red)}

.day-pick{display:grid;grid-template-columns:repeat(7,1fr);gap:5px}
.day-pick .alg-box{padding:9px 4px;flex-direction:column;gap:5px;text-align:center;font-size:.76rem}
.alg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:6px}
.alg-box{
  display:flex;align-items:center;gap:9px;padding:9px 11px;border:1px solid var(--line);
  border-radius:var(--r-sm);cursor:pointer;font-size:.83rem;line-height:1.3;background:var(--panel)
}
.alg-box:hover{border-color:var(--line-3);background:var(--hover)}
.alg-box input{width:18px;height:18px;flex:0 0 18px;accent-color:var(--brand);cursor:pointer}

/* Kitchen ticket allergen strip — has to be impossible to skim past */
.sec-card{background:var(--panel);border:1px solid var(--line);border-top-color:var(--edge);border-radius:var(--r);box-shadow:var(--lift),var(--shadow-soft);margin-bottom:14px;overflow:hidden}
.sec-card.hidden-cat{opacity:.62}
.sec-head-row{padding:12px 16px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;background:transparent}
.sec-head-row .ic{font-size:1.15rem;line-height:1}
.sec-head-row h3{font-size:.97rem;font-weight:700}
.sec-head-row .cnt{font-size:.78rem;color:var(--muted)}

/* ============================================================
   INSIGHTS
   ============================================================ */
.seg{display:inline-flex;background:var(--sunken);border:1px solid var(--line);border-radius:var(--radius-md);padding:4px;gap:2px}
.seg button{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:32px;padding:0 14px;border-radius:var(--radius-sm);
  font-size:.83rem;font-weight:600;line-height:1;color:var(--muted);transition:.14s;white-space:nowrap
}
.seg button:hover{color:var(--ink)}
.seg button.on{background:var(--panel-solid);color:var(--ink);box-shadow:0 1px 2px rgba(16,18,22,.08),0 0 0 1px var(--line)}

.bars{display:flex;flex-direction:column;gap:7px}
.bar-row{display:flex;align-items:center;gap:12px;min-width:0}
.bar-lbl{
  flex:0 0 96px;font-size:.79rem;color:var(--ink-2);font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}
.bar-track{flex:1;height:22px;background:var(--sunken);border-radius:var(--r-sm);overflow:hidden;min-width:40px}
.bar-fill{
  display:block;height:100%;border-radius:var(--r-sm);
  background:var(--chart);transition:width .3s ease;min-width:2px
}
.bar-fill.hi{background:var(--brand)}
.bar-val{flex:0 0 auto;min-width:64px;text-align:right;font-size:.8rem;font-weight:700;font-variant-numeric:tabular-nums}

@media(max-width:600px){
  .bar-lbl{flex:0 0 72px;font-size:.74rem}
  .bar-val{min-width:54px;font-size:.74rem}
  .seg{width:100%}
  .seg button{flex:1;padding:0 6px}
}

/* Messaging */
.msg-body{font-size:.83rem;line-height:1.5;color:var(--ink-2);max-width:520px}
.msg-body .lnk{color:var(--blue);word-break:break-all}
.conn{display:flex;align-items:center;gap:14px;padding:18px;flex-wrap:wrap}
.conn .gmark{width:46px;height:46px;border-radius:var(--r);background:rgba(255,255,255,.7);border:1px solid var(--line);display:grid;place-items:center;font-size:1.35rem;font-weight:800;flex:0 0 46px}
.conn .tx{flex:1;min-width:200px}
.conn .tx b{display:block;font-size:.95rem}
.conn .tx span{font-size:.82rem;color:var(--muted)}
.conn.on{background:var(--green-lt)}
.conn.off{background:var(--amber-lt)}
.dot-live{width:8px;height:8px;border-radius:50%;background:var(--green);display:inline-block;margin-right:6px}
.dot-off{width:8px;height:8px;border-radius:50%;background:var(--amber);display:inline-block;margin-right:6px}
.tpl{margin-bottom:16px}
.tpl label{display:block;font-size:.8rem;font-weight:700;margin-bottom:6px}
.tpl .hint{font-size:.78rem;color:var(--muted);margin-bottom:7px}
.preview{background:var(--sunken);border:1px solid var(--line);border-radius:var(--r-md);padding:11px 13px;font-size:.82rem;line-height:1.5;margin-top:8px;color:var(--ink-2)}
.st-sent{background:var(--green-lt);color:var(--green)}
.st-queued{background:var(--blue-lt);color:var(--blue)}
.st-held{background:var(--amber-lt);color:var(--amber)}

/* Staff without manager rights never see these controls at all */
.meter{height:10px;border-radius:var(--radius-pill);background:var(--sunken);overflow:hidden;margin:10px 0}
.meter span{display:block;height:100%;border-radius:var(--radius-pill);background:var(--green);transition:width .3s}
.meter span.mid{background:var(--amber)}
.meter span.high{background:var(--red)}

/* Print — only the run sheet, nothing else */
@media print{
  .side,.topbar,.panel-head .b,.b,.toast,.mdl,.edit-banner,.floor-toolbar{display:none!important}
  .shell{display:block}
  .main{padding:0;max-width:none}
  .view{display:none!important}
  .view.on{display:block!important}
  .kanban{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  .col,.ticket,.panel{break-inside:avoid;box-shadow:none;border-color:#999}
  body{background:#fff;font-size:11px}
  .ticket{border:1px solid #666;margin-bottom:6px}
}

/* Layout edit mode */
.edit-banner{
  display:none;align-items:center;gap:12px;background:var(--sunken);border:1px solid var(--line);
  border-radius:var(--r);padding:12px 16px;margin-bottom:14px;font-size:.86rem
}
.edit-banner.on{display:flex}
.floor.editing{cursor:crosshair}
.floor.editing .tbl{cursor:grab}
.floor.editing .tbl:active{cursor:grabbing}
.floor.editing .tbl{border-style:dashed;border-color:var(--ink-2)}
.floor-object{
  position:absolute;transform:translate(-50%,-50%);display:grid;place-items:center;z-index:1;
  min-width:10px;min-height:8px;color:var(--muted);font-size:.64rem;font-weight:700;
  overflow:hidden;text-align:center;pointer-events:none
}
/* Every structure is a solid soft block. They used to be a mix — a
   near-black slab for a wall, a dashed outline for the kitchen, and a
   label with no fill at all, through which the grid and whatever was
   behind it showed. A plan you can see through is not a plan. */
.floor-object.wall{background:var(--line-3);color:var(--ink-2);border-radius:var(--radius-sm)}
.floor-object.kitchen{background:var(--sunken);color:var(--muted);box-shadow:inset 0 0 0 1px var(--line);border-radius:var(--r-sm)}
.floor-object.road{background:var(--sunken);color:var(--muted);border-radius:var(--r-sm)}
.floor-object.door{background:var(--amber-lt);color:var(--amber);border-radius:var(--r-sm)}
.floor-object.label{background:#e7e9ed;color:#5c626a;border-radius:var(--r-sm)}
.floor-object.editable{pointer-events:auto;cursor:grab;outline:1px dashed var(--faint);outline-offset:2px;z-index:3}
.floor-object.editable:active{cursor:grabbing}
.torders{position:absolute;left:50%;bottom:-18px;transform:translateX(-50%);max-width:130px;padding:2px 5px;border-radius:var(--radius-sm);background:var(--ink);color:#fff;font-size:9px;font-weight:750;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;z-index:4}
/* The delete badge lived here: a red disc hung outside the table's own
   box, which the room clips, so on any table near an edge it was a
   sliver of red with no target. Deleting a table is done from the panel
   you get by clicking it in layout mode, which is where the rest of its
   settings already are. */

/* ============================================================
   MODAL
   ============================================================ */
.mdl{position:fixed;inset:0;z-index:100;display:none;align-items:center;justify-content:center;padding:20px}
.mdl.open{display:flex}
.mdl-bg{position:absolute;inset:0;background:rgba(17,20,24,.36)}
.mdl-card{position:relative;background:var(--panel-solid);border:1px solid var(--line);border-radius:var(--radius-lg);width:100%;max-width:580px;max-height:92vh;overflow-y:auto;box-shadow:var(--shadow-lift)}
.mdl-head{padding:24px 28px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;background:var(--panel-solid);z-index:3}
.mdl-head h3{font-size:1.25rem;font-weight:700;line-height:1.3;letter-spacing:-.02em}
.mdl-body{padding:28px}
.x{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;font-size:1.3rem;line-height:1;color:var(--muted);border-radius:var(--radius-sm)}
.x:hover{background:var(--hover);color:var(--ink)}
.warn-box{background:var(--amber-lt);border:1px solid var(--amber-edge);border-radius:var(--r-md);padding:12px;margin-bottom:13px}
.warn-box h4{font-size:.78rem;color:var(--amber);margin-bottom:6px}

/* Hidden with opacity + visibility rather than a percentage slide — a
   percentage offset is relative to the element's own height, so a short
   toast never actually leaves the screen. Same fault as the customer site. */
.toast{
  position:fixed;bottom:20px;right:20px;background:var(--ink);
  color:#fff;padding:16px 22px;border-radius:var(--radius-md);font-size:.92rem;font-weight:550;z-index:200;max-width:360px;line-height:1.45;
  transform:translateY(12px);box-shadow:var(--shadow-float);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .2s ease,transform .28s cubic-bezier(.2,.9,.3,1.2),visibility .2s
}
/* Clickable while showing: the Undo button lives in here. */
.toast.show{transform:translateY(0);opacity:1;visibility:visible;pointer-events:auto}
.toast.bad{background:var(--red)}
.toast.good{background:var(--green)}

.view{display:none}
.view.on{display:block}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media(max-width:1180px){
  .floor-wrap{grid-template-columns:1fr}
  .floor-view{height:460px}
  .g4{grid-template-columns:repeat(2,1fr)}
}

@media(max-width:900px){
  .shell{grid-template-columns:1fr}
  .main{padding:0 16px 56px}
  .global-tools{height:60px;margin:0 -16px 24px;padding:0 10px 0 8px}
  .topbar h1{font-size:1.28rem}
  .stats{grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px}
  .stat{padding:13px 14px}
  .stat .num{font-size:1.5rem}
  .panel-head{padding:12px 14px}
  .panel-body{padding:14px}
  .kanban{display:grid;grid-template-columns:1fr}
  .col.is-folded{flex-basis:auto;min-height:52px;max-height:52px}
  .col.is-folded .col-head{
    min-height:52px;flex-direction:row;gap:var(--s2);padding:var(--s3);
    justify-content:flex-start;border-bottom:0
  }
  .col.is-folded .col-label{display:block}
  .col.is-folded .col-icon{background:var(--stage-bg)}
  .col.is-folded .col-head .n{margin-left:auto}
  .kds{grid-template-columns:1fr}
  .g2,.g3,.g4{grid-template-columns:1fr}
  .floor-view{height:380px}
  .floor-toolbar{gap:12px;padding:12px 14px}
  .floor-clock{min-width:auto}
  .scrub{flex:1 1 100%;order:3}
  .occ-bar{flex:1 1 100%;order:4}
  .mdl{padding:0;align-items:flex-end}
  .mdl-card{max-width:none;border-radius:var(--radius-sm) var(--radius-sm) 0 0;max-height:94vh}
  .toast{left:14px;right:14px;bottom:14px;max-width:none}
}

@media(max-width:600px){
  .global-tools{margin-bottom:var(--s3)}
  .workspace-context span{display:none}
  .tool-clock,.tool-link{display:none}
  .workspace-context b{padding-left:0;border-left:0}
  .settings-tabs{margin-left:-4px;margin-right:-4px}
  .task-popover{position:fixed;left:8px;right:8px;top:104px;width:auto;max-height:calc(100vh - 116px)}
  /* Toolbar buttons pair up rather than stacking.

     They used to be flex:1 1 100% each, so Today's three actions became
     three full-width buttons and 165px of chrome between the date and
     the first real number on the screen. Two to a row keeps the phone
     readable, and because the primary action is last in the source it
     lands on its own row at full width — which is the hierarchy you
     want anyway. Inputs stay full width; a date or a search box that
     shares a row with a button is unusable on a phone. */
  .topbar{gap:var(--s2)}
  .topbar > .b{flex:1 1 calc(50% - var(--s2))}
  .topbar > .in{flex:1 1 100%}
  .topbar > .seg{width:100%}
  .seg{overflow-x:auto;justify-content:flex-start}
  .seg button{flex:1 0 auto;min-width:84px}
  .topbar .spacer{display:none}
  .panel-head{flex-wrap:wrap}
  .panel-head .b{flex:1 1 auto}
  /* Wide tables scroll rather than squashing their columns */
  .tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .tbl-scroll table{min-width:560px}
  .acts{justify-content:flex-start}
  .sec-head-row{flex-wrap:wrap}
  .sec-head-row .acts{width:100%;justify-content:flex-start;flex-wrap:wrap}
  .conn{flex-direction:column;align-items:flex-start}
  .conn .acts{width:100%;flex-wrap:wrap}
  .edit-banner{flex-wrap:wrap}
  .edit-banner .b{flex:1 1 auto}
  .avail-btn{min-width:0;width:100%}
  .price-in{width:100%}
  .media-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .media-facts{grid-template-columns:1fr 1fr}
  .media-detail{block-size:240px}
  .media-variant-head{align-items:flex-start;flex-direction:column}
  .media-variant-actions{display:grid;grid-template-columns:1fr 1fr;width:100%}
  .media-variant-head .media-variant-actions .b{width:100%;min-width:0}
  .media-copy{inline-size:auto}
  .media-variants{grid-template-columns:1fr;max-height:210px}
  .test-set{align-items:stretch;flex-direction:column}
  .test-set .b{width:100%}
  .task-card{align-items:flex-start;flex-direction:column}
  .task-card .b{width:100%}
  .al-chip{width:100%;justify-content:flex-start}
  .al-stages{width:100%}
  .al-stage{flex:1 1 0;min-width:0}
}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ============================================================
   PROVIDER CATALOGUE, MAILING LIST AND APPEARANCE
   ============================================================ */

/* --- choosing a sending service --- */
.prov-list{display:flex;flex-direction:column;gap:10px;margin-bottom:4px}
.prov{
  display:block;width:100%;text-align:left;padding:16px 18px;border-radius:var(--radius-md);
  border:1.5px solid var(--line);background:var(--panel);cursor:pointer;transition:.15s
}
.prov:hover{border-color:var(--line-3);background:var(--hover)}
.prov.on{border-color:var(--ink);box-shadow:0 0 0 3px var(--sel-ring)}
.prov-head{display:flex;align-items:center;gap:10px;margin-bottom:6px;flex-wrap:wrap}
.prov-head b{font-size:1rem;line-height:1.3}
.prov .tag{
  font-size:.7rem;font-weight:700;
  background:var(--sunken);color:var(--ink-2);padding:3px 9px;border-radius:var(--radius-pill);line-height:1.4
}
.prov-foot{
  display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
  margin-top:10px;padding-top:10px;border-top:1px solid var(--line)
}

/* --- which channel carries which message --- */
.route-grid{display:flex;flex-direction:column;gap:10px}
.route-row{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--panel)
}
.route-row .tx{display:flex;flex-direction:column;gap:2px;flex:1;min-width:180px}
.route-row select{margin-left:auto}

/* --- style presets --- */
.preset-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.preset{
  display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  cursor:pointer;transition:.15s;text-align:center
}
.preset:hover{border-color:var(--line-3);background:var(--hover)}
.preset.on{border-color:var(--ink);background:var(--hover);box-shadow:0 0 0 3px var(--sel-ring)}
.preset .pe{font-size:1.6rem;line-height:1}
.preset .pl{font-size:.85rem;font-weight:600;line-height:1.3}
.preset .sw{display:flex;gap:4px}
.preset .sw i{width:16px;height:16px;border-radius:var(--radius-sm);display:block}

/* --- colour pickers --- */
.colour-row{display:flex;align-items:center;gap:10px}
/* Named .swatch, not .col — `.col` was already the kanban column on the
   orders board, and because this block sits later in the file it won
   the cascade and squashed every column to 52x40px. Renamed rather than
   made more specific: two unrelated things should not share a name. */
.swatch{
  width:52px;height:40px;padding:2px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--panel);cursor:pointer;flex:0 0 52px
}
.rng{width:100%;max-width:340px;accent-color:var(--brand);height:32px}

.theme-preview{
  margin-top:18px;padding:18px;border-radius:var(--radius-md);
  background:var(--p-paper);border:1px solid var(--line)
}
.tp-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:10px}
.tp-btn{
  display:inline-flex;align-items:center;min-height:42px;padding:0 22px;border-radius:var(--radius-pill);
  background:var(--p-accent);color:#fff;font-weight:600;font-size:.9rem;line-height:1
}
.tp-txt{color:var(--p-ink);font-size:.9rem}

/* --- image URLs with a thumbnail --- */
.img-row{display:flex;align-items:center;gap:12px}
.img-prev{
  width:64px;height:44px;flex:0 0 64px;border-radius:var(--radius-sm);overflow:hidden;
  border:1px solid var(--line);background:var(--sunken);
  display:grid;place-items:center;font-size:.8rem;color:var(--muted)
}
.img-prev img{width:100%;height:100%;object-fit:contain}
.img-row .in{flex:1;min-width:0}

/* --- section on/off --- */
.sect-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
.sect{
  display:flex;align-items:flex-start;gap:11px;padding:14px 15px;cursor:pointer;
  border:1.5px solid var(--line);border-radius:var(--radius-md);background:var(--panel);transition:.15s
}
.sect:hover{border-color:var(--line-3);background:var(--hover)}
.sect.on{border-color:var(--ink);background:var(--hover)}
.sect input{width:18px;height:18px;flex:0 0 18px;margin-top:2px;cursor:pointer;accent-color:var(--brand)}
.sect .tx{display:flex;flex-direction:column;gap:3px;min-width:0}

/* --- wording, grouped by where it appears --- */
.copy-group{margin-bottom:26px}
.copy-group:last-child{margin-bottom:0}
.copy-group h3{
  font-size:.74rem;color:var(--muted);
  margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--line)
}
.copy-group textarea.in{resize:vertical;min-height:64px;line-height:1.5;padding-top:10px;padding-bottom:10px}
.tag-soft{
  font-size:.66rem;font-weight:600;
  color:var(--muted);background:var(--sunken);padding:2px 7px;border-radius:var(--radius-pill);margin-left:6px
}

/* Consent tick in the dashboard filter bar */
.chk{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-size:.85rem}
.chk input{width:16px;height:16px;cursor:pointer;accent-color:var(--brand)}

@media(max-width:720px){
  .route-row select{margin-left:0;width:100%}
  .preset-grid{grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}
}

/* Link out to the supplier's own live pricing page. We deliberately quote
   no rates ourselves — see the note above PROVIDERS in store.js. */
.prov-price{
  display:inline-block;margin-top:10px;font-size:.79rem;font-weight:600;
  color:var(--brand-text);text-decoration:underline;text-underline-offset:3px
}
.prov-price:hover{color:var(--brand-dk)}

/* ============================================================
   ALERTS BAR
   ------------------------------------------------------------
   One row, above the page heading, and empty far more often than not.
   It replaced two stacked bars that between them occupied 145px at the
   top of every screen in the product and repeated numbers already
   visible below them.

   Nothing here is decorative. A chip appears because somebody has to
   act, and it is a button because the only useful response to "2 orders
   need a call" is to be taken to them.
   ============================================================ */
.alerts{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s4)}

.al-chips{display:flex;gap:var(--s2);flex-wrap:wrap;min-width:0}
/* Role: a control. Same geometry from .pill; only colour and the fact
   that it responds to a press are its own. */
.al-chip{transition:filter .14s;cursor:pointer}
.al-chip:hover{filter:brightness(.96)}
.al-bad{background:var(--red-lt);color:var(--red);border-color:#f6d5d2}
.al-warn{background:var(--amber-lt);color:var(--amber);border-color:#f0dcb8}

/* The four stage counts, for the roles whose screen shows them nowhere
   else. The manager never sees this — see renderAlerts(). */
.al-stages{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}

/* ============================================================
   THE SERVICE BAR PILL — one component, every item in that row
   ------------------------------------------------------------
   The stage counts and the alert chips used to be two rules that
   happened to look similar, and the bar read as two products bolted
   together: 6px counts beside 999px chips, different heights, one
   aligned to the baseline and the other to the centre.

   Matching two rules by hand is how they drift apart again. So there is
   ONE rule that owns the geometry — shape, height, padding, alignment —
   and the two roles differ only in colour. Anything added to this bar
   later inherits the geometry by using the class, not by remembering a
   number.

   Every value here is deliberate:
     height        fixed, not min-height. min-height lets a taller child
                   push one pill out of line with its neighbours, which
                   is exactly how the row lost its rhythm before.
     align-items   center, NOT baseline. A 1rem number beside a 0.7rem
                   uppercase label has no shared baseline worth aligning
                   to, and baseline alignment was what tipped the counts
                   off the chips' optical centre.
     line-height   1, so the text box is the glyph box and the flex
                   centring is the only thing positioning it. */
.bar-pill{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  height:36px;padding:0 var(--s4);border-radius:var(--radius-pill);
  border:1px solid transparent;line-height:1;white-space:nowrap;
  font-size:var(--t-small);font-weight:600;font-family:inherit
}

/* Role: a read-out. It is a <div> with no handler, so it gets no hover
   lift and no pressed state — dressing a number as something pressable
   is a worse fault than dressing it as a rectangle. Colour and weight
   separate it from the chip beside it; geometry never does. */
.al-stage{background:var(--line-2);color:var(--muted);gap:6px}
.al-stage b{font-size:var(--t-lead);font-weight:700;color:var(--muted)}
.al-stage span{font-size:var(--t-micro);font-weight:700}
/* A stage with nothing in it is a fact, not a highlight. Only the ones
   holding food get full contrast, so the eye lands on the work. */
.al-stage.has{background:var(--panel-solid);border-color:var(--line);color:var(--ink-2);
  box-shadow:var(--lift),var(--shadow)}
.al-stage.has b{color:var(--ink)}

/* A single-screen role has no use for a sidebar. */
body.single-view .side{display:none}
body.single-view #sideToggle{display:none}
body.single-view .shell{grid-template-columns:1fr}
body.single-view .main{padding:14px 16px 40px;max-width:none}

/* ============================================================
   KITCHEN DISPLAY
   Read at two metres with your hands full. Big type, one action,
   no prices and no customer contact details.
   ============================================================ */
/* ============================================================
   KITCHEN DISPLAY
   ------------------------------------------------------------
   Read from two metres by somebody holding a pan, and it still has to
   look like the rest of the product — a chef and a manager are looking
   at one system, not two.

   Two columns, fixed. It used to be auto-fill from a 300px minimum,
   which on a wide screen gave four narrow cards and wrapped every line
   that mattered: "44m overdue" broke away from its ticket reference,
   and a dish called "Hyderabadi Lamb Biryani" ran onto three lines. Two
   columns are wide enough that nothing wraps, and big enough to read
   from across a kitchen. Three only above 1700px, where they are still
   wide enough to hold a dish name.

   State is a tinted head and a coloured clock, not a red slab: at a
   glance you see WHICH ticket is late and by how much, rather than a
   wall of red in which nothing is more urgent than anything else.
   ============================================================ */
.kds{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s4);align-items:start}
.kds-empty{
  grid-column:1/-1;text-align:center;padding:60px 20px;color:var(--muted);
  font-size:1.1rem;background:var(--panel);border:1px solid var(--line);border-radius:var(--r)
}
.kds-empty b,.kds-empty span{display:block;letter-spacing:0}
.kds-empty b{margin-bottom:8px;color:var(--ink)}
.kds-ticket{
  background:var(--panel);
  border:1px solid var(--line);border-top-color:var(--edge);border-radius:var(--radius-lg);
  overflow:hidden;display:flex;flex-direction:column
}

.kds-head{
  display:flex;align-items:center;gap:var(--s3);flex-wrap:nowrap;min-width:0;
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line-2);background:var(--panel)
}
.kds-ref{font-size:1.4rem;white-space:nowrap}
.kds-mode{
  display:inline-flex;align-items:center;gap:5px;min-width:0;
  font-size:var(--t-small);font-weight:700;
  padding:4px 9px;border-radius:var(--r-pill);background:var(--panel-solid);color:var(--ink-2);
  line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis
}
.kds-mode .ic{width:14px;height:14px;flex-basis:14px}
.kds-mode.delivery{background:var(--blue-lt);color:var(--blue)}
/* The clock never wraps and never gives up its space — it is the one
   number the pass is actually reading. */
.kds-clock{
  margin-left:auto;flex:0 0 auto;text-align:right;line-height:1;white-space:nowrap;
  font-variant-numeric:tabular-nums
}
.kds-clock b{display:block;font-size:.86rem;font-weight:800;letter-spacing:0;line-height:1.05;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.kds-clock small{display:block;margin-top:2px;color:var(--muted);font-size:.62rem;font-weight:600;line-height:1.05;max-width:100%;overflow:hidden;text-overflow:ellipsis}

.kds-ticket.soon .kds-clock b{color:var(--amber)}

.kds-ticket.late .kds-clock b{color:var(--red)}
.kds-ticket.late{border-color:var(--red-edge)}
.kds-ticket.needs-ack{border:2px solid var(--red);box-shadow:0 0 0 3px var(--red-lt)}
.kds-ticket.soon .kds-clock small,.kds-ticket.late .kds-clock small{color:currentColor;opacity:.8}

.kds-body{padding:var(--s4);display:flex;flex-direction:column;gap:var(--s3);flex:1}
.kds-update{
  display:flex;flex-direction:column;gap:5px;padding:var(--s3);
  border-radius:var(--radius-md);background:var(--red-lt);color:var(--ink);line-height:1.4
}
.kds-update-label{font-size:var(--t-small);font-weight:600;color:var(--red)}
.kds-update b{font-size:1.12rem}
.kds-update p{font-size:var(--t-body)}
.kds-update small{font-size:var(--t-small);color:var(--muted);font-weight:600}

/* The one thing on this screen where being wrong hurts someone. */
.kds-alg{
  background:#33220f;color:#ffd9a8;border-radius:var(--r-sm);padding:10px 12px;line-height:1.4;
  display:flex;flex-direction:column;gap:2px
}
.kds-alg b{font-size:var(--t-micro);color:#ffb454}
.kds-alg span{font-size:.95rem;font-weight:600}
/* A customer who has told us they have an allergy outranks everything
   else on the ticket, including the dish list. */
.kds-alg.guest{background:#8f2f26;color:#fff}
.kds-alg.guest b{color:#ffd9d5}
/* Same rule as the order ticket: a dish nobody has assessed is not a
   warning, it is a fact. This was an amber bordered panel on every
   ticket on the pass, all shift, because no dish has a record — which
   makes the dark allergen block above it, the one that actually matters,
   just more coloured furniture. */
.kds-unchecked{font-size:var(--t-small);color:var(--muted)}

.kds-items{list-style:none;display:flex;flex-direction:column;gap:var(--s2)}
/* align-items:flex-start rather than baseline: a dish name long enough to
   wrap should wrap under itself, not drag its quantity chip down with it. */
.kds-items li{display:flex;gap:12px;align-items:flex-start;font-size:1.08rem;font-weight:600;line-height:1.3}
.kds-items .q{
  flex:0 0 28px;height:28px;border-radius:var(--r-sm);background:var(--ink);color:#fff;
  display:inline-grid;place-items:center;font-size:.85rem;font-weight:800
}
.kds-items .n{min-width:0;padding-top:3px}
.kds-sub,.tk-sub{display:block;margin-top:3px;font-size:var(--t-micro);font-weight:600;color:var(--muted)}
.tk-stock-note{display:block;margin-top:3px;color:var(--amber);font-size:var(--t-micro);font-weight:700;line-height:1.35}
.kds-note{font-size:.88rem;background:var(--sunken);border-radius:var(--r-sm);padding:8px 11px;line-height:1.45}
.kds-note.alert{background:var(--red-lt);color:var(--red);font-weight:600}
/* One action carries the ticket; "Chat" is not its equal and no longer
   gets the same 52px slab underneath it. */
.kds-acts{display:grid;gap:var(--s2);padding:0 var(--s4) var(--s4)}
.kds-acts .b{width:100%}
.kds-note-btn{min-height:38px;font-size:var(--t-body);color:var(--muted)}

/* ---- Phase 2: station and expo KDS ----
   Every changing label owns its dimensions. Status, timer and save text
   change via paint only; no adjacent control is allowed to move. */
.kds-topbar{gap:var(--s3);min-height:58px}
.kds-mode-switch{
  width:168px;height:36px;display:grid;grid-template-columns:1fr 1fr;padding:2px;
  border:1px solid var(--line);background:var(--sunken);border-radius:var(--radius-pill)!important;
  flex:0 0 168px
}
.kds-mode-switch button{
  height:30px;border:0;background:transparent;color:var(--muted);font:inherit;font-size:var(--t-small);
  font-weight:700;padding:0 12px;border-radius:var(--radius-pill)!important;cursor:pointer;white-space:nowrap
}
.kds-mode-switch button.active{background:var(--panel-solid);color:var(--ink);box-shadow:var(--shadow-soft)}
.kds-station-select{
  width:204px;height:36px;flex:0 0 204px;border:1px solid var(--line);background:var(--panel-solid);
  color:var(--ink);padding:0 34px 0 14px;border-radius:var(--radius-pill)!important;font:inherit;font-size:var(--t-small);
  font-weight:700
}
.kds-status-rail{
  min-height:52px;display:flex;align-items:center;gap:var(--s3);margin-bottom:0;overflow:hidden
}
.kds-routing-rail{
  height:52px;min-height:52px;display:flex;align-items:center;gap:8px;margin-bottom:var(--s4);
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;contain:layout paint
}
.kds-routing-rail::-webkit-scrollbar{display:none}
.kds-route-scope,.kds-route-empty,.kds-route-pill{
  height:36px;min-height:36px;padding:0 14px;display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--radius-pill)!important;box-sizing:border-box;white-space:nowrap;letter-spacing:0;
  font:inherit;font-size:var(--t-small);font-weight:600;line-height:1;flex:0 0 auto
}
.kds-route-scope{background:var(--ink);color:#fff;border:1px solid var(--ink)}
.kds-route-empty{background:var(--sunken);color:var(--muted);border:1px solid var(--line)}
.kds-route-pill{background:var(--panel-solid);color:var(--ink);border:1px solid var(--line);cursor:pointer}
.kds-route-pill.has-live-work{background:var(--amber-lt);color:var(--amber);border-color:var(--amber-edge)}
.kds-route-pill.has-ready-work:not(.has-live-work){background:var(--green-lt);color:var(--green);border-color:var(--green-edge)}
.kds-route-pill.is-current{box-shadow:inset 0 0 0 2px currentColor;cursor:default}
.kds-route-pill:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.kds-all-day{
  height:36px;min-width:0;flex:1;display:flex;align-items:center;gap:8px;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;contain:layout paint
}
.kds-all-day::-webkit-scrollbar{display:none}
.kds-all-label,.kds-all-empty,.kds-all-pill,.kds-feedback,.kds-course-pill,.kds-state-pill,
.kds-line-state,.kds-line-action,.expo-station{
  height:36px;border-radius:var(--radius-pill)!important;display:inline-flex;align-items:center;justify-content:center;
  padding:0 14px;line-height:1;white-space:nowrap;box-sizing:border-box
}
.kds-all-label{background:transparent;color:var(--muted);font-size:var(--t-small);font-weight:560;flex:0 0 auto}
.kds-all-empty{background:var(--sunken);color:var(--muted);font-size:var(--t-small);flex:0 0 116px}
.kds-all-pill{gap:8px;background:var(--panel);color:var(--ink);border:1px solid var(--line);font-size:var(--t-small);font-weight:560;flex:0 0 auto;padding-left:6px}
.kds-all-pill b{min-width:24px;height:24px;padding:0 6px;display:inline-grid;place-items:center;background:var(--ink);color:#fff;border-radius:var(--radius-pill)!important;font-size:.9rem;font-weight:700}
.kds-feedback{
  width:156px;flex:0 0 156px;background:var(--sunken);border:1px solid transparent;color:var(--muted);
  font-size:var(--t-small);font-weight:700;font-variant-numeric:tabular-nums;transition:opacity .16s,transform .16s
}
.kds-feedback.is-saving{background:var(--blue-lt);color:var(--blue)}
.kds-feedback.is-saved{background:var(--green-lt);color:var(--green)}
.kds-feedback.is-error{background:var(--red-lt);color:var(--red);border-color:var(--red-edge)}
.kds-course-pill{background:var(--blue-lt);color:var(--blue);font-size:var(--t-small);font-weight:600;flex:0 0 auto}
.kds-state-pill{min-width:92px;background:var(--sunken);color:var(--muted);font-size:var(--t-small);font-weight:600}
.kds-state-pill.is-cooking,.kds-state-pill.is-fired{background:var(--amber-lt);color:var(--amber)}
.kds-state-pill.is-ready{background:var(--green-lt);color:var(--green)}
.kds-state-pill.is-served{background:var(--blue-lt);color:var(--blue)}
.kds-clock{
  width:196px;height:36px;padding:0 12px;border-radius:var(--radius-pill)!important;background:var(--panel-solid);
  display:flex;flex-direction:row;justify-content:flex-end;align-items:center;gap:8px;overflow:hidden
}
.kds-clock b,.kds-clock small{margin:0;min-width:0;white-space:nowrap}
.kds-timer-rail{
  min-height:52px;padding:8px var(--s4);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:8px;border-bottom:1px solid var(--line);background:var(--panel-solid);contain:layout paint
}
.kds-timer{
  height:36px;min-width:0;padding:0 10px;display:flex;align-items:center;justify-content:space-between;gap:6px;
  border:1px solid transparent;border-radius:var(--radius-pill)!important;box-sizing:border-box;
  font-variant-numeric:tabular-nums;line-height:1;white-space:nowrap;overflow:hidden
}
.kds-timer-cook,.kds-timer-pass{justify-content:space-between}
.kds-timer small{font-size:.74rem;font-weight:560;color:currentColor;opacity:.85}
.kds-timer b{font-size:1rem;overflow:hidden}
.kds-timer-placed{background:var(--sunken);color:var(--ink)}
/* Read from across a kitchen, so these three keep their AAA pairs
   (9:1 and up) rather than the softer status tints used elsewhere. */
.kds-timer.sla-green{background:#d1fae5;color:#064e3b;border-color:#a7f3d0}
.kds-timer.sla-amber{background:#fef3c7;color:#78350f;border-color:#fde68a}
.kds-timer.sla-red{background:#ffe4e6;color:#881337;border-color:#fecdd3}
.kds-ticket.sla-amber{border-color:var(--amber-edge)}
.kds-ticket.sla-red{border-color:var(--red-edge)}

.kds-items .kds-line{
  min-height:62px;display:grid;grid-template-columns:32px minmax(0,1fr) 92px 82px;align-items:center;
  gap:10px;padding:7px 0;border-bottom:1px solid var(--line)
}
.kds-items .kds-line:last-child{border-bottom:0}
.kds-line .n{padding-top:0;font-size:1rem;line-height:1.25}
.kds-line .n small{display:block;margin-top:3px;color:var(--muted);font-size:var(--t-micro);font-weight:600}
.kds-line-state{width:92px;background:var(--sunken);color:var(--muted);font-size:var(--t-small);font-weight:600}
.kds-line.is-cooking .kds-line-state{background:var(--amber-lt);color:var(--amber)}
.kds-line.is-ready .kds-line-state{background:var(--green-lt);color:var(--green)}
.kds-line-action{
  width:82px;border:1px solid var(--line);background:var(--ink);color:#fff;font:inherit;
  font-size:var(--t-small);font-weight:650;cursor:pointer
}
.kds-line-action:disabled{opacity:.6;cursor:wait}
.kds-line-action.is-static{background:var(--green-lt);color:var(--green);border-color:transparent;cursor:default}
.kds-line-action.is-undo{background:#fff;color:var(--ink);border-color:var(--ink)}
.kds-undo-ticket{border-color:var(--ink);color:var(--ink);background:#fff}
.kds-course-context{
  height:36px;padding:0 14px;border-radius:var(--radius-pill)!important;background:var(--blue-lt);color:var(--blue);
  display:flex;align-items:center;justify-content:space-between;gap:12px;box-sizing:border-box;
  font-size:var(--t-small);white-space:nowrap;overflow:hidden
}
.kds-course-context span{color:var(--muted);overflow:hidden;text-overflow:ellipsis}
.kds-course-context b{overflow:hidden;text-overflow:ellipsis}
.expo-ticket{grid-column:1/-1}
.expo-courses{display:grid;gap:var(--s3)}
.expo-course{min-height:96px;padding:var(--s3);background:var(--sunken);border:1px solid var(--line);border-radius:var(--radius-lg)}
.expo-course.is-held{opacity:.62}
.expo-course.is-served{background:var(--blue-lt);border-color:var(--blue)}
.expo-course-head{height:36px;display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.expo-stations{min-height:44px;margin-top:8px;display:flex;gap:8px;align-items:center;overflow-x:auto}
.expo-station{min-width:158px;gap:10px;background:var(--panel-solid);border:1px solid var(--line);font-size:var(--t-small)}
.expo-station span{color:var(--muted);text-transform:capitalize}
.expo-station.is-cooking,.expo-station.is-fired{border-color:var(--amber);background:var(--amber-lt)}
.expo-station.is-ready{border-color:var(--green);background:var(--green-lt)}
.expo-station.is-served{border-color:var(--blue);background:var(--blue-lt)}
.expo-acts{grid-template-columns:minmax(220px,1fr) 110px;min-height:68px}
.station-status{
  height:36px;min-width:86px;padding:0 14px;display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--radius-pill)!important;font-size:var(--t-small);font-weight:600
}
.station-status.is-active{background:var(--green-lt);color:var(--green)}
.station-status.is-inactive{background:var(--sunken);color:var(--muted)}
tr.is-muted{opacity:.64}
.station-order-actions{flex-wrap:nowrap}

@media(max-width:1100px){
  .kds-topbar{align-items:flex-start;flex-wrap:wrap}
  .kds-topbar .spacer{display:none}
  .kds-status-rail{align-items:flex-start;min-height:88px;flex-direction:column-reverse}
  .kds-feedback{align-self:flex-end;flex:0 0 36px;margin-top:-44px}
  .kds-all-day{width:100%;flex:0 0 36px}
  .kds-routing-rail{width:100%}
  .kds{grid-template-columns:1fr}
  .kds-items .kds-line{grid-template-columns:32px minmax(0,1fr) 82px}
  .kds-line-state{width:82px}
  .kds-line-action{grid-column:2/4;width:100%}
}

@media(max-width:560px){
  .kds-timer-rail{padding-left:10px;padding-right:10px;gap:5px}
  .kds-timer{padding:0 7px;gap:4px}
  .kds-timer small{font-size:.55rem}
  .kds-timer b{font-size:.72rem}
}

@media(min-width:1700px){ .kds{grid-template-columns:repeat(3,minmax(0,1fr))} }

.off-list{display:flex;flex-direction:column;gap:6px}
.off-row{
  display:flex;align-items:center;gap:10px;padding:8px 11px;
  background:var(--red-lt);border-radius:var(--radius-sm);font-size:.88rem;font-weight:600
}
.off-row span{flex:1;min-width:0}
.badge-inline{
  background:var(--red);color:#fff;border-radius:var(--radius-pill);font-size:.7rem;font-weight:700;
  margin-left:4px;line-height:1.4
}

/* ============================================================
   DELIVERY RUN SHEET
   Phone-first: one card, one decision, thumb-sized targets.
   ============================================================ */
.runs{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px;align-items:start}
.run{
  background:var(--panel);border:2px solid var(--line);border-radius:var(--r);
  padding:14px;display:flex;flex-direction:column;gap:9px;box-shadow:var(--shadow)
}
.run.go{border-color:var(--green)}
.run.out{border-color:var(--blue)}
.run.wait{opacity:.72}
.run-top{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.run-ref{font-weight:800;font-size:1.02rem}
.run-stage{font-size:.7rem;font-weight:700;padding:3px 9px;border-radius:var(--radius-pill);background:var(--line-2);line-height:1.4}
.run-stage.go{background:var(--green-lt);color:var(--green)}
.run-stage.out{background:var(--blue-lt);color:var(--blue)}
.run-slot{margin-left:auto;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
.run-addr{font-size:1.08rem;font-weight:700;line-height:1.35}
.run-who{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:.9rem;color:var(--muted)}
.run-tel{
  display:inline-flex;align-items:center;gap:5px;min-height:34px;padding:0 12px;
  border-radius:var(--radius-pill);background:var(--blue-lt);color:var(--blue);font-weight:700;font-size:.85rem
}

/* Cash on delivery is shouted, not mentioned. A driver who finds out at
   the door has already lost the argument. */
.run-cash{
  background:var(--amber);color:#2a1e02;border-radius:var(--radius-md);padding:10px 12px;
  display:flex;flex-direction:column;gap:1px;line-height:1.3
}
.run-cash b{font-size:1.15rem;font-weight:800;letter-spacing:.01em}
.run-cash span{font-size:.78rem;font-weight:600;opacity:.85}
.run-paid{
  background:var(--green-lt);color:var(--green);border-radius:var(--radius-md);padding:8px 12px;
  font-size:.85rem;font-weight:700
}
.run-note{font-size:.84rem;background:var(--line-2);border-radius:var(--radius-sm);padding:7px 10px;line-height:1.45}
.run-note.alert{background:var(--red-lt);color:var(--red);font-weight:600}
.run-taken{font-size:.82rem;color:var(--muted);font-style:italic}
.run-acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:auto;padding-top:4px}
.b-wide{flex:1 1 100%}

/* ============================================================
   ORDER NOTE THREAD
   ============================================================ */
.thread{display:flex;flex-direction:column;gap:8px;max-height:280px;overflow-y:auto}
/* A system entry is quieter than a person's — the eye should land on
   what somebody wrote or must answer, with the state changes as the
   thread between them. */
/* ---------- the timeline stack ---------- */
/* ---------- the timeline stack ----------
   Three columns on a fixed grid — time, spine, body — and EVERY row uses
   the same one. The previous version shifted highlighted rows 8px left
   with a negative margin so their tint could bleed to the edge, which
   moved their spine segment with them: the line kicked sideways at every
   alert and the rows no longer lined up down the left. The tint belongs
   to the body, not to the row.

   The spine is one continuous element on the container rather than a
   segment per row, so it cannot develop gaps at the joins. It stops
   short at both ends so it doesn't trail into the composer below. */
.tl{display:flex;flex-direction:column;position:relative}
.tl::before{
  content:"";position:absolute;left:52px;top:20px;bottom:20px;width:1px;
  background:var(--line)
}
.tl-empty{color:var(--muted);font-size:var(--t-small);padding:var(--s4) 0}
.tl-row{
  display:grid;grid-template-columns:46px 15px minmax(0,1fr);gap:0 10px;
  align-items:start;padding:var(--s1) 0
}
.tl-when{
  font-size:var(--t-micro);color:var(--muted);font-weight:600;
  font-variant-numeric:tabular-nums;text-align:right;padding-top:12px
}
.tl-mark{
  width:9px;height:9px;border-radius:50%;margin:14px 3px 0;z-index:1;
  background:var(--panel-solid);border:2px solid var(--line-3);box-sizing:content-box
}
/* Filled for a person, hollow for the system — findable without reading. */
.tl-person > .tl-mark{background:var(--ink-2);border-color:var(--ink-2)}
.tl-open > .tl-mark{background:var(--red);border-color:var(--red)}
/* Same padding on every body, whether or not it is tinted, so the text
   starts on the same line down the whole stack. */
.tl-body{min-width:0;padding:9px 12px;border-radius:var(--r-sm)}
.tl-head{display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap}
.tl-head b{font-size:var(--t-body);font-weight:600;line-height:1.4;min-width:0}
.tl-detail{font-size:var(--t-small);color:var(--muted);margin-top:2px}
.tl-who{font-size:var(--t-micro);color:var(--muted);margin-top:4px}
.tl-waiting{font-size:var(--t-micro);font-weight:700;color:var(--red)}
/* An open alert is the only thing here that needs answering, so it is
   the only thing that gets colour. */
.tl-open > .tl-body{background:var(--red-lt)}
.tl-open .tl-head b{color:var(--red)}
.tl-open .tl-detail{color:var(--red);opacity:.85}
/* Resolved stays: the record that somebody dealt with it is the half an
   argument with a customer turns on. */
.tl-done .tl-head b{text-decoration:line-through;text-decoration-color:var(--line-3);color:var(--muted)}
.tl-done .tl-detail{color:var(--muted)}
.tl-sys .tl-head b{font-weight:400;color:var(--ink-2)}
/* The action reads after the entry it belongs to — title, then why,
   then what to do about it, then who raised it. Right-aligning it into
   the title row made it collide with a long headline and pushed the
   reason underneath it, so the row read out of order. */
.tl-do{margin-top:var(--s2)}
.tl-do .b{width:100%;justify-content:center}

.mdl-block{
  display:flex;flex-direction:column;gap:2px;margin-bottom:14px;padding:11px 13px;
  border-radius:var(--r-sm);background:var(--red-lt);color:var(--red);line-height:1.4
}
.mdl-block b{font-size:var(--t-body)}
.mdl-block span{font-size:var(--t-small);opacity:.85}
.note-action-fields{padding:var(--s3);margin:0 0 var(--s3);border:1px solid var(--red-edge);border-radius:var(--r-sm);background:var(--red-lt)}
.note-action-fields[hidden]{display:none}
.resolution-summary,.resolution-next{
  display:flex;flex-direction:column;gap:4px;padding:var(--s3);margin-bottom:var(--s3);
  border:1px solid var(--line);background:var(--sunken);line-height:1.4
}
.resolution-summary>span{font-size:var(--t-micro);font-weight:800;color:var(--red)}
.resolution-summary>b{font-size:1rem}
.resolution-summary p,.resolution-next span{font-size:var(--t-small);color:var(--muted)}
.resolution-summary small{font-size:var(--t-micro);font-weight:600;color:var(--ink-2)}
.resolution-next{margin-top:var(--s3)}
.mdl-actions{display:flex;justify-content:flex-end;gap:var(--s2);margin-top:var(--s4);flex-wrap:wrap}
@media(max-width:640px){
  .kds{grid-template-columns:1fr}
  .runs{grid-template-columns:1fr}
  .alerts{gap:var(--s2);margin-bottom:var(--s3)}
  .al-chips{width:100%}
  .run-acts .b{flex:1 1 100%}
  .mdl-actions .b{flex:1 1 100%}
  .tl-row{grid-template-columns:38px 13px 1fr;gap:0 7px}
  .tl-row::before{left:44px}
}

/* Default states, declared rather than left implicit. A modifier class in
   the markup with no rule behind it reads like a missing style; these say
   "nothing extra needed here" out loud. suite-09 checks for exactly this. */
.kds-ticket.ok{ /* inside target time — the plain card is the right answer */ }
.kds-mode.collection{ /* base pill styling is correct for collection */ }

/* Who can do what, spelled out where someone assigns a job. */
.role-help{
  display:flex;flex-direction:column;gap:7px;margin-bottom:16px;padding:11px 13px;
  background:var(--line-2);border-radius:var(--radius-md)
}
.role-help div{display:flex;flex-direction:column;gap:1px;line-height:1.4}
.role-help b{font-size:.82rem}
.role-help span{font-size:.78rem;color:var(--muted)}
.st-role-manager{background:var(--sunken);color:var(--ink-2)}
.st-role-front{background:var(--blue-lt);color:var(--blue)}
.st-role-expo{background:var(--red-lt);color:var(--red)}
.st-role-kitchen{background:var(--amber-lt);color:var(--amber)}
.st-role-driver{background:var(--green-lt);color:var(--green)}

/* ============================================================
   ALLERGEN GRID
   Fourteen columns of checkbox against a menu of a hundred dishes.
   Headers rotate because "Sulphur dioxide / sulphites" will not fit
   a 40px column any other way, and the dish name column freezes so
   you always know which row you're ticking.
   ============================================================ */
.alg-scroll{overflow-x:auto;max-height:70vh;overflow-y:auto}
.alg-table{width:100%;border-collapse:collapse;font-size:.85rem}
.alg-table thead th{
  position:sticky;top:0;z-index:3;background:var(--panel-solid);
  border-bottom:1px solid var(--line);padding:8px 4px;vertical-align:bottom
}
/* The longest label — "Cereals containing gluten" — ran the full height
   of the cell and touched the top of the panel. The height is set from
   that label plus room to breathe, not from the average one. */
.alg-table th.alg-col{width:40px;height:166px;padding:18px 4px 10px;vertical-align:bottom}
.alg-table th.alg-col span{
  display:block;writing-mode:vertical-rl;transform:rotate(180deg);
  font-size:.72rem;font-weight:600;color:var(--ink-2);white-space:nowrap;
  margin:0 auto;letter-spacing:.02em
}
.alg-table th.alg-dish,.alg-table td.alg-dish{
  position:sticky;left:0;z-index:2;background:var(--panel-solid);
  text-align:left;min-width:190px;padding:9px 12px;border-right:1px solid var(--line)
}
.alg-table thead th.alg-dish{z-index:4}
.alg-table td.alg-dish b{display:block;line-height:1.3}
.alg-table td.alg-dish .small{color:var(--muted)}
.alg-table th.alg-act,.alg-table td.alg-act{padding:6px 12px;text-align:right;white-space:nowrap}
.alg-table tbody tr{border-bottom:1px solid var(--line-2)}
.alg-table tbody tr:hover td{background:var(--hover)}
.alg-table tbody tr:hover td.alg-dish{background:var(--hover)}
.alg-table td.alg-col{text-align:center;padding:6px 0}
.alg-table td.alg-col input{width:17px;height:17px;cursor:pointer;accent-color:var(--brand)}
/* A checked dish is visibly settled, so the eye skips to the work left. */
/* A checked row already ends in a green '✓ Checked' button; a green bar
   down its left said the same thing again, 101 times. */
.alg-table tr.alg-done{background:#fbfdfc}

/* ============================================================
   MEDIA LIBRARY
   ============================================================ */
.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.media-item{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;transition:.15s}
.media-item:hover{border-color:var(--line-3);box-shadow:var(--shadow-soft)}
.media-item.weak{border-color:#f0d3a8}
.media-thumb{position:relative;aspect-ratio:4/3;background:var(--line-2);cursor:pointer;overflow:hidden}
.media-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.media-flag{
  position:absolute;top:7px;left:7px;background:var(--amber);color:#2a1e02;
  font-size:.66rem;font-weight:800;padding:3px 7px;border-radius:var(--radius-sm);letter-spacing:.02em
}
.media-flag.ok{background:var(--green);color:#fff}
.media-flag.media-warning{width:26px;height:26px;padding:0;display:grid;place-items:center;color:#fff}
.media-flag.media-warning .ic{width:15px;height:15px}
.media-item figcaption{padding:9px 10px;display:flex;flex-direction:column;gap:2px;line-height:1.35}
.media-item figcaption b{font-size:.84rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.media-use{font-size:.72rem;color:var(--green);font-weight:600}
.off-row>span{display:flex;flex:1;min-width:0;flex-direction:column}
.off-row>span small{color:var(--muted);font-size:var(--t-small)}

.media-detail{
  position:relative;display:grid;place-items:center;block-size:clamp(240px,34vh,360px);inline-size:100%;
  border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;margin-bottom:14px;
  contain:layout paint;background-color:#f3f4f6;
  background-image:linear-gradient(45deg,rgba(28,32,39,.035) 25%,transparent 25%),
    linear-gradient(-45deg,rgba(28,32,39,.035) 25%,transparent 25%),
    linear-gradient(45deg,transparent 75%,rgba(28,32,39,.035) 75%),
    linear-gradient(-45deg,transparent 75%,rgba(28,32,39,.035) 75%);
  background-position:0 0,0 8px,8px -8px,-8px 0;background-size:16px 16px
}
.media-detail img{
  position:absolute;inset:0;display:block;inline-size:100%;block-size:100%;
  min-inline-size:0;min-block-size:0;max-inline-size:100%;max-block-size:100%;
  object-fit:contain;object-position:center;contain:paint
}
.media-modal .mdl-card{max-width:760px}
.media-variant-head{display:flex;align-items:center;gap:12px;justify-content:space-between;margin:2px 0 8px}
.media-variant-summary{flex:1;min-width:0}
.media-variant-head b{display:block;font-size:var(--t-body)}
.media-preview-meta{
  display:block;block-size:18px;line-height:18px;color:var(--muted);font-size:var(--t-small);
  margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums
}
.media-variant-actions{display:flex;align-items:center;gap:7px;flex:0 0 auto}
.media-copy{inline-size:116px;min-inline-size:116px;padding:0}
.media-copy-slot{--status-slot-inline:112px;--status-slot-block:28px}
.media-copy-label{justify-content:center;gap:5px;color:inherit;margin:0}
.media-copy.is-copied{color:var(--green);border-color:var(--green);background:var(--green-lt)}
.media-variants{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;
  max-height:180px;overflow-y:auto;margin-bottom:14px
}
.media-variant{
  display:flex;align-items:center;gap:8px;min-width:0;min-height:60px;padding:9px 10px;text-align:left;
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel)
}
.media-variant:hover{border-color:var(--line-3);background:var(--hover)}
.media-variant.on{border-color:var(--brand);background:var(--brand-lt);box-shadow:inset 0 0 0 1px var(--brand)}
.media-variant>span{min-width:0;flex:1}
.media-variant b,.media-variant small{display:block;line-height:1.35}
.media-variant b{font-size:.79rem}
.media-variant small{color:var(--muted);font-size:.7rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.media-variant .media-variant-mark{
  display:grid;place-items:center;inline-size:24px;block-size:24px;min-inline-size:24px;flex:0 0 24px;
  border-radius:50%;background:var(--brand);color:var(--brand-ink);opacity:0;transform:scale(.88);
  transition:opacity var(--motion-fast) var(--ease-standard),transform var(--motion-fast) var(--ease-standard)
}
.media-variant.on .media-variant-mark{opacity:1;transform:scale(1)}
.media-variant .media-variant-mark .ic{width:14px;height:14px;flex-basis:14px}
.media-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-top:4px}
.media-facts div{display:flex;flex-direction:column;gap:1px;background:var(--line-2);padding:9px 11px;border-radius:var(--radius-sm)}
.media-usage{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);margin-top:var(--s3);padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-sm)}
.media-usage span{color:var(--muted);font-size:var(--t-small);text-align:right}
.media-quality-note{display:flex;flex-direction:column;gap:3px;margin-top:var(--s3);padding:11px 13px;border-radius:var(--r-sm);background:var(--amber-lt);font-size:var(--t-small);line-height:1.45}
.media-quality-note.good{background:var(--green-lt)}
.media-quality-note span{color:var(--muted)}
.media-facts b{font-size:.68rem;color:var(--muted)}
.media-facts span{font-size:.85rem;overflow-wrap:anywhere}
/* Test data is an operational tool: one row per route, one click to
   create it, and no form fields that imply this is a real customer. */
.test-modal .mdl-card{max-width:590px}
.test-scenarios{display:flex;flex-direction:column;gap:8px}
.test-scenario{
  min-height:60px;display:flex;align-items:center;gap:12px;width:100%;padding:10px 12px;
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel);text-align:left
}
.test-scenario:hover{border-color:var(--line-3);background:var(--hover)}
.test-scenario>span{flex:1;min-width:0}
.test-scenario b,.test-scenario small{display:block}
.test-scenario b{font-size:var(--t-body)}
.test-scenario small{color:var(--muted);font-size:var(--t-small);margin-top:2px}
.test-scenario>.ic:last-child{width:14px;height:14px;flex-basis:14px;color:var(--muted)}
.modal-actions{display:flex;justify-content:flex-end;gap:8px}
.test-set{
  display:flex;align-items:center;gap:14px;justify-content:space-between;
  margin-top:14px;padding-top:14px;border-top:1px solid var(--line)
}
.test-set b,.test-set span{display:block}
.test-set span{color:var(--muted);font-size:var(--t-small);margin-top:2px}

/* What the importer found, before committing to downloading it */
.imp-preview{display:grid;grid-template-columns:repeat(auto-fill,minmax(74px,1fr));gap:6px;margin-top:12px;max-height:210px;overflow-y:auto}
.imp-preview img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--radius-sm);background:var(--line-2)}

/* The picker */
.pick-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;max-height:330px;overflow-y:auto;padding:2px}
.pick-img{
  border:2px solid var(--line);border-radius:var(--radius-md);overflow:hidden;background:var(--panel);
  cursor:pointer;padding:0;display:flex;flex-direction:column;position:relative;transition:.14s
}
.pick-img:hover{border-color:var(--line-3)}
.pick-img img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.pick-name{font-size:.72rem;padding:5px 7px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Still selectable — the restaurant may know better than the rule — but
   it says plainly that it will look soft here. */
.pick-img.unfit img{opacity:.45}
.pick-warn{
  position:absolute;top:6px;left:6px;background:var(--amber);color:#2a1e02;
  font-size:.62rem;font-weight:800;padding:2px 6px;border-radius:var(--radius-sm)
}

/* ============================================================
   DEVICE-AWARE LAYOUT
   ------------------------------------------------------------
   Set by applyDevice() from the role and the actual viewport. The role
   says what someone probably has; the viewport says what they picked up,
   and the viewport wins.
   ============================================================ */

/* ---- phone: the delivery driver, one hand, possibly raining ---- */
body[data-device="phone"] .main{padding:0 16px 56px}
body[data-device="phone"] .global-tools{margin:0 -16px 24px;padding:0 10px 0 8px;height:60px}
body[data-device="phone"] .topbar h1{font-size:1.15rem}
/* Every action becomes thumb-sized and full width. */
body[data-device="phone"] .b{min-height:42px;font-size:.88rem}
body[data-device="phone"] .b-sm{min-height:38px}
body[data-device="phone"] .topbar .b{flex:1 1 calc(50% - var(--s2))}

/* The allergen grid is 101 dishes by 14 columns, and on a phone that is
   1,414 checkboxes at 17px each. It is a desk job and it stays a desk
   job, but a manager standing in the kitchen with the supplier on the
   phone still has to be able to tick one box without hitting its
   neighbour. The grid keeps its shape and scrolls sideways; the targets
   get thumb-sized, which is the difference between awkward and unusable. */
body[data-device="phone"] .alg-table td.alg-col{padding:0}
body[data-device="phone"] .alg-table td.alg-col input{width:26px;height:26px;margin:5px 0}
body[data-device="phone"] .alg-table th.alg-col{width:44px}
body[data-device="phone"] .alg-table th.alg-dish,
body[data-device="phone"] .alg-table td.alg-dish{max-width:150px}
body[data-device="phone"] .runs,
body[data-device="phone"] .kds{grid-template-columns:1fr}
body[data-device="phone"] .kanban{display:grid;grid-template-columns:1fr}
body[data-device="phone"] .stats{grid-template-columns:1fr 1fr}
body[data-device="phone"] .al-stages{width:100%}
body[data-device="phone"] .al-stage{flex:1 1 0;min-width:0}
/* A modal on a phone is a sheet from the bottom, not a floating box. */
body[data-device="phone"] .mdl{align-items:flex-end;padding:0}
body[data-device="phone"] .mdl-card{max-width:none;width:100%;border-radius:var(--radius-sm) var(--radius-sm) 0 0;max-height:92vh}
body[data-device="phone"] .customer-summary{grid-template-columns:1fr}
body[data-device="phone"] .media-detail{block-size:240px}
body[data-device="phone"] .media-variant-head{align-items:flex-start;flex-direction:column}
body[data-device="phone"] .media-variant-actions{display:grid;grid-template-columns:1fr 1fr;width:100%}
body[data-device="phone"] .media-variant-head .media-variant-actions .b{width:100%;min-width:0}
body[data-device="phone"] .media-copy{inline-size:auto}
body[data-device="phone"] .media-variants{grid-template-columns:1fr;max-height:210px}
body[data-device="phone"] .test-set{align-items:stretch;flex-direction:column}
body[data-device="phone"] .test-set .b{width:100%}

/* User management is a frequent phone task when somebody is locked out
   before service. Keep the full identity and every action on-screen rather
   than hiding Reset/Disable beyond a table's horizontal scroll edge. */
body[data-device="phone"] #staffTable{min-width:0!important}
body[data-device="phone"] #staffTable thead{display:none}
body[data-device="phone"] #staffTable tbody{display:block}
body[data-device="phone"] #staffTable tbody tr{
  display:grid;grid-template-columns:minmax(0,1fr) max-content;gap:4px 12px;
  padding:14px;border-bottom:1px solid var(--line)
}
body[data-device="phone"] #staffTable tbody tr:last-child{border-bottom:0}
body[data-device="phone"] #staffTable td{display:block;padding:0;border:0;min-width:0}
body[data-device="phone"] #staffTable td:nth-child(1){grid-column:1;grid-row:1}
body[data-device="phone"] #staffTable td:nth-child(2){grid-column:1;grid-row:2}
body[data-device="phone"] #staffTable td:nth-child(3){grid-column:2;grid-row:1;text-align:right}
body[data-device="phone"] #staffTable td:nth-child(4){grid-column:2;grid-row:2;text-align:right}
body[data-device="phone"] #staffTable td:nth-child(5){grid-column:1/-1;grid-row:3;margin-top:8px}
body[data-device="phone"] #staffTable .acts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
body[data-device="phone"] #staffTable .acts .b{width:100%;padding-left:8px;padding-right:8px}

/* ---- tablet: front of house, standing, touch ---- */
body[data-device="tablet"] .main{padding:0 28px 64px}
body[data-device="tablet"] .global-tools{margin:0 -28px 32px;padding:0 20px}
/* Bigger targets than a mouse needs. */
body[data-device="tablet"] .b{min-height:44px}
body[data-device="tablet"] .kanban{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
body[data-device="phone"] .col.is-folded,
body[data-device="tablet"] .col.is-folded{flex-basis:auto;min-height:52px;max-height:52px}
body[data-device="phone"] .col.is-folded .col-head,
body[data-device="tablet"] .col.is-folded .col-head{
  min-height:52px;flex-direction:row;gap:var(--s2);padding:var(--s3);
  justify-content:flex-start;border-bottom:0
}
body[data-device="phone"] .col.is-folded .col-label,
body[data-device="tablet"] .col.is-folded .col-label{display:block}
body[data-device="phone"] .col.is-folded .col-icon,
body[data-device="tablet"] .col.is-folded .col-icon{background:var(--stage-bg)}
body[data-device="phone"] .col.is-folded .col-head .n,
body[data-device="tablet"] .col.is-folded .col-head .n{margin-left:auto}
body[data-device="tablet"] .runs{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}

/* ---- wall: the kitchen display, read from two metres ---- */
body[data-device="wall"] .main{padding:16px 20px 40px}
body[data-device="wall"] .global-tools{margin:-16px -20px var(--s5);padding:0 20px}
/* The wall screen is the same card, one size up. It keeps two columns —
   the point of the layout is that nothing wraps, and that is worth more
   from two metres away than fitting a fourth ticket on. */
body[data-device="wall"] .kds{grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}
body[data-device="wall"] .kds-ref{font-size:1.45rem}
body[data-device="wall"] .kds-clock{width:216px}
body[data-device="wall"] .kds-clock b{font-size:.9rem}
body[data-device="wall"] .kds-clock small{font-size:.64rem}
body[data-device="wall"] .kds-mode{font-size:var(--t-body)}
body[data-device="wall"] .kds-items li{font-size:1.25rem}
body[data-device="wall"] .kds-items .q{flex-basis:32px;height:32px;font-size:.95rem}
body[data-device="wall"] .kds-alg span{font-size:1.1rem}
body[data-device="wall"] .kds-acts .b{min-height:56px;font-size:1.05rem}
body[data-device="wall"] .topbar h1{font-size:1.7rem}
/* A wall display sits across the kitchen, so the row scales as a
   whole — height and padding together, never padding alone, which
   would break the shared geometry the .pill rule exists to hold. */
body[data-device="wall"] .bar-pill{height:52px;padding:0 var(--s5);font-size:var(--t-body)}
body[data-device="wall"] .al-stage b{font-size:1.4rem}


/* ============================================================
   NAVIGATION DRAWER — phone and tablet
   ------------------------------------------------------------
   The same rail, slid in from the left by the menu button at the top
   left, over a dimmed screen. Choosing a screen closes it. A strip of
   seventeen sideways-scrolling buttons was the alternative, and most of
   them were always off-screen.
   ============================================================ */
@media(max-width:900px){
  .side,body.sidebar-collapsed .side{
    display:flex;position:fixed;top:0;bottom:0;left:0;width:min(320px,86vw);height:100dvh;
    transform:translateX(-104%);transition:transform .28s var(--ease-out);z-index:300;
    box-shadow:var(--shadow-float);border-right:0;padding-top:20px
  }
  body.nav-open .side{transform:none}
  body.nav-open .nav-scrim{display:block;position:fixed;inset:0;background:rgba(24,24,27,.34);z-index:290}
  body.nav-open{overflow:hidden}
}
body[data-device="phone"] .shell,body[data-device="tablet"] .shell{grid-template-columns:1fr}
body[data-device="phone"] .side,body[data-device="tablet"] .side,
body[data-device="phone"].sidebar-collapsed .side,body[data-device="tablet"].sidebar-collapsed .side{
  display:flex;position:fixed;top:0;bottom:0;left:0;width:min(320px,86vw);height:100dvh;
  transform:translateX(-104%);transition:transform .28s var(--ease-out);z-index:300;
  box-shadow:var(--shadow-float);border-right:0;padding-top:20px
}
body.nav-open[data-device="phone"] .side,body.nav-open[data-device="tablet"] .side{transform:none}
body.nav-open[data-device="phone"] .nav-scrim,body.nav-open[data-device="tablet"] .nav-scrim{display:block;position:fixed;inset:0;background:rgba(24,24,27,.34);z-index:290}
body[data-device="phone"] .tool-clock,body[data-device="phone"] .tool-link{display:none}
.ic-touch{display:none}
@media(max-width:900px){.ic-desk{display:none}.ic-touch{display:block}}
body[data-device="phone"] .ic-desk,body[data-device="tablet"] .ic-desk{display:none}
body[data-device="phone"] .ic-touch,body[data-device="tablet"] .ic-touch{display:block}
@media(max-width:700px){
  th,td{padding:14px 12px}
  th:first-child,td:first-child{padding-left:16px}
  th:last-child,td:last-child{padding-right:16px}
  .panel-head{padding:16px 18px;min-height:60px}
  .panel-body{padding:18px}
  .stats,.stats:has(>:nth-child(5)),.stats:has(>:nth-child(6)),.stats:has(>:nth-child(7)){grid-template-columns:1fr 1fr;gap:10px;margin-bottom:28px}
  .stat{padding:16px 18px}
  .stat .num{font-size:1.6rem}
  .topbar h1{font-size:1.6rem}
}
/* Bigger tap targets inside the drawer. */
body[data-device="phone"] .side nav button,body[data-device="tablet"] .side nav button{min-height:48px}
body[data-device="phone"] .side nav .nav-items button,body[data-device="tablet"] .side nav .nav-items button{min-height:44px}
@media(prefers-reduced-motion:reduce){.side{transition:none!important}}

/* A single-screen role never needs navigation, whatever the device. */
body.single-view[data-device="phone"] .side,
body.single-view[data-device="tablet"] .side{display:none}



/* Account switched off — staff keep working, but must know why the
   website has gone dark and the orders have stopped. Deliberately at the
   very top of the page and impossible to dismiss: this is not a toast. */
.acct-notice {
  background: #7f1d1d;
  color: #fff;
  padding: 10px 16px;
  font-size: .86rem;
  line-height: 1.5;
  text-align: center;
  position: sticky;
  top: 0;
  z-index: 200;
}
.acct-notice b { font-weight: 700; }


/* ------------------------------------------------------------
   An action button carries a sentence and a phone number, and on a
   250px column that ran straight out of both sides of the card. It
   wraps now, and nothing inside it can push it wider than its parent.
   ------------------------------------------------------------ */
.tk-block .b{
  width:100%;min-width:0;white-space:normal;overflow-wrap:anywhere;
  text-align:center;line-height:1.3;padding-top:8px;padding-bottom:8px
}
.tk-block .b .ic{flex:0 0 15px}
.tk-block{min-width:0}
.ticket{min-width:0}

/* ============================================================
   INVENTORY
   ------------------------------------------------------------
   Sized for a chef's hand on a tablet, not a mouse on a desk. The
   step buttons are 44px because that is the smallest target a wet
   finger hits reliably, and the count between them is set large and
   tabular so it can be read at arm's length without leaning in.
   ============================================================ */
.stock-search{width:min(260px,30vw)}
.stock-summary{display:flex;align-items:center;gap:var(--s3);padding:0 var(--s1) var(--s3);flex-wrap:wrap}
.stock-summary span{display:inline-flex;align-items:baseline;gap:5px;color:var(--muted);font-size:var(--t-small)}
.stock-summary b{color:var(--ink);font-size:var(--t-lead);font-variant-numeric:tabular-nums}
.stock-summary .is-danger,.stock-summary .is-danger b{color:var(--red)}
.stock-summary .is-pending,.stock-summary .is-pending b{color:var(--amber)}
.stock-summary .is-complete,.stock-summary .is-complete b{color:var(--green)}

/* Did that save? A count the chef changed must say so on its own row —
   the panel-head "Saved" was too far from the number to be an answer.
   The slot is a permanent grid cell. Idle, saving, saved and failed all
   occupy exactly 132 × 32px; only the absolute child changes opacity. */
.stock-save-slot{
  --status-slot-inline:132px;--status-slot-block:32px;
  align-self:center;justify-self:start
}
.stock-save{
  gap:7px;padding:0 9px;border:1px solid transparent;border-radius:var(--r-sm);
  font-size:var(--t-small);color:var(--muted);white-space:nowrap;line-height:1
}
.stock-save.is-saving{color:var(--ink)}
.stock-save.is-saved{background:var(--green-lt);color:var(--green)}
.stock-save.is-error{
  appearance:none;justify-content:center;background:var(--red-lt);border-color:var(--red-edge);
  color:var(--red);cursor:pointer
}
.stock-save.is-error span{font-weight:600}
.stock-save.is-error span::before{content:"·";margin-right:7px}
.stock-save.is-error:hover{border-color:var(--red);background:var(--red-lt)}
.stock-sync-note{font-size:var(--t-small);font-weight:700;line-height:1.35}
.stock-sync-note.is-error{color:var(--red)}
.stock-spinner{width:14px;height:14px;flex:0 0 14px;border:2px solid var(--line-3);
  border-top-color:var(--ink);border-radius:50%;animation:stock-spin .7s linear infinite}
@keyframes stock-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.stock-spinner{animation:none}}

.stock-list{display:flex;flex-direction:column}
.stock-row{
  display:grid;grid-template-columns:minmax(220px,1fr) 132px auto minmax(180px,auto);gap:var(--s3);
  align-items:center;min-height:82px;padding:var(--s3) var(--s4);border-top:1px solid var(--line);
  transition:background var(--motion-base) var(--ease-standard),box-shadow var(--motion-base) var(--ease-standard)
}
.stock-row:first-child{border-top:0}
.stock-name{min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.stock-title{min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.stock-name b{font-weight:700;font-size:var(--t-lead);overflow-wrap:anywhere}
.stock-tag{
  font-size:var(--t-micro);font-weight:700;letter-spacing:0;
  background:var(--line-2);color:var(--muted);padding:3px 7px;border-radius:var(--r-pill)
}
.stock-tag-always{background:var(--line-2);color:var(--muted)}
.stock-tag-counted{background:var(--green-lt);color:var(--green)}
.stock-tag-out{background:var(--red);color:#fff}
.stock-meta{display:flex;align-items:center;gap:10px;flex-wrap:wrap;color:var(--muted);font-size:var(--t-micro)}
.stock-review{display:inline-flex;align-items:center;gap:6px;color:var(--amber);font-weight:700}
.stock-review i{width:7px;height:7px;border-radius:50%;background:var(--amber);box-shadow:0 0 0 3px var(--amber-lt)}
.stock-review.is-done{color:var(--muted);font-weight:600}
.stock-review.is-done i{background:var(--green);box-shadow:none}

.stock-count{display:flex;align-items:center;gap:var(--s2)}
.stock-step{
  width:44px;height:44px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--panel-solid);font-size:1.25rem;font-weight:600;color:var(--ink);
  cursor:pointer;line-height:1;transition:.12s
}
.stock-step:hover{background:var(--hover);border-color:var(--line-3)}
.stock-step:active{transform:scale(.94)}
.stock-step:disabled,.stock-acts .b:disabled{cursor:not-allowed;opacity:.45;transform:none}
.stock-num{
  min-width:2.6ch;text-align:center;font-size:1.4rem;font-weight:700;
  font-variant-numeric:tabular-nums;line-height:1
}
.stock-num.is-zero{color:var(--muted)}
.stock-restock{display:flex;justify-content:flex-end}
.stock-restock .b{min-height:44px}
.stock-acts{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
.stock-stop,.stock-verify{border:0;background:transparent;color:var(--muted);font-size:var(--t-small);font-weight:650;padding:7px 2px;white-space:nowrap}
.stock-stop:hover,.stock-verify:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.stock-stop:disabled,.stock-verify:disabled{opacity:.45;cursor:not-allowed;text-decoration:none}
.stock-86{white-space:normal;line-height:1.25}

/* Running low is amber, gone is red — the same language the board uses,
   so nobody has to learn a second colour scheme. */
.stock-row.is-unreviewed{box-shadow:none}
.stock-row.is-tracked{background:transparent;box-shadow:none}
.stock-row.is-low{background:var(--amber-lt);box-shadow:none}
.stock-row.is-low .stock-num{color:var(--amber)}
.stock-row.is-out{background:var(--red-lt);box-shadow:none}
.stock-row.is-out .stock-num{color:var(--red)}
.stock-row.is-out .stock-title>b{color:var(--muted)}
.stock-row.is-saving{box-shadow:none}
.stock-row.is-saved{box-shadow:none}
.stock-row.is-unsaved{background:var(--red-lt);box-shadow:none}

@media(max-width:720px){
  .stock-search{width:100%}
  .stock-row{grid-template-columns:auto minmax(0,1fr) 132px;
    grid-template-areas:"name name status" "count acts acts";
    column-gap:var(--s3);row-gap:var(--s2);padding:var(--s3)}
  .stock-name{grid-area:name}
  .stock-save-slot{grid-area:status}
  .stock-count,.stock-restock{grid-area:count;justify-content:flex-start}
  .stock-acts{grid-area:acts;justify-content:flex-start;width:100%}
  .stock-acts .b{min-height:42px}
}
@media(max-width:520px){
  .stock-row{grid-template-columns:minmax(0,1fr);grid-template-areas:"name" "count" "acts"}
  .stock-save-slot{grid-area:count;justify-self:end;z-index:1}
}

/* Where a button would be for the department that owns this step. An
   empty space reads as a broken screen; this reads as "not yours, and
   here is who to find". */
.step-locked{display:inline-flex;align-items:center;font-size:var(--t-small);
  color:var(--muted);background:var(--sunken);border:1px solid var(--line);
  border-radius:var(--r-md);padding:6px 10px;line-height:1.3;max-width:22rem}


/* ============================================================
   THE CHECKOUT
   ------------------------------------------------------------
   Every dimension in here is fixed before there is anything to put in
   it. A bill is read while a guest waits, and a number that moves under
   the cursor as a total resolves is how the wrong button gets pressed.

   Two rules do the work:
     · the parts list reserves its height, so switching Seat -> Equal
       does not resize the modal under the pointer;
     · every row carries a .status-slot, so "Taking..." -> "Paid" is an
       opacity change inside a box that was always that size.
   ============================================================ */
.co{display:flex;flex-direction:column;gap:var(--s4)}

/* The split chooser. Same geometry contract as .bar-pill: one class
   owns height, radius and padding, and the states are colour only. */
.co-tabs{display:flex;flex-wrap:wrap;gap:var(--s2)}
.co-tab{
  display:inline-flex;align-items:center;justify-content:center;
  height:36px;padding:0 var(--s4);border-radius:var(--radius-pill);
  border:1px solid var(--line-2);background:var(--card);color:var(--muted);
  line-height:1;white-space:nowrap;cursor:pointer;
  font-size:var(--t-small);font-weight:600;font-family:inherit;
  transition:background var(--motion-base) var(--ease-standard),
             color var(--motion-base) var(--ease-standard)
}
.co-tab[aria-selected="true"]{background:var(--brand);color:#fff;border-color:transparent}
.co-close{width:132px;flex:0 0 132px}

/* Reserved before the parts exist. min-block-size, not height: a
   twelve-seat table is allowed to grow, a four-top must not shrink the
   modal when it switches mode. */
.co-parts{
  display:flex;flex-direction:column;gap:var(--s2);
  min-block-size:13.5rem;contain:layout
}
.co-part{
  display:flex;align-items:center;gap:var(--s3);
  min-block-size:3rem;padding:0 var(--s4);
  border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--card)
}
.co-part[data-paid="true"]{opacity:.55}
.co-part .co-part-name{flex:1;min-inline-size:0;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.co-part .co-part-sub{display:block;font-size:var(--t-small);font-weight:400;color:var(--muted)}
.co-part .co-part-amt{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}

/* The money read-out. Fixed row heights and tabular figures, so the
   digits do not shuffle sideways as a total changes. */
.co-sums{
  display:flex;flex-direction:column;gap:0;
  border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:var(--s3) var(--s4);background:var(--sunk,var(--card))
}
.co-sum{display:flex;align-items:center;justify-content:space-between;
  block-size:2rem;font-size:var(--t-small);color:var(--muted)}
.co-sum b{font-variant-numeric:tabular-nums;color:var(--ink);font-weight:600}
.co-sum.co-owed{block-size:2.5rem;font-size:1rem;color:var(--ink);font-weight:600}
.co-sum.co-owed b{font-size:1.25rem}

.co-tenders{display:flex;flex-wrap:wrap;gap:var(--s2)}
.co-amounts{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:flex-end}
.co-amounts .fld{flex:1 1 8rem;min-inline-size:0}

/* One reserved place for every answer this panel can give — refusal,
   progress and success share it, so none of them moves the buttons. */
.co-feedback{
  --status-slot-inline:100%;--status-slot-block:2.75rem;
  display:block;inline-size:100%
}
.co-feedback .fade-badge{
  justify-content:flex-start;padding:0 var(--s3);border-radius:var(--radius-md);
  font-size:var(--t-small);line-height:1.35;white-space:normal
}
.co-feedback[data-state="working"] .co-working,
.co-feedback[data-state="bad"] .co-bad,
.co-feedback[data-state="good"] .co-good{opacity:1;transform:none}
.co-bad{background:var(--red-soft,rgba(200,60,60,.10));color:var(--red)}
.co-good{background:var(--green-soft,rgba(40,140,90,.10));color:var(--green)}
.co-working{color:var(--muted)}

@media (prefers-reduced-motion:reduce){
  .co-tab,.co-feedback .fade-badge{transition:none}
}

/* ---- Training mode (demo fix D6) ----
   "Test service" and "Skip ahead 2 hours" make fake orders and move the
   clock. They only show to a manager who has turned Training mode on, with
   a banner across every screen so nobody mistakes it for a real service. */
body:not(.training) .training-only{display:none!important}
.training-banner{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s4);
  padding:10px 14px;border-radius:var(--r-md);background:var(--amber-lt);border:1px solid var(--amber-edge);font-size:.9rem}
.training-banner b{color:var(--amber)}
.training-banner span{flex:1;min-width:200px}

/* A folded stage was an icon and a number with no name (demo fix D7.7).
   The rail now carries a one-word name under the icon; tablets and
   phones already show the full label when folded, so it stays hidden there. */
.col-short{display:none}
.col.is-folded .col-short{display:block;font-size:.66rem;font-weight:700;letter-spacing:.02em;
  color:var(--muted);text-align:center;max-width:100%;overflow:hidden;text-overflow:ellipsis}
body[data-device="phone"] .col.is-folded .col-short,
body[data-device="tablet"] .col.is-folded .col-short{display:none}
@media (max-width: 900px){ .col.is-folded .col-short{display:none} }

/* A closed ticket keeps one quiet way to read what happened, set as a
   link at the end of its total row rather than a full-width button. */
.tk-history{margin-left:auto;padding:6px 2px;color:var(--ink-2);font-size:var(--t-small);font-weight:600;text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--line-3)}
.tk-history:hover{color:var(--ink);text-decoration-color:currentColor}
.foh-course-spine.is-closed{opacity:.8}

/* When every stage is unfolded the columns get narrow. The stage icon
   gives up its place before a stage name is broken mid-word. */
.col{container-type:inline-size;container-name:board-col}
@container board-col (max-width:210px){
  .col-head{grid-template-columns:minmax(0,1fr) auto 14px;padding:14px 12px}
  .col-icon{display:none}
  .col-body{padding:10px}
}

/* Paid at handover — two equal choices, nothing else to read */
.pay-ask{font-size:var(--t-lead);margin:0 0 16px}
.pay-tenders{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px}
.pay-tenders .b{width:100%;justify-content:center}
.pay-note{margin:0 0 16px}

/* ============================================================
   THE ORDER PAD — menu left, check right; one column on a phone
   ============================================================ */
.pad{position:fixed;inset:0;z-index:90;background:rgba(24,24,27,.34);display:flex;align-items:stretch;justify-content:center;padding:16px}
.pad[hidden]{display:none}
body.pad-open{overflow:hidden}
.pad-sheet{background:var(--bg);border-radius:var(--radius-lg);box-shadow:var(--shadow-float);width:100%;max-width:1440px;display:flex;flex-direction:column;min-height:0;overflow:hidden}
.pad-head{display:flex;align-items:center;gap:16px;padding:16px 20px;background:var(--panel);border-bottom:1px solid var(--line)}
.pad-title{flex:1;min-width:0}
.pad-title h2{font-size:var(--t-h2);font-weight:750;margin:0}
.pad-title .sub{color:var(--muted);font-size:var(--t-small)}
.pad-mode button{min-height:40px;padding:0 16px}
.pad-close{flex:0 0 auto}
.pad-who{padding:12px 20px;background:var(--panel);border-bottom:1px solid var(--line)}
.pad-fields{display:flex;flex-wrap:wrap;gap:12px 16px;align-items:flex-end}
.pad-field{display:flex;flex-direction:column;gap:6px;min-width:150px}
.pad-field>span{font-size:var(--t-micro);font-weight:650;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
.pad-field.pad-wide{flex:1 1 260px}
.pad-seats{flex:1 1 320px}
.pad-zone{margin:10px 0 0;font-size:var(--t-small);color:var(--green)}
.pad-zone.bad{color:var(--red)}
.stepper{display:inline-flex;align-items:center;gap:10px}
.stepper b{min-width:22px;text-align:center;font-variant-numeric:tabular-nums}
.stepper .b{min-width:40px;justify-content:center}
.chips{display:flex;flex-wrap:wrap;gap:6px}
.chip{display:inline-flex;align-items:center;min-height:40px;padding:0 14px;border-radius:var(--radius-pill);border:1px solid var(--line-3);background:var(--panel);font-size:var(--t-small);font-weight:600;color:var(--ink-2);white-space:nowrap}
.chip.on{background:var(--ink);border-color:var(--ink);color:#fff}
.pad-switch{display:none}
.pad-body{flex:1;min-height:0;display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,420px)}
.pad-menu{display:flex;flex-direction:column;min-height:0;min-width:0;padding:16px 20px;gap:12px}
.pad-search{position:relative}
.pad-search .ic{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--muted);pointer-events:none}
.pad-search .in{padding-left:42px;width:100%}
.pad-cats{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px;scrollbar-width:none}
.pad-grid{flex:1;min-height:0;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px;align-content:start;padding-bottom:16px}
.pad-cat-head{grid-column:1/-1;font-size:var(--t-micro);font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-top:8px}
.pad-dish{position:relative;display:flex;flex-direction:column;gap:6px;text-align:left;min-height:84px;padding:12px 14px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:var(--shadow-soft);transition:border-color .12s,transform .06s}
.pad-dish:hover{border-color:var(--line-3)}
.pad-dish:active{transform:scale(.98)}
.pad-dish-top{display:flex;gap:8px;justify-content:space-between;align-items:baseline}
.pad-dish-top b{font-size:var(--t-body);font-weight:650;line-height:1.3}
.pad-dish small{font-size:var(--t-micro);color:var(--muted);line-height:1.35}
.pad-dish small.warn{color:var(--amber)}
.pad-dish.is-off{opacity:.55;cursor:not-allowed}
.pad-dish-count{position:absolute;top:-7px;right:-7px;min-width:24px;height:24px;padding:0 7px;border-radius:var(--radius-pill);background:var(--ink);color:#fff;font-size:var(--t-micro);font-weight:700;display:inline-flex;align-items:center;justify-content:center}
.pad-empty{grid-column:1/-1}
.pad-ticket{display:flex;flex-direction:column;min-height:0;min-width:0;background:var(--panel);border-left:1px solid var(--line);overflow-y:auto}
.pad-section{padding:16px 20px;border-bottom:1px solid var(--line-2)}
.pad-section h3{font-size:var(--t-small);font-weight:700;margin:0 0 10px;color:var(--ink-2)}
.pad-start p{color:var(--muted);font-size:var(--t-small);margin:0}
.pad-course+.pad-course{margin-top:12px}
.pad-course-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;font-size:var(--t-small)}
.pad-st-held{background:var(--sunken);color:var(--ink-2)}
.pad-st-fired,.pad-st-cooking{background:var(--amber-lt);color:var(--amber)}
.pad-st-ready{background:var(--green-lt);color:var(--green)}
.pad-st-served{background:var(--sunken);color:var(--muted)}
.pad-line{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;gap:10px;align-items:center;padding:8px 0}
.pad-line+.pad-line{border-top:1px solid var(--line-2)}
.pad-line .q{font-weight:700;font-variant-numeric:tabular-nums;min-width:20px}
.pad-line .n{display:flex;flex-direction:column;gap:2px;min-width:0;font-weight:600}
.pad-line .n small{font-size:var(--t-micro);color:var(--muted);font-weight:500}
.pad-line .num{font-variant-numeric:tabular-nums;font-size:var(--t-small)}
.pad-line.is-void{opacity:.6}
.pad-line.is-draft{grid-template-columns:auto minmax(0,1fr) auto;row-gap:6px}
.pad-line-opts{grid-column:2/-1;display:flex;gap:8px}
.pad-line-opts .in{min-height:36px;padding-top:0;padding-bottom:0;font-size:var(--t-small)}
.pad-note{align-self:flex-start;font-size:var(--t-micro);color:var(--muted);text-decoration:underline;text-underline-offset:2px;font-weight:500}
.pad-note-in{min-height:36px;font-size:var(--t-small)}
.pad-void{display:flex;gap:8px;align-items:center;padding:0 0 10px 30px;flex-wrap:wrap}
.pad-void .in{flex:1 1 180px;min-height:36px;font-size:var(--t-small)}
.pad-voided{margin-top:8px}
.pad-foot{margin-top:auto;position:sticky;bottom:0;padding:14px 20px 18px;background:var(--panel);border-top:1px solid var(--line);display:flex;flex-direction:column;gap:6px}
.pad-sum{display:flex;justify-content:space-between;font-size:var(--t-small);color:var(--ink-2)}
.pad-total{font-size:var(--t-lead);font-weight:750;color:var(--ink);margin-top:2px}
.pad-acts{display:flex;gap:8px;margin-top:8px}
.pad-acts .b{flex:1;justify-content:center}
.pad-go{width:100%;justify-content:center;margin-top:8px}
.pad-acts .pad-go{margin-top:0}
.tk-line-note{display:block;color:var(--muted);font-size:var(--t-micro)}
.tk-item-void{opacity:.55}
.kds-note{display:block;font-weight:700}
.floor-check{margin:0 0 16px;display:flex;flex-direction:column;gap:6px}
.floor-check.has-check{padding:12px 14px;border:1px solid var(--green-edge);background:var(--green-lt);border-radius:var(--radius-md)}
.floor-check-top{display:flex;justify-content:space-between;font-size:var(--t-small)}
.floor-check .b{align-self:flex-start}
.tbl.has-check::after{content:"";position:absolute;top:6px;right:6px;width:9px;height:9px;border-radius:var(--radius-pill);background:var(--green);box-shadow:0 0 0 2px #fff}

@media (max-width:899px){
  .pad{padding:0}
  .pad-sheet{border-radius:0}
  .pad-head{padding:12px 16px;gap:10px;flex-wrap:wrap}
  .pad-mode{order:3;width:100%}
  .pad-mode button{flex:1}
  .pad-who{padding:10px 16px}
  .pad-field{min-width:0;flex:1 1 140px}
  .pad-switch{display:flex;margin:10px 16px 0;width:auto}
  .pad-switch button{flex:1;min-height:40px}
  /* One page that scrolls, not three boxes fighting for 844px. */
  .pad-sheet{overflow-y:auto;-webkit-overflow-scrolling:touch}
  .pad-sheet>*{flex-shrink:0}
  .pad-body{grid-template-columns:minmax(0,1fr);flex:none}
  .pad-grid,.pad-ticket{overflow:visible}
  .pad-switch{position:sticky;top:0;z-index:2;background:var(--sunken)}
  .pad-body.pane-menu .pad-ticket{display:none}
  .pad-body.pane-ticket .pad-menu{display:none}
  .pad-ticket{border-left:0}
  .pad-menu{padding:12px 16px}
  .pad-grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
}
.pad-warn{margin:0 0 6px;font-size:var(--t-small);color:var(--amber);font-weight:600}
