/* The app's one stylesheet: the tokens, the three shells (Operator, staff,
   storefront), and every component more than one screen uses.

   Row 7.7 (card #53): a component lives HERE, once. A screen's own stylesheet
   holds only what is unique to that screen, and never redefines a component
   this file owns — tests/unit/checks/css.php fails when one does, and when a
   font-size, spacing or radius is a literal rather than a token.
   docs/OPERATOR-LOOK.md is the spec. */

:root {
  /* Colour. Row 7.10 (Cameron, 2026-10-19: "a modern professional look"): a cooler
     neutral page, white cards that sit on it with a soft shadow, and one blue. */
  --bg: #f4f5f7; --surface: #ffffff; --ink: #111827; --muted: #5b6472; --line: #e3e6eb;
  --line-strong: #8a93a2;  /* a control's edge: 3.1:1 on white, the floor for a border */
  --brand: #2b59c3; --brand-ink: #ffffff; --accent: #eef3ff; --field: #ffffff;
  --ok-bg: #e7f5ec; --ok-ink: #1c5e33; --error-bg: #fcebea; --error-ink: #8a1f17;
  --info-bg: #eef3ff; --info-ink: #1f3f8a; --viewing-bg: #f39c12; --viewing-ink: #1d1300;
  --shadow: 0 1px 2px rgb(16 24 40 / .06), 0 1px 3px rgb(16 24 40 / .08);
  --shadow-raised: 0 8px 24px rgb(16 24 40 / .14);

  /* Type. Five sizes, and no others: every font-size in public/assets/*.css is one of these. */
  --text-xs: .8125rem;   /* 13px: table meta, status pills, counts */
  --text-s: .875rem;     /* 14px: hints, sub-menu items, table cells */
  --text-m: 1rem;        /* body, fields, buttons */
  --text-l: 1.25rem;     /* card and section headings (h2) */
  --text-xl: 1.625rem;   /* screen title (h1), tile counts */
  --weight-strong: 600;  /* h1, h2, current menu item, primary button */
  --weight-label: 500;   /* labels, table headings, top menu items */

  /* Spacing. Every margin, gap and padding is one of these. */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px;

  /* Shape and control height. */
  --radius: 12px;           /* cards */
  --radius-control: 8px;    /* inputs, buttons, tabs, menu items */
  --radius-pill: 999px;     /* status pills and count badges */
  --control-h: 44px;        /* buttons, inputs, selects: the tap minimum */
  --control-h-s: 36px;      /* button.small, table row actions (desktop only) */

  /* The Operator's frame. Row 7.10 keeps row 7.6's shape — a dark sidebar under a
     dark bar, the current group open — and modernises it: wider, rounded items,
     a soft highlight instead of wp-admin's blue block and arrow.
     dark-ok: the frame is the SAME in light and dark; the screens inside it keep
     the tokens above and follow the device. */
  --bar-h: 52px;
  --nav-w: 240px;
  --nav-bg: #111827;
  --nav-ink: #e5e7eb;
  --nav-icon: #9ca3af;
  --nav-hover-ink: #ffffff;
  --nav-hover-bg: rgb(255 255 255 / .07);
  --nav-open-bg: #1f2937;               /* the account panel and the folded flyouts */
  --nav-sub-ink: #c3c8d0;
  --nav-heading-ink: #9ca3af;
  --nav-current-bg: rgb(255 255 255 / .12);
  --nav-current-ink: #ffffff;
  --nav-mark: #7aa7ff;                  /* the bar beside the current item */
  --nav-arrow: var(--bg);

  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d1117; --surface: #161b22; --ink: #e6edf3; --muted: #9aa5b4; --line: #2a313c; --line-strong: #5c6a80;
    --brand: #7aa7ff; --brand-ink: #0b1220; --accent: #1b2538; --field: #0d1117;
    --ok-bg: #173323; --ok-ink: #a6e0bb; --error-bg: #3a1714; --error-ink: #f3b1aa;
    --info-bg: #182638; --info-ink: #b5d0f0;
    --shadow: 0 0 0 1px rgb(255 255 255 / .02); --shadow-raised: 0 8px 24px rgb(0 0 0 / .5);
  }
}

/* ---- base ---------------------------------------------------------------- */

* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink); font: var(--text-m)/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased; }
a { color: var(--brand); text-underline-offset: 2px; }
h1 { font-size: var(--text-xl); font-weight: var(--weight-strong); letter-spacing: -.015em; line-height: 1.2; margin: 0 0 var(--space-3); }
h2 { font-size: var(--text-l); font-weight: var(--weight-strong); letter-spacing: -.01em; line-height: 1.3; margin: 0 0 var(--space-3); }
h3 { font-size: var(--text-m); font-weight: var(--weight-strong); margin: 0 0 var(--space-2); }
p { margin: 0 0 var(--space-3); }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: var(--space-2); top: var(--space-2); background: var(--surface); padding: var(--space-2); z-index: 10; }
.muted, .hint { color: var(--muted); }
.hint { margin: var(--space-1) 0 0; font-size: var(--text-s); }
.small { font-size: var(--text-xs); }
.crumbs { margin: 0 0 var(--space-1); font-size: var(--text-s); color: var(--muted); }
.crumbs a { color: var(--muted); }
.lead { max-width: 760px; color: var(--muted); }
.pre, .prewrap { white-space: pre-wrap; overflow-wrap: anywhere; }
/* A placeholder or shortcode is one long word: it breaks rather than run off a phone at a larger text size (card #167). */
code { overflow-wrap: anywhere; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---- shells ------------------------------------------------------------- */

/* The staff shell's bar and the Operator's are the frame's (below). */
.topbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); padding: var(--space-3) var(--space-4); background: var(--brand); color: var(--brand-ink); }
.topbar a, .topbar .button-link { color: var(--brand-ink); }
.topbar .store-name { font-weight: var(--weight-strong); text-decoration: none; margin-right: auto; }
.topbar .who { font-size: var(--text-s); }
.topbar .button-quiet { border: 1px solid currentColor; background: transparent; color: var(--brand-ink); }
.site-header { padding: var(--space-4); background: var(--surface); border-bottom: 1px solid var(--line); }
.site-header .store-name { font-weight: var(--weight-strong); font-size: var(--text-l); text-decoration: none; color: var(--ink); }

/* minmax(0, 1fr), not 1fr: a 1fr track will not shrink below its content, which is what
   made the whole page scroll sideways at 835 px (docs/OPERATOR-LOOK.md, Overview 2). */
.frame { display: grid; grid-template-columns: var(--nav-w) minmax(0, 1fr); min-height: calc(100dvh - var(--bar-seen, var(--bar-h))); }
main { padding: var(--space-5) var(--space-6); max-width: 1440px; width: 100%; min-width: 0; }
.shell-storefront main, main.narrow { margin: 0 auto; max-width: 720px; }

/* ---- the Operator's frame: a dark bar and sidebar, in both modes -------- */

/* One row at the standard text size, at every width. When her words are larger than the bar has room for (the
   app's sheet sets a minimum text size from the phone's, docs/APP-API.md "The sheet"; a computer's text size does
   the same), the bar wraps onto a second row rather than cut off its right end, where the account menu and Sign
   out are (card #167). Every control keeps its own width (flex: none); the store's name and the search box start
   from their smallest (flex-basis 0 and 9rem), because a flex row breaks a line by each item's starting width
   before anything shrinks, and then grow into what the row leaves. A row that wrapped keeps to the right, so the
   account menu's panel opens inside the screen. The sidebar sticks under the bar's measured height, --bar-seen
   (app-menu.js), so a bar of two rows never covers it. */
.shell-operator .topbar, .shell-staff .topbar {
  position: sticky; top: 0; z-index: 40;
  flex-wrap: wrap; justify-content: flex-end; gap: var(--space-1) var(--space-2); padding: 0 var(--space-4) 0 var(--space-3); min-height: var(--bar-h);
  background: var(--nav-bg); color: var(--nav-ink); font-size: var(--text-s);
  border-bottom: 1px solid rgb(255 255 255 / .08);
}
/* :where(), so the name's and the search box's own flex below win over it. */
:where(.shell-operator .topbar, .shell-staff .topbar) > * { flex: none; }
.shell-operator .topbar a, .shell-staff .topbar a,
.shell-operator .topbar .button-link, .shell-staff .topbar .button-link { color: var(--nav-ink); }
.shell-operator .topbar a:hover, .shell-staff .topbar a:hover,
.shell-operator .topbar a:focus-visible, .shell-staff .topbar a:focus-visible,
.shell-operator .topbar .button-link:hover, .shell-staff .topbar .button-link:hover { color: var(--nav-hover-ink); }
/* The bar is dark in BOTH modes, so a control on it takes the bar's own ink, never --brand-ink,
   which is near-black in dark mode and would leave the Test Mode pill unreadable. */
.shell-operator .topbar .button-quiet, .shell-staff .topbar .button-quiet { border-color: rgb(255 255 255 / .28); color: var(--nav-ink);
  min-height: var(--control-h-s); font-size: var(--text-xs); border-radius: var(--radius-pill); padding: 0 var(--space-3); }
.shell-operator .topbar .button-quiet:hover, .shell-staff .topbar .button-quiet:hover { border-color: var(--nav-hover-ink); color: var(--nav-hover-ink); background: var(--nav-hover-bg); }
.shell-operator .topbar :focus-visible, .shell-staff .topbar :focus-visible { outline-color: var(--nav-mark); }

/* The store's name, with its first letter as a badge, as a modern admin's workspace switcher. */
.shell-operator .topbar .store-name, .shell-staff .topbar .store-name { display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: var(--control-h); font-size: var(--text-m); font-weight: var(--weight-strong); }
.shell-operator .topbar .store-name::before { content: attr(data-initial); display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; border-radius: var(--radius-control); background: var(--nav-mark); color: var(--nav-bg);
  font-size: var(--text-s); font-weight: 700; }
.shell-operator .topbar .store-name[data-initial=""]::before { display: none; }

/* Visit site and Report a problem: quiet links with an icon, the words hidden below 480px. */
.topbar .visit-site, .topbar .report-problem { display: inline-flex; align-items: center; gap: var(--space-2); text-decoration: none;
  min-height: var(--control-h-s); padding-inline: var(--space-3); border-radius: var(--radius-pill); }
.shell-operator .topbar .visit-site, .shell-staff .topbar .visit-site,
.shell-operator .topbar .report-problem { color: var(--nav-sub-ink); font-size: var(--text-xs); }
.shell-operator .topbar .visit-site:hover, .shell-staff .topbar .visit-site:hover,
.shell-operator .topbar .report-problem:hover { color: var(--nav-hover-ink); background: var(--nav-hover-bg); }
@media (max-width: 480px) {
  .topbar .visit-site-words { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
}
/* A 360 px phone keeps the bar on one row at the standard text size: Menu with its word, the store's badge, Visit
   site, Test Mode and the account menu, 4 px apart. */
@media (max-width: 400px) {
  .shell-operator .topbar, .shell-staff .topbar { column-gap: var(--space-1); padding-inline: var(--space-2); }
}
.account-panel .report-problem-menu { display: none; }
/* Row 15.1 (card #172): Help, just before Report a problem and the same quiet link, in the same window. As with Report a
   problem, the account menu's copy shows only below 768 px, where the bar's is hidden, so exactly one is on screen. */
.topbar .help-link { display: inline-flex; align-items: center; gap: var(--space-2); text-decoration: none;
  min-height: var(--control-h-s); padding-inline: var(--space-3); border-radius: var(--radius-pill); }
.shell-operator .topbar .help-link { color: var(--nav-sub-ink); font-size: var(--text-xs); }
.shell-operator .topbar .help-link:hover, .shell-operator .topbar .help-link[aria-current="page"] { color: var(--nav-hover-ink); background: var(--nav-hover-bg); }
.account-panel .help-link-menu { display: none; }
/* Row 15.2 (card #173): Help for this page, a panel over the screen (public/assets/js/help.js). A side sheet from
   768 px, the whole screen on a phone; the article inside brings help.css with it. */
.help-panel { margin: 0 0 0 auto; padding: 0; width: min(36rem, 100vw); max-width: 100vw; height: 100dvh; max-height: 100dvh;
  border: 0; border-left: 1px solid var(--line); background: var(--bg); color: var(--ink); box-shadow: var(--shadow-raised); }
.help-panel[open] { display: flex; flex-direction: column; }
.help-panel::backdrop { background: rgb(0 0 0 / .45); }
/* Rows 17.1 and 17.2 (cards #179, #180): a question asked before a text or an email goes, in a dialog its script draws. */
.ask-dialog { width: min(32rem, calc(100vw - 2 * var(--space-4))); border: 0; border-radius: var(--radius); padding: var(--space-5);
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-raised); }
.ask-dialog::backdrop { background: rgb(0 0 0 / .45); }
.ask-dialog h2 { margin-top: 0; }
/* Card #178 (OPERATOR-LOOK.md, "Settings form, unsaved change"): a Save row marked data-save-bar rides along the bottom
   of the window once its form has changed (site-pages.js), so Save is in reach on a long screen like Header. Below the
   sidebar and its flyouts (30), the phone menu (35) and the top bar (40), so no menu item is ever under it. */
.save-bar.is-floating { position: sticky; bottom: 0; z-index: 20; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin: 0; padding: var(--space-3) var(--space-4); background: var(--surface); border-top: 1px solid var(--line); box-shadow: var(--shadow-raised); }
@media (prefers-reduced-motion: no-preference) { .save-bar.is-floating { animation: fmb-save-bar 200ms ease-out; } }
/* Card #178: what Save and visit site says beside its buttons, once it has posted the form into a new tab. */
.save-status { color: var(--muted); }
.save-status:empty { display: none; }
@keyframes fmb-save-bar { from { transform: translateY(100%); } to { transform: translateY(0); } }
.help-panel-bar { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2) var(--space-1) var(--space-4);
  background: var(--nav-bg); color: var(--nav-ink); }
.help-panel-name { margin: 0 auto 0 0; font-weight: var(--weight-strong); }
.help-panel-bar .help-panel-all { display: inline-flex; align-items: center; min-height: 48px; padding: 0 var(--space-3); color: var(--nav-ink);
  border-radius: var(--radius-control); }
.help-panel-close { min-width: 48px; min-height: 48px; padding: 0 var(--space-3); border: 1px solid rgb(255 255 255 / .25); border-radius: var(--radius-control);
  background: transparent; color: var(--nav-ink); font-size: var(--text-m); } /* dark-ok: the panel's bar is the top bar's colour */
.help-panel-bar :focus-visible { outline-color: var(--nav-mark); }
.help-panel-body { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; padding: var(--space-4) var(--space-5) var(--space-6); }
.help-panel-body .help-article h1 { font-size: var(--text-xl); }
.help-panel-wait { color: var(--muted); }
body.help-open { overflow: hidden; }

/* The name gives way first, never below 3em (its badge and a letter), so the bar wraps only when even that leaves
   no room. From nothing (flex-basis 0) it grows into its row before the search box does (its grow of 1000 to the
   box's 1), up to its own full width (max-content) and no wider, so a long name is cut short with an ellipsis
   rather than push the account menu onto a second row: on a 1024 px computer, "Nourish Together Freezer Meals"
   with "Stephanie Rodriguez-Hernandez" in the account menu had sent her name to a row of its own (card #164's
   review). */
.shell-operator .topbar .store-name, .shell-staff .topbar .store-name { flex: 1000 1 0; min-width: 3em; margin-right: auto; max-width: max-content;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.menu-button { display: none; align-items: center; gap: var(--space-2); background: transparent; color: var(--nav-ink);
  border: 0; min-height: var(--control-h); min-width: var(--control-h); padding: 0 var(--space-2); font-size: var(--text-s); }
.menu-button:hover, .menu-button:focus-visible { color: var(--nav-hover-ink); }

.account-menu { position: relative; }
.account-menu > summary { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; list-style: none;
  min-height: var(--control-h); padding: 0 var(--space-3); white-space: nowrap; border-radius: var(--radius-pill); }
.account-menu > summary::-webkit-details-marker { display: none; }
.account-menu > summary:hover, .account-menu > summary:focus-visible { color: var(--nav-hover-ink); background: var(--nav-hover-bg); }
.account-panel { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: 50; display: flex; flex-direction: column; align-items: stretch;
  gap: 0; min-width: 13rem; padding: var(--space-2); background: var(--nav-open-bg); color: var(--nav-ink);
  border: 1px solid rgb(255 255 255 / .08); border-radius: var(--radius); box-shadow: var(--shadow-raised); }
.account-panel a, .account-panel .button-link { color: var(--nav-ink); text-decoration: none; min-height: var(--control-h); display: flex; align-items: center;
  padding: 0 var(--space-3); border-radius: var(--radius-control); width: 100%; }
.account-panel form { display: flex; }
.account-panel a:hover, .account-panel .button-link:hover { color: var(--nav-hover-ink); background: var(--nav-hover-bg); }

/* The sidebar. */
.app-menu { background: var(--nav-bg); color: var(--nav-ink); padding: var(--space-3) var(--space-2) var(--space-6);
  position: sticky; top: var(--bar-seen, var(--bar-h)); align-self: start; height: calc(100dvh - var(--bar-seen, var(--bar-h))); overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: rgb(255 255 255 / .2) transparent; }
.app-menu ul { list-style: none; margin: 0; padding: 0; }
.app-menu > .menu-top > li + li { margin-top: var(--space-1); }
.app-menu .menu-row { display: flex; align-items: stretch; border-radius: var(--radius-control); }
.app-menu a { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; color: var(--nav-ink); border-radius: var(--radius-control); }
.app-menu a[data-level="top"] { flex: 1; min-width: 0; min-height: 38px; padding: 0 var(--space-2) 0 var(--space-3); font-size: var(--text-s); font-weight: var(--weight-label); }
.app-menu .menu-icon { flex: none; color: var(--nav-icon); }
.app-menu .menu-words { min-width: 0; overflow-wrap: normal; word-break: keep-all; }
.app-menu .menu-row:hover, .app-menu a[data-level="sub"]:hover, .app-menu a[data-level="beyond"]:hover { background: var(--nav-hover-bg); }
.app-menu a:hover, .app-menu a:focus-visible, .app-menu .menu-toggle:hover, .app-menu .menu-toggle:focus-visible { color: var(--nav-hover-ink); }
.app-menu a:hover .menu-icon, .app-menu a:focus-visible .menu-icon { color: var(--nav-hover-ink); }
.app-menu :focus-visible { outline-color: var(--nav-mark); outline-offset: -2px; }

/* The chevron is its own button, so Enter on the label navigates and Enter here opens the group. */
.app-menu .menu-toggle { flex: none; width: 36px; min-height: 38px; padding: 0; background: transparent; border: 0;
  color: var(--nav-icon); border-radius: var(--radius-control); }
.app-menu .menu-toggle svg { transition: transform 150ms ease-out; }
@media (prefers-reduced-motion: reduce) { .app-menu .menu-toggle svg { transition: none; } }
.app-menu li.is-open > .menu-row > .menu-toggle svg { transform: rotate(90deg); }

/* Only the open groups' items show. Every <a> stays in the HTML: tests/parity/lib/menu.py reads it.
   The sub-list hangs from a thin guide line under its group's icon. */
.app-menu .menu-sub { display: none; margin: var(--space-1) 0 var(--space-2) var(--space-5); padding-left: var(--space-2);
  border-left: 1px solid rgb(255 255 255 / .12); }
.app-menu li.is-open > .menu-sub { display: block; }
.app-menu a[data-level="sub"], .app-menu a[data-level="beyond"] { min-height: 32px; padding: 0 var(--space-3); font-size: var(--text-s); color: var(--nav-sub-ink); }
/* My Site Settings' eighteen items under four small headings (row 7.10). Not links: the menu's contract is its <a>s. */
.app-menu .menu-heading { margin: var(--space-3) 0 var(--space-1); padding: 0 var(--space-3); font-size: var(--text-xs); font-weight: var(--weight-strong);
  letter-spacing: .06em; text-transform: uppercase; color: var(--nav-heading-ink); }
.app-menu .menu-heading:first-child { margin-top: var(--space-1); }

/* The group a screen is in: its label bright; the item itself: a soft highlight and a mark. */
.app-menu li.is-current > .menu-row, .app-menu a[data-level="top"][aria-current="page"] { background: var(--nav-current-bg); }
.app-menu li.is-here > .menu-row > a[data-level="top"], .app-menu li.is-current > .menu-row > a[data-level="top"] { color: var(--nav-current-ink); font-weight: var(--weight-strong); }
.app-menu li.is-here > .menu-row > a[data-level="top"] .menu-icon, .app-menu li.is-current > .menu-row > a[data-level="top"] .menu-icon { color: var(--nav-mark); }
.app-menu a[aria-current="page"] { color: var(--nav-current-ink); font-weight: var(--weight-strong); }
.app-menu a[aria-current="page"] .menu-icon { color: var(--nav-mark); }
.app-menu .menu-sub a[aria-current="page"] { background: var(--nav-current-bg); box-shadow: inset 3px 0 0 var(--nav-mark); }

/* From 1024 px the sidebar shows the five groups alone (row 7.10): the current group's screens are the
   tabs over the screen (.screen-tabs), and each group's list opens as a flyout on hover or focus, so
   every screen stays one press from anywhere and no visible tab shares a name with a visible link. */
@media (min-width: 1024px) {
  /* Above the screen, so a flyout opens over the page's cards, never under them. */
  .shell-operator .app-menu { overflow: visible; z-index: 30; }
  .shell-operator .app-menu > .menu-top > li { position: relative; }
  .shell-operator .app-menu .menu-toggle { display: none; }
  .shell-operator .app-menu a[data-level="top"] { padding-right: var(--space-3); }
  .shell-operator .app-menu li.is-here > .menu-row { background: var(--nav-current-bg); box-shadow: inset 3px 0 0 var(--nav-mark); }
  .shell-operator .app-menu .menu-sub { display: block; position: absolute; left: calc(100% + var(--space-2)); top: calc(-1 * var(--space-2)); z-index: 30;
    width: 240px; margin: 0; padding: var(--space-2); border: 1px solid rgb(255 255 255 / .08); border-radius: var(--radius);
    background: var(--nav-open-bg); box-shadow: var(--shadow-raised); visibility: hidden; opacity: 0; transition: opacity 100ms linear, visibility 0s 100ms; }
  .shell-operator .app-menu .menu-sub::before { content: ""; position: absolute; right: 100%; top: 0; bottom: 0; width: var(--space-3); }
  @media (prefers-reduced-motion: reduce) { .shell-operator .app-menu .menu-sub { transition: none; } }
  .shell-operator .app-menu > .menu-top > li:hover > .menu-sub,
  .shell-operator .app-menu > .menu-top > li:focus-within > .menu-sub { visibility: visible; opacity: 1; transition: opacity 100ms linear; }
  /* My Site Settings' flyout is long: two columns of sets. */
  .shell-operator .app-menu #menu-group-my-site-settings { width: 460px; columns: 2; column-gap: var(--space-2); }
  .shell-operator .app-menu #menu-group-my-site-settings > li { break-inside: avoid; }
  .shell-operator .app-menu #menu-group-my-site-settings > .menu-heading { break-before: auto; }
}

/* The current group's screens, as tabs over the screen (row 7.10). */
.screen-tabs { margin: 0 0 var(--space-5); }
.screen-tabs ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; }
.screen-tabs a { display: inline-flex; align-items: center; text-decoration: none; white-space: nowrap; font-weight: var(--weight-label); font-size: var(--text-s); }
.screen-tabs-group { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2); color: var(--muted);
  font-size: var(--text-xs); font-weight: var(--weight-strong); letter-spacing: .06em; text-transform: uppercase; }
.screen-tabs-group .menu-icon { width: 16px; height: 16px; color: var(--brand); }
.screen-sets { gap: 2px; padding: 3px; margin: 0 0 var(--space-3); width: fit-content; max-width: 100%; /* token-exempt: a segmented control's hairline inset */
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-control); box-shadow: var(--shadow); }
.screen-sets a { min-height: 34px; padding: 0 var(--space-3); border-radius: var(--radius-control); color: var(--muted); }
.screen-sets a:hover { color: var(--ink); background: var(--bg); }
.screen-sets a[aria-current="page"] { background: var(--brand); color: var(--brand-ink); }
.screen-tab-list { gap: 0 var(--space-1); border-bottom: 1px solid var(--line); }
.screen-tab-list a { min-height: 44px; padding: 0 var(--space-3); margin-bottom: -1px; /* token-exempt: the tab's underline sits on the row's rule */
  color: var(--muted); border-bottom: 2px solid transparent; }
.screen-tab-list a:hover { color: var(--ink); border-bottom-color: var(--line-strong); }
.screen-tab-list a[aria-current="page"] { color: var(--brand); border-bottom-color: var(--brand); font-weight: var(--weight-strong); }
/* On a phone and a tablet the rows scroll sideways rather than wrap. */
@media (max-width: 1023px) {
  .screen-tabs ul { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .screen-tabs ul::-webkit-scrollbar { display: none; }
  .screen-tabs li { flex: none; }
}
@media print { .screen-tabs { display: none; } }

/* At a larger text size (the app's sheet) Switch back goes onto a second row before the words shrink below 8em. */
.viewing-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); min-height: var(--bar-h);
  padding: 0 var(--space-3); background: var(--viewing-bg); color: var(--viewing-ink); font-size: var(--text-s); }
.viewing-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.viewing-words { flex: 1 1 0; min-width: min(8em, 60vw); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewing-bar form { margin-left: auto; }
.viewing-bar button { background: var(--viewing-ink); color: #fff; } /* dark-ok: the viewing bar is one colour in both modes */

/* 768–1023 px: a rail of icons, each group a flyout. */
@media (min-width: 768px) and (max-width: 1023px) {
  .frame { grid-template-columns: 60px minmax(0, 1fr); }
  main { padding: var(--space-5) var(--space-4); }
  .app-menu { overflow: visible; padding: var(--space-3) var(--space-2); z-index: 30; }
  .app-menu > .menu-top > li { position: relative; }
  .app-menu .menu-words { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .app-menu a[data-level="top"] { justify-content: center; padding: 0; min-height: 44px; }
  .app-menu .menu-toggle { display: none; }
  .app-menu .menu-sub { display: block; position: absolute; left: calc(100% + var(--space-2)); top: 0; z-index: 30; width: 220px; margin: 0;
    padding: var(--space-2); border: 1px solid rgb(255 255 255 / .08); border-radius: var(--radius); background: var(--nav-open-bg);
    box-shadow: var(--shadow-raised); visibility: hidden; opacity: 0; transition: opacity 100ms linear; }
  @media (prefers-reduced-motion: reduce) { .app-menu .menu-sub { transition: none; } }
  .app-menu > .menu-top > li:hover > .menu-sub,
  .app-menu > .menu-top > li:focus-within > .menu-sub { visibility: visible; opacity: 1; }
}

/* Below 768 px: no sidebar. The Menu button opens it as a sheet, and the screen starts under the bar. */
@media (max-width: 767px) {
  :root { --bar-h: 52px; }
  .frame { grid-template-columns: minmax(0, 1fr); }
  .menu-button { display: inline-flex; }
  main { padding: var(--space-4); }
  /* From nothing (flex-basis 0) the name grows into all its row leaves, so a long name never pushes Test Mode or
     the account menu onto a second row at the standard size: only words too large for one row do. */
  .shell-operator .topbar .store-name, .shell-staff .topbar .store-name { flex: 1 1 0; max-width: none; }
  .account-menu .account-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .topbar .report-problem { display: none; }
  .account-panel .report-problem-menu { display: inline-flex; }
  .topbar .help-link { display: none; }
  .account-panel .help-link-menu { display: inline-flex; }
  .help-panel { width: 100vw; border-left: 0; }
  .help-panel-body { padding: var(--space-4) var(--space-4) var(--space-6); }
  /* --menu-top is the bar's bottom edge, set by app-menu.js as the sheet opens: lower while a viewing bar is above it. */
  .app-menu { display: none; position: fixed; left: 0; right: 0; top: var(--menu-top, var(--bar-h)); z-index: 35; height: auto;
    max-height: calc(100dvh - var(--menu-top, var(--bar-h))); overflow-y: auto; box-shadow: var(--shadow-raised); }
  .app-menu.is-shown { display: block; animation: fmb-menu-in 180ms ease-out; }
  @media (prefers-reduced-motion: reduce) { .app-menu.is-shown { animation: none; } }
  .app-menu a[data-level="top"], .app-menu .menu-toggle { min-height: var(--control-h); }
  .app-menu a[data-level="sub"], .app-menu a[data-level="beyond"] { min-height: var(--control-h); }
}
@keyframes fmb-menu-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* ---- Search settings (row 7.11, card #160) ------------------------------
   One box: in the bar from 768 px, at the top of the menu sheet below it (while
   the sheet is open), and in <main> on /admin/search-settings. Its list is a
   card on the screen's own surface, so it follows light and dark; the box in
   the bar is on the bar, which is dark in both modes. Every target is 48 px. */
.settings-search { position: relative; }
.settings-search input[type=search] { min-height: 48px; padding-left: var(--space-6); }
.settings-search-icon { position: absolute; left: var(--space-3); top: 15px; pointer-events: none; color: var(--muted); } /* token-exempt: centres the 18 px icon in the 48 px box */
.settings-search-page { max-width: 36rem; margin-bottom: var(--space-4); }
.shell-operator .topbar:has(> .settings-search) .store-name { margin-right: 0; }
/* From its smallest (9rem), so it never sends the bar onto a second row that shrinking would have spared. */
.settings-search-bar { flex: 1 1 9rem; max-width: 26rem; min-width: 9rem; margin-right: auto; }
.settings-search-bar input[type=search] { background: rgb(255 255 255 / .08); border-color: rgb(255 255 255 / .2); color: var(--nav-ink); box-shadow: none; } /* dark-ok: the bar is dark in both modes */
.settings-search-bar input[type=search]:hover { border-color: rgb(255 255 255 / .4); } /* dark-ok: the bar is dark in both modes */
.settings-search-bar input[type=search]::placeholder { color: var(--nav-sub-ink); opacity: 1; }
.settings-search-bar input[type=search]:focus-visible { outline-color: var(--nav-mark); }
.settings-search-bar .settings-search-icon { color: var(--nav-icon); }
.settings-search-results { position: absolute; top: calc(100% + var(--space-1)); left: 0; z-index: 60; width: min(30rem, calc(100vw - var(--space-6)));
  max-height: min(70vh, 34rem); overflow-y: auto; overscroll-behavior: contain; padding: var(--space-2); font-size: var(--text-m);
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-raised); }
.settings-search-results ul, .settings-search-list { list-style: none; margin: 0; padding: 0; }
.settings-search-results ul a, .settings-search-list a { display: flex; flex-direction: column; justify-content: center; min-height: 48px;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-control); color: var(--ink); text-decoration: none; }
.settings-search-results ul a:hover, .settings-search-results ul a.is-active, .settings-search-list a:hover { background: var(--accent); }
.settings-search-name { font-weight: var(--weight-label); }
.settings-search-line { font-size: var(--text-xs); color: var(--muted); }
.settings-search-count { margin: 0; padding: var(--space-1) var(--space-3) var(--space-2); font-size: var(--text-xs); color: var(--muted); }
.settings-search-none { margin: 0; padding: var(--space-2) var(--space-3); }
.settings-search-all, .settings-search-menu { display: flex; align-items: center; min-height: 48px; padding: 0 var(--space-3); font-weight: var(--weight-label); }
/* The list hangs from the bar but sits on the screen's surface, so the bar's own link colours and focus ring stay on the bar. */
.shell-operator .topbar .settings-search-results ul a, .shell-operator .topbar .settings-search-results ul a:hover,
.shell-operator .topbar .settings-search-results ul a:focus-visible { color: var(--ink); }
.shell-operator .topbar .settings-search-results .settings-search-all, .shell-operator .topbar .settings-search-results .settings-search-menu,
.shell-operator .topbar .settings-search-results .settings-search-all:hover, .shell-operator .topbar .settings-search-results .settings-search-menu:hover { color: var(--brand); }
.shell-operator .topbar .settings-search-results :focus-visible { outline-color: var(--brand); outline-offset: -3px; }
.settings-search-list { max-width: 40rem; }
.settings-search-list li + li { border-top: 1px solid var(--line); }
.settings-search-note { margin: var(--space-2) 0; }
/* The setting a result opened: an outline and a wash that fades, for a moment (settings-search.js takes it off). */
:target, .settings-search-found { scroll-margin-top: calc(var(--bar-seen, var(--bar-h)) + var(--space-5)); }
.settings-search-found { outline: 3px solid var(--brand); outline-offset: 4px; border-radius: var(--radius-control); }
@media (prefers-reduced-motion: no-preference) { .settings-search-found { animation: fmb-found 2.4s ease-out; } }
@keyframes fmb-found { from, 35% { background-color: var(--accent); } to { background-color: transparent; } }
/* 768–1023 px: Visit site, Help, Report a problem and the account menu keep their icons and their names (as on a phone), and give
   the box their words' room; the store's name keeps its own, up to 30% of the width, rather than be squeezed under the box. */
@media (min-width: 768px) and (max-width: 1023px) {
  .shell-operator .topbar:has(> .settings-search) .visit-site-words,
  .shell-operator .topbar:has(> .settings-search) .report-problem-words,
  .shell-operator .topbar:has(> .settings-search) .help-link-words,
  .shell-operator .topbar:has(> .settings-search) .account-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .shell-operator .topbar:has(> .settings-search) .store-name { flex: 0 0 auto; max-width: 30vw; }
}
/* Below 768 px the box is a strip that hangs from the bar's bottom edge while the sheet is open: placed in the bar
   (which is sticky), never over it, so the bar's Menu button, store name and account menu stay seen and tappable
   wherever the bar is, a viewing bar above it or not (row 7.11 review). The sheet starts under the strip. */
@media (max-width: 767px) {
  .settings-search-bar { display: none; }
  body.menu-open .settings-search-bar { display: block; position: absolute; top: calc(100% + 1px); left: 0; right: 0; z-index: 36; max-width: none; margin: 0;
    padding: var(--space-3) var(--space-4); background: var(--nav-bg); border-bottom: 1px solid rgb(255 255 255 / .08); } /* dark-ok: the sheet is the bar's colour */
  /* --menu-strip is the strip's own height, measured by app-menu.js as the sheet opens: 72 px at the standard text size, more at a larger one. */
  body.menu-open:has(.settings-search-bar) .app-menu { top: calc(var(--menu-top, var(--bar-h)) + var(--menu-strip, 72px));
    max-height: calc(100dvh - var(--menu-top, var(--bar-h)) - var(--menu-strip, 72px)); }
  .settings-search-bar .settings-search-icon { left: var(--space-5); top: 27px; } /* token-exempt: the box sits 12 px down the sheet's strip */
  .settings-search-bar .settings-search-results { left: var(--space-4); right: var(--space-4); width: auto; max-height: calc(100dvh - var(--menu-top, var(--bar-h)) - 96px); }
}
@media print { .settings-search { display: none; } }

/* ---- title row --------------------------------------------------------- */

/* h1 and the screen's one primary action on a line, as WordPress's "Products [Add new product]". */
.page-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); margin-bottom: var(--space-4); }
.page-head > :last-child:not(h1):not(:first-child) { margin-left: auto; }
.page-head h1 { margin: 0; }
.section-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }

/* ---- cards and settings rows ------------------------------------------- */

.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-4); min-width: 0; box-shadow: var(--shadow); }
/* A card's own heading is a label for the card, not a second page title. */
.card > h2, .card > header > h2, .card > .section-head > h2, .card > legend h2 { font-size: var(--text-m); margin-bottom: var(--space-3); }
.card > :last-child { margin-bottom: 0; }
.card.narrow { max-width: 440px; margin: var(--space-5) auto; }
.card-inset { border: 1px solid var(--line); border-radius: var(--radius-control); padding: var(--space-3) var(--space-4); background: var(--bg); }
/* An informational card: Shop Organization's note, and a screen not built yet. */
.notice-card { background: var(--info-bg); color: var(--info-ink); border-color: var(--info-ink); }

/* A settings field: label beside the field from 900px, as WordPress's form-table.
   The hint goes UNDER the field, never on a negative margin. */
/* minmax(0, 1fr): a rich editor's toolbar or a long shortcode never makes the row wider than a phone (card #167). */
.settings-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-1); margin: 0 0 var(--space-3); }
.settings-row > label, .settings-row > .settings-label { margin: 0; font-weight: var(--weight-label); font-size: var(--text-s); }
.settings-row .hint { margin-top: var(--space-1); }
@media (min-width: 900px) {
  .settings-row { grid-template-columns: 200px minmax(0, 640px); gap: var(--space-1) var(--space-5); align-items: start; padding: var(--space-3) 0; margin: 0; border-top: 1px solid var(--line); }
  .settings-row:first-of-type { border-top: 0; }
  .settings-row > label, .settings-row > .settings-label { grid-column: 1; padding-top: var(--space-3); color: var(--ink); }
  .settings-row > :not(label):not(.settings-label) { grid-column: 2; }
}

/* ---- forms ------------------------------------------------------------- */

label { font-weight: var(--weight-label); margin-top: var(--space-2); font-size: var(--text-s); }
input[type=text], input[type=email], input[type=password], input[type=search], input[type=tel], input[type=url], input[type=date],
input[type=time], input[type=datetime-local], input[type=number], select, textarea {
  font: inherit; font-size: var(--text-m); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-strong);
  border-radius: var(--radius-control); background: var(--field); color: var(--ink); width: 100%; max-width: 100%; min-height: var(--control-h);
  box-shadow: inset 0 1px 1px rgb(16 24 40 / .04); transition: border-color 120ms, box-shadow 120ms;
}
input[type=text]:hover, input[type=email]:hover, input[type=password]:hover, input[type=search]:hover, input[type=tel]:hover, input[type=url]:hover,
input[type=number]:hover, input[type=date]:hover, input[type=time]:hover, input[type=datetime-local]:hover, select:hover, textarea:hover { border-color: var(--muted); }
input[type=checkbox], input[type=radio] { accent-color: var(--brand); }
textarea { min-height: calc(var(--control-h) * 2); }
/* Card #192: Safari draws today's date and the time, in grey, inside an empty date or time box. empty-dates.js marks such a
   box (data-empty, Apple's engine only) until she types in it; its stand-in is hidden meanwhile, so an empty box looks empty.
   On the box, not its parts: WebKit greys an empty part from the box's own colour after the stylesheet, so a part's colour
   hides only a part that holds a value (the review of #192, in WebKit). */
input[data-empty]:not(:focus) { color: transparent; }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible, summary:focus-visible {
  outline: 3px solid var(--brand); outline-offset: 2px;
}
.stack { display: flex; flex-direction: column; gap: var(--space-2); max-width: 440px; }
.stack-wide { display: flex; flex-direction: column; gap: var(--space-2); }
.stack button { align-self: flex-start; margin-top: var(--space-2); }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.two > div { display: flex; flex-direction: column; gap: var(--space-2); }
.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-2) var(--space-3); align-items: end; }
.field-row > div { display: flex; flex-direction: column; gap: var(--space-1); }
fieldset { border: 1px solid var(--line); border-radius: var(--radius); margin: 0 0 var(--space-3); padding: var(--space-2) var(--space-4) var(--space-3); min-width: 0; }
legend { font-weight: var(--weight-label); padding: 0 var(--space-1); }
.choices { border: 0; padding: 0; margin: 0 0 var(--space-2); display: flex; flex-direction: column; gap: var(--space-1); }
.choices legend { font-weight: var(--weight-label); margin-bottom: var(--space-1); }

/* One tick and its words: a real 44px target, because it is tapped at a pickup. */
label.check { font-weight: 400; display: flex; align-items: center; gap: var(--space-2); margin: 0; min-height: var(--control-h); }
label.check input { width: 20px; height: 20px; flex: none; }
/* Its words wrap, an email address anywhere, rather than run off a phone at a larger text size (card #167). */
label.check { overflow-wrap: anywhere; }
label.check > :not(input) { min-width: 0; }
/* In a table a tick's words keep whole, so the table sizes its columns as before (a wide table scrolls in its own box). */
td label.check { overflow-wrap: normal; }

/* The browser's file control, hidden, with its own label as a quiet button. */
.file-input { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.file-input input[type=file] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
input[type=file] { max-width: 100%; }
.file-input > label { display: inline-flex; align-items: center; justify-content: center; margin: 0; cursor: pointer;
  min-height: var(--control-h); padding: 0 var(--space-4); border: 1px solid var(--line-strong); border-radius: var(--radius-control);
  background: var(--surface); color: var(--ink); font-weight: var(--weight-label); box-shadow: var(--shadow); }
.file-input > label:hover { background: var(--bg); }
.file-input input[type=file]:focus-visible + label { outline: 3px solid var(--brand); outline-offset: 2px; }
.file-input .file-name { color: var(--muted); font-size: var(--text-s); }

/* ---- buttons ----------------------------------------------------------- */

/* Primary: one per form or title row. Secondary: an outline. Tertiary: underlined text. */
button, .button { font: inherit; font-size: var(--text-m); font-weight: var(--weight-strong); padding: 0 var(--space-4);
  min-height: var(--control-h); border-radius: var(--radius-control); border: 0; background: var(--brand); color: var(--brand-ink);
  cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  box-shadow: var(--shadow); transition: filter 120ms, background-color 120ms, border-color 120ms; white-space: nowrap; }
/* On an Operator or staff screen, which the app's sheet shows at her larger text size (card #167), a button is never
   wider than its row, and its words wrap whenever one line is wider than the button's room, rather than run off a
   phone's edge. A table's row of buttons keeps one line above 640 px. Only there: fmb.css styles the shop too, and
   at a 360 px phone's standard size every meal card's "Add to cart" broke onto two lines in its 130 px column, which
   its one line had fit (card #164's review), so a public page's button keeps its words on one line, as before.
   :where(), so each keeps the specificity of the rule above. */
:where(.shell-operator, .shell-staff) button, :where(.shell-operator, .shell-staff) .button { white-space: normal; text-align: center; max-width: 100%; }
@media (min-width: 641px) { table button, table .button { white-space: nowrap; } }
button:hover, .button:hover { filter: brightness(1.08); }
/* Secondary: white with a grey edge, as every modern admin's; the brand colour is kept for the one primary. */
.button-quiet { border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); font-weight: var(--weight-label); }
.button-quiet:hover { filter: none; background: var(--bg); border-color: var(--muted); }
.button-secondary { background: var(--accent); color: var(--brand); border: 1px solid var(--line); font-weight: var(--weight-label); box-shadow: none; }
.button-link { background: none; border: 0; padding: 0; min-height: 0; font-weight: 400; text-decoration: underline; color: var(--brand); box-shadow: none; }
.button-link:hover { filter: none; text-decoration-thickness: 2px; }
.button-danger { background: var(--error-ink); color: var(--surface); }
.button-small, button.button-small, .button-quiet.button-small { box-shadow: none; }
.button-small, button.button-small { min-height: var(--control-h); padding: 0 var(--space-3); font-size: var(--text-s); }
button[aria-busy="true"] { opacity: .7; }
/* A press that started something slow (public/assets/js/working.js, card #158): a 16 px spinner before the words. */
button[aria-busy="true"]::before { content: ""; width: 16px; height: 16px; flex: none; border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: fmb-spin .8s linear infinite; }
@keyframes fmb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { button[aria-busy="true"]::before { animation: none; border-right-color: currentColor; } }
button:disabled, .button[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

/* A row's Call, Email and Text (card #103, fmb_contact_buttons_html()): three square icon buttons in one
   row, as the original site's Orders and Customers lists draw them. Each is a 44px target around a 36px
   face, so the faces sit 8px apart and three fit in 132px; a paused one is a dashed, muted square with
   the word "paused", and may take the row to a second line. */
.contact-buttons { display: inline-flex; flex-wrap: wrap; align-items: center; vertical-align: middle; min-width: calc(var(--control-h) * 3); }
.contact-button { display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-h); min-height: var(--control-h);
  padding: var(--space-1); color: var(--brand); text-decoration: none; }
.contact-face { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); min-width: var(--control-h-s);
  min-height: var(--control-h-s); padding: 0 var(--space-2); border: 1px solid var(--brand); border-radius: var(--radius-control);
  background: var(--field); font-size: var(--text-xs); white-space: nowrap; }
.contact-icon { flex: none; }
a.contact-button:hover .contact-face { background: var(--accent); border-color: var(--brand); }
a.contact-button:focus-visible { outline: none; }
a.contact-button:focus-visible .contact-face { outline: 3px solid var(--brand); outline-offset: 2px; }
.contact-button.is-off { color: var(--muted); cursor: default; }
.contact-button.is-off .contact-face { border-style: dashed; border-color: var(--muted); background: transparent; }
form.inline, .inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0; min-width: 0; max-width: 100%; }
form.inline { display: inline-flex; }
.inline-form label { margin: 0; }
.inline-form select, .inline-form input { width: auto; max-width: 100%; }
.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin: var(--space-2) 0 0; }
.row-actions { white-space: nowrap; }
.row-actions > * { margin-right: var(--space-3); }
.row-actions .button-link { min-height: var(--control-h-s); }

/* ---- status tabs, filters, bulk bar ------------------------------------ */

/* Status tabs (row 7.10): a row of tabs on a rule, the current one underlined in the brand colour.
   A view switch (Orders' All orders / Process / By Location) is a segmented control.
   A sideways scroller of pills on a phone, never four wrapped lines. */
.status-tabs, .coupons-views { display: flex; flex-wrap: wrap; align-items: stretch; gap: 0 var(--space-1); margin: 0 0 var(--space-4);
  font-size: var(--text-s); border-bottom: 1px solid var(--line); }
.status-tabs a, .coupons-views a { display: inline-flex; align-items: center; min-height: 40px; padding: 0 var(--space-3);
  color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; font-weight: var(--weight-label); white-space: nowrap; }
.status-tabs a, .coupons-views a { margin-bottom: -1px; } /* token-exempt: the tab's underline sits on the row's rule */
.status-tabs a:hover, .coupons-views a:hover { color: var(--ink); border-bottom-color: var(--line-strong); }
.order-views { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px; padding: 3px; margin: 0; /* token-exempt: a segmented control's hairline inset */
  font-size: var(--text-s); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-control); }
.order-views a { display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-control);
  color: var(--muted); text-decoration: none; font-weight: var(--weight-label); }
.order-views a:hover { color: var(--ink); }
.order-views a[aria-current="page"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }
.status-tabs a[aria-current="page"], .coupons-views a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--brand); font-weight: var(--weight-strong); }
.pages a[aria-current="page"] { font-weight: var(--weight-strong); color: var(--ink); text-decoration: none; }
.status-tabs .count, .order-views .count { color: var(--muted); }

/* A filter bar is always open on a desktop: its summary only appears on a phone,
   where the bar folds away so the table is the first thing on the screen. The
   markup carries `open`, because CSS cannot open a closed <details>. */
.filters-box { border: 0; padding: 0; margin: 0 0 var(--space-4); }
.filters-box > summary { display: none; }
@media (max-width: 767px) {
  .filters-box > summary { display: flex; align-items: center; gap: var(--space-2); cursor: pointer;
    min-height: var(--control-h); padding: 0 var(--space-3); border: 1px solid var(--line);
    border-radius: var(--radius-control); background: var(--surface); font-weight: var(--weight-label); }
  .filters-box[open] > summary { margin-bottom: var(--space-2); }
  .filters-box > summary .count { color: var(--muted); font-weight: 400; }

  /* Ten status links wrapped to four lines is what this replaces: one row that scrolls sideways. */
  .status-tabs, .order-views, .coupons-views { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity;
    gap: var(--space-2); padding-bottom: var(--space-1); -webkit-overflow-scrolling: touch; }
  .status-tabs > *, .order-views > *, .coupons-views > * { flex: none; scroll-snap-align: start; }
  .order-views { display: flex; width: 100%; background: transparent; border: 0; padding: 0; margin-bottom: var(--space-2); }
  .order-views a[aria-current="page"] { box-shadow: none; }
  .status-tabs, .coupons-views { border-bottom: 0; }
  .status-tabs a, .order-views a, .coupons-views a { display: inline-flex; align-items: center; min-height: var(--control-h-s); margin: 0;
    padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface); text-decoration: none; }
  .status-tabs a[aria-current="page"], .order-views a[aria-current="page"], .coupons-views a[aria-current="page"] { background: var(--accent); border-color: var(--brand); }
}

/* Every field fills its cell: no fixed widths, so nothing pushes the page sideways. */
.filters, .order-filters, .coupons-filters, .report-filter, .tc-filter-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--space-3);
  margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); align-items: end;
}
.filters > div, .order-filters > div, .coupons-filters > div, .report-filter > p, .tc-filter-grid > div,
.filter-field, .export-field { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; margin: 0; }
.filters label, .order-filters label, .coupons-filters label, .report-filter label, .tc-filter-grid label,
.filter-field label, .export-field label { margin: 0; font-size: var(--text-s); }
.filters input, .filters select, .order-filters input, .order-filters select, .coupons-filters input, .coupons-filters select,
.report-filter select, .tc-filter-grid input, .tc-filter-grid select { width: 100%; min-width: 0; }
/* The Filter button takes the next cell, not a row of its own: a whole row for one button was most of the filter bar. */
.filter-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: end; justify-content: flex-start; }

/* Bulk actions on the left, the count and pager on the right, wrapping as one unit. */
.bulk, .bulk-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-3); }
.bulk label, .bulk-bar label { margin: 0; }
.bulk select, .bulk-bar select { width: auto; }
.bulk-end { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.pages, .cust-pages { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); align-items: center; }
.pages span[aria-current], .cust-pages span[aria-current] { font-weight: var(--weight-strong); }
.filtered-total { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-3); margin: var(--space-3) 0; }
.filtered-total strong { font-size: var(--text-l); }

/* ---- table ------------------------------------------------------------- */

/* position: relative, so a box hidden for screen readers in a cell (a row's tick's label) scrolls with the table
   inside it rather than escape it and make the whole page scroll sideways (card #167). */
.table-wrap, .coupons-table, .cust-table-wrap, .table-scroll {
  position: relative; overflow-x: auto; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); margin: 0 0 var(--space-5);
  box-shadow: var(--shadow);
}
table.list, .coupons-table table, table.cust-list { border-collapse: collapse; width: 100%; font-size: var(--text-s); }
table.list th, table.list td, .coupons-table th, .coupons-table td, table.cust-list th, table.cust-list td {
  text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line); vertical-align: middle;
}
/* Row 7.10: a quiet heading row, small capitals on the page colour, as a modern admin's table. */
table.list thead th, .coupons-table thead th, table.cust-list thead th { background: var(--bg); color: var(--muted); font-weight: var(--weight-strong);
  font-size: var(--text-xs); letter-spacing: .03em; text-transform: uppercase; white-space: nowrap; padding-block: var(--space-3); }
table.list thead th a, .coupons-table thead th a, table.cust-list thead th a { color: var(--muted); text-decoration: none; }
table.list thead th a:hover { color: var(--ink); text-decoration: underline; }
table.list thead th[aria-sort="ascending"] a::after { content: " ↑"; }
table.list thead th[aria-sort="descending"] a::after { content: " ↓"; }
/* A date, a sum or a status reads on one line; on a desktop the table scrolls sideways before it wraps them. */
@media (min-width: 641px) {
  table.list td[data-label="Total"], table.list td[data-label="Status"], table.list td[data-label="Items"],
  table.list td[data-label="Price"], table.list td[data-label="Order #"], table.list td.num { white-space: nowrap; }
}
table.list tr:last-child td, .coupons-table tr:last-child td, table.cust-list tr:last-child td, table.cust-list tr:last-child th { border-bottom: 0; }
table.list tbody tr, .coupons-table tbody tr { transition: background-color 80ms; }
table.list tbody tr:hover, .coupons-table tbody tr:hover { background: var(--accent); }
table.list .row-title, .coupons-table .row-title, .cust-name { font-weight: var(--weight-label); }
table.list .row-title a, .coupons-table .row-title a, a.row-title { text-decoration: none; font-weight: var(--weight-strong); }
table.list .row-title a:hover, .coupons-table .row-title a:hover { text-decoration: underline; }
table.list td.name, table.list .row-title { min-width: 12rem; }
table.list input[type=checkbox], .coupons-table input[type=checkbox] { width: 20px; height: 20px; }
table.list td.thumb { width: 56px; }
table.list td.thumb img { object-fit: cover; border-radius: var(--radius-control); background: var(--accent); }
table.list td.num, table.list th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.list select { width: auto; max-width: 16rem; }
tr.retired td, tr.is-paused td { color: var(--muted); }
.empty, .coupons-empty { color: var(--muted); padding: var(--space-3) 0; }

/* Below 640px a row is a card, and each value carries its own heading. */
@media (max-width: 640px) {
  table.list thead { position: absolute; left: -9999px; }
  /* Two values a line, each with its heading above it, so a row is half as tall as a list of lines. */
  table.list tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--line); padding: var(--space-3); }
  table.list tbody tr:hover { background: transparent; }
  table.list td { display: block; border: 0; padding: 0; min-width: 0; overflow-wrap: anywhere; }
  /* A first cell with no heading is the card's first full-width line: its words (a name, a link, a button, a phone number)
     are real content and must not be covered. Only a tick box (td.pick) is pinned to the card's top-right corner, where
     it takes no room, so the fix is one rule for every list rather than one per screen (row 3.4). */
  table.list tr { position: relative; }
  table.list td:not([data-label]):first-child { grid-column: 1 / -1; }
  table.list td.pick:first-child { position: absolute; right: var(--space-3); top: var(--space-3); grid-column: auto; }
  table.list td[data-label="Customer"], table.list td[data-label="Name"], table.list td[data-label="Contact"],
  table.list td[data-label="Actions"], table.list td.name, table.list td.contact { grid-column: 1 / -1; }
  table.list td[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: var(--text-xs);
    font-weight: var(--weight-label); text-transform: uppercase; letter-spacing: .03em; }
  table.list td[data-label="Actions"]::before, table.list td[data-label="Contact"]::before { content: none; }
}

/* ---- status pill ------------------------------------------------------- */

.status, .pill, .cust-tag, .coupon-draft, .tag, .log-redirected {
  display: inline-block; padding: 2px var(--space-2); /* token-exempt: 2px 8px is the pill's own, from docs/OPERATOR-LOOK.md's Components table */
  border-radius: var(--radius-pill); font-size: var(--text-xs); line-height: 1.5;
  font-weight: var(--weight-label); background: var(--accent); color: var(--ink); white-space: nowrap;
}
/* A dot before an order's status, in the pill's own colour, so a column of them scans by shape too. */
.status[class*="order-status-"]::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; margin-right: 6px; vertical-align: middle; /* token-exempt: the dot's own gap */ }
.status-published, .status-went, .pill-paid, .order-status-completed { background: var(--ok-bg); color: var(--ok-ink); }
.status-offline, .status-held, .pill-unpaid, .order-status-ready, .coupon-draft, .log-redirected { background: var(--info-bg); color: var(--info-ink); }
.status-stopped, .status-paused, .status-trash, .cust-tag,
.order-status-refunded, .order-status-cancelled, .order-status-failed, .order-status-trash { background: var(--error-bg); color: var(--error-ink); }
.tag { color: var(--muted); margin-left: var(--space-2); }

/* ---- tiles ------------------------------------------------------------- */

.tiles, .cust-tiles { list-style: none; margin: 0 0 var(--space-4); padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-3); }
.tile, .cust-tile { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-4); border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface); color: var(--ink); text-decoration: none; position: relative; box-shadow: var(--shadow);
  transition: border-color 120ms, transform 120ms, box-shadow 120ms; }
.tile:hover, .tile:focus-visible, .cust-tile:hover, .cust-tile:focus-visible { border-color: var(--brand); box-shadow: var(--shadow-raised); }
@media (prefers-reduced-motion: no-preference) { .tile:hover { transform: translateY(-1px); } }
.tile-count, .cust-tile-value { font-size: var(--text-xl); font-weight: 700; line-height: 1.1; color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.tile-count.is-long { font-size: var(--text-l); }
.tile-label, .cust-tile-label { font-weight: var(--weight-label); color: var(--muted); font-size: var(--text-s); }
.cust-tile-label, .cust-tile-meta { color: var(--muted); font-size: var(--text-s); }
/* The whole tile is the link, so it needs no separate "View": an arrow says so. */
.tile::after { content: "→"; position: absolute; top: var(--space-3); right: var(--space-4); color: var(--muted); }
.tile:hover::after { color: var(--brand); }

/* ---- notices and flashes ---------------------------------------------- */

.flash, .notice, .banner { padding: var(--space-3) var(--space-4); border-radius: var(--radius-control); margin: 0 0 var(--space-4); overflow-wrap: anywhere;
  border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-left: 4px solid currentColor; }
.flash { display: flex; align-items: flex-start; gap: var(--space-3); }
/* A flash that is one paragraph reads as one: "Warning:" and its sentence on the same lines, never two columns. */
p.flash { display: block; }
.flash-words { flex: 1; min-width: 0; }
.flash-close { background: none; border: 0; color: inherit; min-height: var(--control-h); min-width: var(--control-h); padding: 0; font-size: var(--text-l); }
.flash-ok, .notice-ok, .store-open.is-open { background: var(--ok-bg); color: var(--ok-ink); }
.flash-error, .notice-warning, .store-open.is-closed, .banner { background: var(--error-bg); color: var(--error-ink); }
.flash-info, .notice-info, .banner.info, .cust-notice { background: var(--info-bg); color: var(--info-ink); }
.notice p, .notice ul, .banner p { margin: var(--space-1) 0; }
.banner p:last-child { margin: 0; }
.banner a { color: inherit; font-weight: var(--weight-strong); }
.field-error { color: var(--error-ink); margin: 0; font-size: var(--text-s); }

/* ---- facts list -------------------------------------------------------- */

/* minmax(0, 1fr), not 1fr: a 1fr track will not shrink below its longest word, and a customer's email address is
   one, which ran one order's cards off a phone's right edge (card #166). The address breaks anywhere instead. A
   label takes the room it needs up to 55% of the list, so at a larger text size it wraps rather than push its
   answer off the screen (card #167). */
.facts { display: grid; grid-template-columns: fit-content(55%) minmax(0, 1fr); gap: var(--space-2) var(--space-4); }
.facts dt { font-weight: var(--weight-label); color: var(--muted); overflow-wrap: break-word; }
.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 760px) {
  .two, .field-row { grid-template-columns: 1fr; }
}
