:root {
  /* Brand teal (client-supplied swatch, #008e96) and two derived stops —
     a deep, near-black-teal for solid fills/high-contrast text, and a mid
     stop close to the raw brand colour for links, hovers and borders. */
  --green-900: #00474d;
  --green-700: #007a82;
  --green-100: #dcf0f1;
  --amber-500: #c08a3e;
  /* WCAG AA (October 2026): #9c6f2f was 3.97:1 as text on the pale amber
     panels (#fdf1de); #805a24 is 5.5:1, and 6.2:1 under white text. */
  --amber-600: #805a24;
  --red-500: #c0392b;
  --red-100: #fbe7e4;
  --blue-100: #e7f0fb;
  --blue-600: #2563eb;
  --violet-100: #f3e5f5;
  --violet-700: #6a1b9a;
  --cream: #f2f9f9;
  --ink: #142222;
  --muted: #5b6d6d;
  --line: #d7e6e6;
  --radius: 0;
  --shadow: none;
  /* Jamie, October 2026: "the option of a dark theme in branding. The white
     will be too bright for some people." The surfaces that were plain
     white or pale grey, and the brand colour where it is used as text, are
     named here so the dark block at the end of this file can swap them.
     On light pages every value is exactly what was hardcoded before. */
  --surface: white;
  --surface-2: #eee;
  --amber-100: #fdf1de;
  --green-ink: var(--green-900);

  /* Department colour palette — cycled through in order as departments are
     created (see lib/departments.js). Kept distinct from the semantic
     badge/status colours above so department colour-coding never gets
     confused with published/pending/approved states. */
  --dept-0-bg: #dcf0f1; --dept-0-fg: #00474d;
  --dept-1-bg: #fdf1de; --dept-1-fg: #9c6f2f;
  --dept-2-bg: #e6e9fb; --dept-2-fg: #3949ab;
  --dept-3-bg: #fbe7e4; --dept-3-fg: #c0392b;
  --dept-4-bg: #e0f2f1; --dept-4-fg: #00695c;
  --dept-5-bg: #f3e5f5; --dept-5-fg: #6a1b9a;
  --dept-6-bg: #fff3e0; --dept-6-fg: #b15600;
  --dept-7-bg: #eceff1; --dept-7-fg: #455a64;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* iPhone Safari enlarges long runs of text inside anything wider than the
   screen — the rota's "Open shifts" banner came out at nearly twice the
   size of everything else (Jamie, October 2026). Text is sized on purpose
   here, so it is left at the size it was given. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--cream);
  color: var(--ink);
  line-height: 1.5;
  padding-bottom: 2rem;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
a { color: var(--green-700); text-decoration: none; }
/* A link inside a sentence is underlined, so it's told apart by more than
   its colour (WCAG 1.4.1). Buttons, chips and nav links aren't sentences. */
p a:not([class]), li a:not([class]), td a:not([class]), .flash a:not([class]), .small a:not([class]), .muted a:not([class]),
label a:not([class]), .help a:not([class]) { text-decoration: underline; text-underline-offset: 2px; }
h1, h2, h3 { margin: 0 0 0.5rem; line-height: 1.25; letter-spacing: -0.01em; }
p { margin: 0 0 0.75rem; }
.muted { color: var(--muted); }
.small { font-size: 0.8rem; }
code { background: var(--surface-2); padding: 0.1rem 0.35rem; border-radius: 0; font-size: 0.85em; }

/* ---------- Top bar / nav (guest-facing pages only — the staff shell
   below uses the sidebar instead, but these classes stay in case any
   ported route still renders its own top nav) ---------- */
.topbar { background: var(--green-900); color: white; position: sticky; top: 0; z-index: 10; border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
.topbar-inner { display: flex; align-items: center; justify-content: space-between; padding: 0.85rem 1rem; gap: 1rem; }
.brand, .brand-title {
  color: white; font-weight: 700; font-size: 1.1rem; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 0.55rem;
}
a.brand { text-decoration: none; }
a.brand:hover .brand-suffix { opacity: 1; }
.brand-suffix { font-weight: 400; opacity: 0.75; }
/* Jamie, October 2026: a venue's own logo was too small to make out — twice
   the size it was (34px, and 64px on the login/welcome card), and shown
   whole at its own shape (contain, width auto) rather than cropped to a
   square, so a wide logo keeps its edges. */
.brand-logo { height: 68px; width: auto; max-width: 180px; border-radius: 0; object-fit: contain; flex-shrink: 0; }
.brand-title .brand-logo { height: 128px; width: auto; max-width: 320px; border-radius: 0; }
/* On a phone the guest top bar's name can wrap beside the bigger logo
   rather than pushing the page wider than the screen. */
@media (max-width: 480px) {
  .topbar .brand { white-space: normal; }
  .brand-logo { max-width: 140px; }
}
.auth-card .brand-title { flex-direction: column; text-align: center; width: 100%; }
.topbar-user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.85rem; }
.user-chip { white-space: nowrap; color: white; }
.user-chip:hover { text-decoration: underline; }
.user-chip em { font-style: normal; opacity: 0.75; display: block; font-size: 0.75rem; }
.link-btn { background: none; border: 1px solid rgba(255,255,255,0.35); color: white; padding: 0.35rem 0.7rem; border-radius: 0; cursor: pointer; font-size: 0.8rem; }
.link-btn:hover { background: rgba(255,255,255,0.1); }
.link-btn-plain { display: inline-flex; align-items: center; background: var(--green-100); border: 1px solid var(--green-100); color: var(--green-ink); padding: 0.35rem 0.7rem; border-radius: 0; cursor: pointer; font-size: 0.8rem; font-weight: 600; line-height: 1.2; text-decoration: none; margin-right: 0.4rem; margin-bottom: 0.3rem; }
.link-btn-plain:last-child { margin-right: 0; }
.link-btn-plain:hover { background: #c8e6e8; border-color: #c8e6e8; color: var(--green-ink); }
.link-btn-danger { background: var(--red-100); border-color: var(--red-100); color: var(--red-500); }
.link-btn-danger:hover { background: #f5d2cc; border-color: #f5d2cc; color: #8f261b; }
.inline-form { display: inline; }
.shift-time-form { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.15rem; }
.time-input-inline { border: 1px solid var(--border, #d7dbd8); border-radius: 0; padding: 0.15rem 0.3rem; font-size: 0.85rem; font-family: inherit; color: inherit; background: var(--surface); width: 6.4rem; }
.time-input-inline:focus { outline: 2px solid var(--green-500, #2f6f5e); outline-offset: 1px; }

.topnav { display: flex; overflow-x: auto; gap: 0.25rem; padding: 0 0.5rem 0.5rem; scrollbar-width: none; }
.topnav::-webkit-scrollbar { display: none; }
.nav-link { display: flex; align-items: center; gap: 0.4rem; color: rgba(255,255,255,0.8); padding: 0.45rem 0.85rem; border-radius: 0; font-size: 0.88rem; white-space: nowrap; flex-shrink: 0; }
.nav-link.active { background: var(--surface); color: var(--green-ink); font-weight: 600; }
.nav-link:hover:not(.active) { background: rgba(255,255,255,0.12); }
.nav-icon { font-size: 1rem; }

/* ---------- App shell: left sidebar (staff pages) ---------- */
body.has-sidebar { padding-bottom: 0; }
.app-shell { display: flex; align-items: flex-start; min-height: 100vh; }
.sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--green-900);
  color: white;
  display: flex;
  flex-direction: column;
  padding: 1rem 0.75rem;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Jamie: "I dont like this grey scrolling bar that seperates the menus …
     it also hides the last part of the '+walk in' button." The sidebar
     still scrolls (wheel, trackpad, touch, keyboard) but shows no bar, so
     nothing is covered. What says there's more is a soft shadow at the edge
     that has more beyond it — at the bottom until you reach the end, at the
     top once you've scrolled down. (The "local" layers move with the menu
     and cover the shadows when there's nothing more that way.) */
  scrollbar-width: none;
  background:
    linear-gradient(var(--green-900) 60%, rgba(0, 71, 77, 0)) top / 100% 3rem no-repeat local,
    linear-gradient(rgba(0, 71, 77, 0), var(--green-900) 40%) bottom / 100% 3rem no-repeat local,
    linear-gradient(rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0)) top / 100% 1.6rem no-repeat scroll,
    linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.65)) bottom / 100% 1.6rem no-repeat scroll,
    var(--green-900);
}
.sidebar::-webkit-scrollbar { display: none; }
.sidebar-brand { display: flex; align-items: center; gap: 0.6rem; color: white; font-weight: 700; font-size: 1.05rem; padding: 0.5rem 0.5rem 1.25rem; }
/* The logo above the pub's name in the narrow desktop sidebar, so a wide
   logo at full size doesn't squeeze the name into a sliver beside it. */
.sidebar-brand { flex-direction: column; align-items: flex-start; }
.sidebar-brand .brand-logo { max-width: 100%; }
/* "+ Add a party" and "+ Walk-in" side by side — both need to fit on one
   row even on a narrow sidebar, so each button drops its own left/right
   padding down a touch rather than wrapping onto two lines. */
.sidebar-add-row { display: flex; gap: 0.4rem; margin: 0 0 1rem; }
.sidebar-add-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.4rem;
  background: var(--surface); color: var(--green-ink); font-weight: 700; font-size: 0.9rem;
  padding: 0.6rem 0.5rem; border-radius: 0; margin: 0; text-decoration: none;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2); flex: 1; white-space: nowrap;
}
.sidebar-add-btn:hover { background: var(--cream); }
/* Walk-in is the secondary action of the pair — an outline treatment
   (same idea as .sidebar-logout-btn below) keeps "Add a party" reading as
   the primary one at a glance. */
.sidebar-add-btn-secondary { background: none; color: white; box-shadow: none; border: 1px solid rgba(255,255,255,0.4); }
.sidebar-add-btn-secondary:hover { background: rgba(255,255,255,0.12); }
/* Tap the logo to switch pub (lib/layout.js brandSwitcherHtml): the logo and
   name are a <details>, and the pubs drop down beneath them. */
.brand-switch { position: relative; }
.brand-switch > summary { list-style: none; cursor: pointer; }
.brand-switch > summary::-webkit-details-marker { display: none; }
.brand-switch-caret { font-size: 0.8em; opacity: 0.8; margin-left: 0.15rem; }
.brand-switch[open] .brand-switch-caret { display: inline-block; transform: rotate(180deg); }
/* Dressed as the sidebar itself — its green, its headings and its links
   (.sidebar-nav-heading, .sidebar-link) — so it reads as part of the menu. */
.brand-switch-menu {
  position: absolute; left: 0; right: 0; top: calc(100% - 0.75rem); z-index: 60;
  background: var(--green-900); color: white;
  border: 1px solid rgba(255,255,255,0.15); box-shadow: 0 8px 24px rgba(0,0,0,0.35); padding: 0.25rem 0 0.35rem;
}
/* On a phone the menu runs across the top, so the list can be wider than the logo. */
@media (max-width: 860px) {
  .brand-switch-menu { right: auto; min-width: 16rem; max-width: calc(100vw - 2rem); top: 100%; }
}
.brand-switch-label { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: rgba(255,255,255,0.55); padding: 0.5rem 0.75rem; }
.brand-switch-item { display: block; padding: 0.6rem 0.75rem; color: rgba(255,255,255,0.82); font-size: 0.92rem; font-weight: normal; text-decoration: none; white-space: normal; }
.brand-switch-item:hover, .brand-switch-item:focus { background: rgba(255,255,255,0.1); color: white; }
.brand-switch-current { background: var(--surface); color: var(--green-ink); font-weight: 600; }
.brand-switch-current:hover, .brand-switch-current:focus { background: var(--surface); color: var(--green-ink); }
.brand-switch-more { font-size: 0.85rem; color: rgba(255,255,255,0.65); border-top: 1px solid rgba(255,255,255,0.15); margin-top: 0.25rem; }
.sidebar-nav { display: flex; flex-direction: column; gap: 0.2rem; flex: 1; }
/* One group per nav heading (Staff & rota / Bookings / My account / no
   heading for Settings) — each headed group is a checkbox-driven dropdown
   (not <details>, so the mobile override below can force it open
   regardless of state — see the media query) so a sidebar with three
   sections' worth of links doesn't sit permanently expanded. The group
   containing the current page is rendered open (lib/layout.js), everything
   else starts collapsed. */
.sidebar-nav-group { display: flex; flex-direction: column; gap: 0.2rem; margin-bottom: 0.85rem; }
.sidebar-nav-group:last-child { margin-bottom: 0; }
.sidebar-nav-toggle { position: absolute; opacity: 0; width: 1px; height: 1px; overflow: hidden; }
.sidebar-nav-heading {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: rgba(255,255,255,0.55); padding: 0.5rem 0.75rem; cursor: pointer; user-select: none;
}
.sidebar-nav-heading:hover { color: rgba(255,255,255,0.85); }
.sidebar-nav-toggle:focus-visible ~ .sidebar-nav-heading { outline: 2px solid rgba(255,255,255,0.6); outline-offset: -2px; border-radius: 0; }
.disclosure-caret { font-size: 0.65rem; line-height: 1; transition: transform 0.15s ease; }
.sidebar-nav-toggle:checked ~ .sidebar-nav-heading .disclosure-caret { transform: rotate(180deg); }
.sidebar-nav-group-items { display: none; flex-direction: column; gap: 0.2rem; }
.sidebar-nav-toggle:checked ~ .sidebar-nav-group-items { display: flex; }
.sidebar-link { display: flex; align-items: center; gap: 0.65rem; color: rgba(255,255,255,0.82); padding: 0.6rem 0.75rem; border-radius: 0; font-size: 0.92rem; white-space: nowrap; }
.sidebar-link.active { background: var(--surface); color: var(--green-ink); font-weight: 600; }
.sidebar-link:hover:not(.active) { background: rgba(255,255,255,0.1); }
.sidebar-icon { display: inline-flex; align-items: center; justify-content: center; width: 1.2rem; height: 1.2rem; flex-shrink: 0; opacity: 0.85; }
.sidebar-icon svg { width: 18px; height: 18px; display: block; }
.sidebar-link.active .sidebar-icon, .sidebar-link:hover .sidebar-icon { opacity: 1; }
.sidebar-footer { border-top: 1px solid rgba(255,255,255,0.15); padding-top: 0.85rem; margin-top: 0.75rem; }
.sidebar-venue { display: block; color: white; padding: 0.4rem 0.5rem; border-radius: 0; }
.sidebar-venue:hover { background: rgba(255,255,255,0.08); }
.sidebar-venue strong { display: block; font-size: 0.95rem; }
.sidebar-venue .muted { color: rgba(255,255,255,0.65) !important; }
.sidebar-status { font-size: 0.8rem; margin: 0.15rem 0; }
.status-open { color: #8fd6b0; font-weight: 700; }
.status-closed { color: #f0a8a0; font-weight: 700; }
.sidebar-logout-form { margin-top: 0.5rem; }
.sidebar-logout-btn { width: 100%; background: none; border: 1px solid rgba(255,255,255,0.3); color: white; padding: 0.5rem; border-radius: 0; cursor: pointer; font-size: 0.85rem; }
.sidebar-logout-btn:hover { background: rgba(255,255,255,0.1); }

.app-main { flex: 1; min-width: 0; }
.app-main .content { max-width: 1200px; margin: 0; padding: 1.5rem 2rem 4rem; }

@media (max-width: 860px) {
  /* stretch, not the desktop flex-start: stacked into one column, the main
     column has to be the width of the screen. Left at flex-start it sized
     itself to its widest content instead — a 720px table made every page
     wider than the phone, and the whole page scrolled sideways. */
  .app-shell { flex-direction: column; align-items: stretch; }
  .sidebar { width: 100%; height: auto; position: static; padding: 0.75rem 1rem; }
  .sidebar-brand { padding: 0.3rem 0.5rem 0.6rem; flex-direction: row; align-items: center; }
  .sidebar-add-row { margin-bottom: 0.6rem; }
  .sidebar-nav { flex-direction: row; flex-wrap: wrap; overflow-x: visible; gap: 0.35rem; padding-bottom: 0.25rem; }
  /* Same grouped/collapsible structure as desktop (a heading toggles its
     own items via the checkbox hack) rather than a flat icon strip — the
     group wrapper is flattened with display:contents so its heading
     becomes a tappable pill in the wrapping row, and its items (still
     display:none until the checkbox is checked, per the base rules above)
     drop onto their own full-width line directly under that pill once
     opened, instead of every group's links sitting permanently visible. */
  .sidebar-nav-group { display: contents; }
  .sidebar-nav-heading {
    display: inline-flex; align-items: center; gap: 0.3rem;
    font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
    color: rgba(255,255,255,0.75); background: rgba(255,255,255,0.1);
    padding: 0.4rem 0.65rem; border-radius: 0; white-space: nowrap; flex-shrink: 0;
  }
  .sidebar-nav-toggle:checked ~ .sidebar-nav-heading { color: white; background: rgba(255,255,255,0.22); }
  .sidebar-nav-group-items { flex: 1 1 100%; flex-direction: row; flex-wrap: wrap; gap: 0.35rem; padding: 0.1rem 0 0.2rem; }
  .sidebar-link { flex-shrink: 0; }
  .sidebar-footer { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
  .sidebar-venue { flex: 1; }
  .sidebar-logout-form { margin-top: 0; }
  .sidebar-logout-btn { width: auto; padding: 0.4rem 0.8rem; }
  .app-main .content { padding: 1.1rem 1rem 3rem; }
}

/* ---------- Content / layout ---------- */
.content { max-width: 1100px; margin: 0 auto; padding: 1.25rem 1rem 4rem; }
.page-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.75rem; margin-bottom: 1rem; }
.page-head h1 { font-size: 1.4rem; margin: 0; }
.back-link { display: inline-block; margin-bottom: 0.75rem; font-size: 0.88rem; }

.stack { display: flex; flex-direction: column; gap: 0.9rem; }
.stack label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; font-weight: 600; color: var(--ink); }
.row { display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }
.row > * { flex: 1; min-width: 160px; }

/* A list item's own row: some text on the left, a tight cluster of
   actions (Edit/Remove/Approve — a handful of short links or buttons) on
   the right. Unlike .row above — built for form fields, where every
   child stretching to at least 160px is the point — nothing here is
   forced wider than its own content, so two or three short actions sit
   close together next to each other instead of spreading out across the
   row with big gaps between them. */
.list-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.list-row-actions { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
/* A wide table in either column scrolls inside its own .table-scroll box
   instead of stretching its column off the page (a grid item won't shrink
   below its content unless told it may). */
.grid-2 > * { min-width: 0; }
@media (max-width: 640px) { .grid-2 { grid-template-columns: 1fr; } }

.form-card { background: var(--surface); border-radius: 0; padding: 1.25rem; border: 1px solid var(--line); }
.form-card + .form-card { margin-top: 1rem; }
.form-card h2 { font-size: 1.05rem; margin: 0 0 0.4rem; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0.9rem; }
.form-grid label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; font-weight: 600; }
.fieldset { border: 1px solid var(--line); border-radius: 0; padding: 1rem; margin: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.fieldset legend { font-weight: 700; padding: 0 0.4rem; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.checkbox-inline { display: flex !important; flex-direction: row !important; align-items: center; gap: 0.5rem; font-weight: 600; }
.checkbox-inline input { width: auto; }
/* WCAG 2.2 target size: a tick box is at least 20px, with room round it. */
.checkbox-inline input[type="checkbox"], .checkbox-inline input[type="radio"] { width: 20px; height: 20px; margin: 2px; flex-shrink: 0; }
.value-unit { display: flex; flex-direction: row; gap: 0.5rem; }
.value-unit input[type="number"] { flex: 1 1 auto; min-width: 0; }
.value-unit select { flex: 0 0 auto; width: auto; }
form.filter-form { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: end; margin-bottom: 1rem; }
form.filter-form label { display: flex; flex-direction: column; font-size: 0.8rem; font-weight: 600; gap: 0.25rem; }

/* ---------- Cards ---------- */
.card { background: var(--surface); border-radius: 0; padding: 1.25rem; margin-bottom: 1rem; border: 1px solid var(--line); }
.card h2 { font-size: 1.05rem; }
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; flex-wrap: wrap; gap: 0.5rem; }
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.75rem; margin-bottom: 1rem; }
/* A ruled tile rather than a tinted block: white, a hairline, and one line of the venue's own colour across the top. */
.stat-tile { background: var(--surface); border: 1px solid var(--line); border-top: 3px solid var(--green-900); padding: 0.85rem 1rem 0.9rem; }
.stat-tile .num { font-size: 1.6rem; font-weight: 700; color: var(--green-ink); }
.stat-tile .label { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
/* Tinted tiles for the platform back office, where several numbers sit side by
   side and the colour is what tells them apart at a glance. Each tone matches
   the ring slice and the badge for the same thing. */
/* The demo's sign-before-entry page (lib/demoAgreement.js) — a column of
   reading width, since it is mostly prose. */
.demo-terms { max-width: 46rem; }
.demo-terms h1 { font-size: 1.3rem; }
.demo-terms-body p { margin: 0 0 0.85rem; }
.demo-terms-body p:last-child { margin-bottom: 0; }

.stat-tile-green { border-top-color: #1baf7a; }
.stat-tile-amber { border-top-color: #e0a32e; }
.stat-tile-blue { border-top-color: #2a78d6; }
.stat-tile-violet { border-top-color: #4a3aa7; }
.stat-tile-green .num { color: #14855c; }
.stat-tile-amber .num { color: #8a6412; }
.stat-tile-blue .num { color: #1f5ea8; }
.stat-tile-violet .num { color: #3d2f88; }

/* ---------- Buttons & forms ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; padding: 0.6rem 1.1rem; border-radius: 0; border: 1px solid var(--line); background: var(--surface); color: var(--ink); font-size: 0.95rem; font-weight: 600; cursor: pointer; text-align: center; }
.btn:hover { background: #f2efe6; }
.btn-primary { background: var(--green-900); color: white; border-color: var(--green-ink); }
.btn-primary:hover { background: var(--green-700); }
.btn-secondary { background: var(--green-100); color: var(--green-ink); border-color: var(--green-100); }
.btn-secondary:hover { background: #c8e6e8; }
.btn-ghost { background: none; border-color: var(--line); }
.btn-amber { background: var(--amber-600); color: white; border-color: var(--amber-600); }
.btn-amber:hover { background: #6b4a1d; border-color: #6b4a1d; }
.btn-danger { background: var(--surface); color: var(--red-500); border-color: var(--red-500); }
.btn-danger:hover { background: var(--red-100); }
.btn-block { width: 100%; }
.btn-small, .btn-sm { padding: 0.4rem 0.75rem; font-size: 0.82rem; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
/* A <summary> styled to look like a normal .btn, with the browser's default
   disclosure triangle suppressed — used for "reveal a form" buttons (like
   Add a note) that shouldn't need any JS to expand/collapse. */
summary.btn { list-style: none; }
summary.btn::-webkit-details-marker { display: none; }
details[open] summary.btn { margin-bottom: 0.75rem; }

input, select, textarea { font: inherit; padding: 0.6rem 0.7rem; border-radius: 0; border: 1px solid var(--line); background: var(--surface); color: var(--ink); width: 100%; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--green-700); outline-offset: 1px; }
textarea { min-height: 70px; resize: vertical; }
input[type="checkbox"] { width: auto; }

/* ---------- Install tip ("Add to Home Screen" nudge) ---------- */
.install-tip { position: relative; background: var(--green-100); color: var(--green-ink); border-radius: 0; padding: 0.75rem 2.2rem 0.75rem 1rem; margin-bottom: 1rem; font-size: 0.88rem; line-height: 1.4; }
.install-tip p { margin: 0; }
.install-tip-close { position: absolute; top: 0.4rem; right: 0.5rem; background: none; border: none; font-size: 1.1rem; line-height: 1; color: var(--green-ink); cursor: pointer; padding: 0.25rem; }

/* ---------- Flash / badges ---------- */
.flash { padding: 0.75rem 1rem; border-radius: 0; margin-bottom: 1rem; font-size: 0.92rem; }
.flash-success { background: var(--green-100); color: var(--green-ink); }
.flash-error { background: var(--red-100); color: var(--red-500); }
.flash-info { background: var(--blue-100); color: #1d4ed8; }
.flash a:not([class]) { color: inherit; }
.flash-warning { background: var(--amber-100); color: var(--amber-600); }
/* A message after a form saved in the background (public/app.js's live
   forms): shown where the eye is, not at the top of a page that was never
   scrolled back up, and gone again on its own. */
.flash-live { position: fixed; left: 50%; bottom: 1.25rem; transform: translateX(-50%); z-index: 60; margin: 0; max-width: min(92vw, 40rem); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18); animation: flash-live-in 0.2s ease-out; }
.flash-live.is-leaving { opacity: 0; transition: opacity 0.4s ease; }
@keyframes flash-live-in { from { opacity: 0; transform: translate(-50%, 0.5rem); } to { opacity: 1; transform: translate(-50%, 0); } }
form.is-saving { opacity: 0.6; pointer-events: none; }

.badge { display: inline-block; padding: 0.2rem 0.6rem; border-radius: 0; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.badge-success { background: var(--green-100); color: var(--green-ink); }
.badge-warning { background: var(--amber-100); color: var(--amber-600); }
.badge-danger { background: var(--red-100); color: var(--red-500); }
.badge-neutral { background: var(--surface-2); color: var(--muted); }
.badge-pending { background: var(--amber-100); color: var(--amber-600); }
.badge-approved { background: var(--green-100); color: var(--green-ink); }
.badge-denied { background: var(--red-100); color: var(--red-500); }
.badge-published { background: var(--green-100); color: var(--green-ink); }
.badge-draft { background: var(--surface-2); color: var(--muted); }
.badge-in { background: var(--green-100); color: var(--green-ink); }
.badge-out { background: var(--surface-2); color: var(--muted); }

/* How many times a guest has been in, beside their name on a booking
   (Jamie, October 2026: "a little black number on a green background").
   Deliberately green rather than the brand teal — the teal badges all mean
   a state of the booking (confirmed, deposit paid), and this means a state
   of the *guest*, so it reads as something different at a glance. Near-black
   on this green is 7.4:1, well past WCAG AA. A guest with no visits yet gets
   the muted "First time" variant instead of a green nought — see
   routes/admin.js's visitBadgeHtml for why. */
.visit-badge {
  display: inline-block; vertical-align: middle; margin-left: 0.35rem;
  min-width: 1.5rem; padding: 0.1rem 0.45rem; border-radius: 999px;
  background: #5fbf6b; color: var(--ink);
  font-size: 0.78rem; font-weight: 700; line-height: 1.5; text-align: center;
  /* .form-grid's labels are column flexboxes, which would otherwise stretch
     the badge the full width of the column. */
  flex: 0 0 auto; align-self: flex-start;
}
/* A label's first line — its text, the badge, and any hint — kept on one row
   inside those column labels, rather than each landing on its own line. */
.field-label-row { display: flex; align-items: center; gap: 0.3rem; flex-wrap: wrap; }
.visit-badge-new { background: var(--surface-2); color: var(--muted); font-weight: 600; text-transform: none; }
.visit-badge[hidden] { display: none; }

/* ---------- Auth page ---------- */
.auth-wrap { display: flex; justify-content: center; padding-top: 2rem; }
.auth-card { background: var(--surface); border-radius: 0; padding: 2rem; width: 100%; max-width: 400px; border: 1px solid var(--line); }
.demo-box { margin-top: 1.25rem; padding: 0.75rem; background: var(--cream); border-radius: 0; font-size: 0.82rem; }
.demo-box div { margin-top: 0.15rem; }
/* Sits under the credentials on a demo tenant’s login page, where "/"
   now lands (routes/booking.js) — the way back to the guest booking
   page for someone who has not logged in. */
.demo-box-guest { margin-top: 0.6rem; padding-top: 0.55rem; border-top: 1px solid var(--line); }

/* ---------- Clock widget ---------- */
.clock-card { text-align: center; padding: 2rem 1.25rem; }
/* A small greeting folded into the clock card itself (rather than its own
   page-head above the card) so the clock button is the first substantial
   thing on the staff landing page — the point of it being their homepage
   at all. */
.clock-greeting { font-size: 0.85rem; margin: 0 0 0.35rem; }
.clock-status { font-size: 1.05rem; margin-bottom: 1.25rem; }
.clock-time { font-size: 2.4rem; font-weight: 700; color: var(--green-ink); margin-bottom: 0.25rem; font-variant-numeric: tabular-nums; }
.clock-btn {
  width: 180px;
  height: 180px;
  border-radius: 0;
  border: none;
  font-size: 1.3rem;
  font-weight: 700;
  color: white;
  cursor: pointer;
  margin: 0.5rem auto 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 20px rgba(0,0,0,0.15);
}
.clock-btn.in { background: var(--green-900); }
.clock-btn.in:hover { background: var(--green-700); }
.clock-btn.out { background: var(--amber-600); }
.clock-btn.out:hover { background: #6b4a1d; }
.clock-btn:disabled { opacity: 0.6; cursor: wait; }
.geo-status { font-size: 0.85rem; margin-top: 0.5rem; }
.geo-status.error { color: var(--red-500); font-weight: 600; }
.geo-status.success { color: var(--green-500, #2f6f5e); font-weight: 600; }

/* ---------- Tables ---------- */
table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.55rem 0.6rem; border-bottom: 1px solid var(--line); vertical-align: top; }
th { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.table-scroll { overflow-x: auto; margin-bottom: 1rem; }
.table-wrap { overflow-x: auto; }
tfoot td { font-weight: 700; border-top: 2px solid var(--line); border-bottom: none; }
.data-table { min-width: 720px; background: var(--surface); border-radius: 0; border: 1px solid var(--line); border-spacing: 0; overflow: hidden; }
.data-table th { background: var(--green-100); }
/* Figures in a column line up digit for digit. */
.data-table td, .data-table th { font-variant-numeric: tabular-nums; }
/* A warning badge and the one thing to do about it, on one line. */
.alert-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 0 0 0.5rem; font-size: 0.9rem; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table .row-inactive { opacity: 0.55; }
.notes-cell { max-width: 220px; }
.actions-cell { white-space: nowrap; }

/* ---------- Dashboard: date nav, status tabs ---------- */
.date-nav { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.date-nav input[type="date"] { width: auto; }
.pill-tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 1rem; }
.pill-tab { display: inline-block; padding: 0.4rem 0.85rem; border-radius: 0; font-size: 0.82rem; font-weight: 600; background: var(--surface); color: var(--muted); border: 1px solid var(--line); }
.pill-tab.active { background: var(--green-900); color: white; border-color: var(--green-ink); }
.pill-tab:hover:not(.active) { background: var(--green-100); }

/* ---------- Covers summary ---------- */
.covers-summary { margin-bottom: 1.1rem; padding: 1rem 1.25rem; }
.covers-summary-total { display: flex; align-items: baseline; gap: 0.6rem; margin-bottom: 0.7rem; }
.covers-summary-total-value { font-size: 1.6rem; font-weight: 800; color: var(--green-ink); }
.covers-summary-breakdown { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.covers-summary-chip { display: flex; flex-direction: column; gap: 0.15rem; background: var(--cream); border-radius: 0; padding: 0.45rem 0.7rem; min-width: 120px; }
.covers-summary-chip-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 700; }
.covers-summary-chip-value { font-size: 0.95rem; font-weight: 700; }

/* ---------- Parties list ---------- */
.party-list { display: flex; flex-direction: column; gap: 0.85rem; }
.party-card { background: var(--surface); border-radius: 0; border: 1px solid var(--line); padding: 1rem 1.25rem; }
.party-card.status-cancelled, .party-card.status-no-show { opacity: 0.6; }
.party-card-header { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 0.9rem; margin-bottom: 0.85rem; }
.party-card-time { font-weight: 700; font-size: 1.05rem; min-width: 60px; }
.party-card-name { flex: 1 1 160px; }
.party-card-status { display: flex; align-items: center; gap: 0.6rem; margin-left: auto; }
.status-select { font-size: 0.85rem; padding: 0.35rem 0.5rem; border-radius: 0; border: 1px solid var(--line); background: var(--surface); color: var(--ink); }
.party-card-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 0.6rem; margin-bottom: 0.65rem; }
.info-box { background: var(--cream); border-radius: 0; padding: 0.5rem 0.7rem; }
.info-label { display: block; font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 700; margin-bottom: 0.2rem; }
.info-value { font-size: 0.92rem; font-weight: 600; }
.party-card-notes { background: var(--cream); border-radius: 0; padding: 0.55rem 0.75rem; font-size: 0.85rem; margin-bottom: 0.65rem; }
.party-card-notes .info-label { margin-bottom: 0.25rem; }
.party-card-footer { display: flex; justify-content: flex-end; }

/* ---------- Parties list: view picker + compact rows ----------
   Jamie: "show 'upcoming bookings' as default, with a drop down box...
   Make each booking box smaller as well so you can view more on one page,
   similar to dojo." Replaces the old one-per-booking .party-card (still
   used, unchanged, by the read-only staff bookings view) with a dense
   row list on the manager-facing Parties list — flexbox rather than grid
   so the same column widths apply to both the header row and every data
   row without needing named grid areas, and so it reflows to a compact
   two-line card at phone width instead of needing horizontal scroll. */
/* A compact pill rather than a full-width label-over-select block — sized
   to its own content (inline-flex) so it reads as one small filter
   control sitting above the list, not an oversized, orphaned form. */
.view-bar { display: inline-flex; align-items: center; gap: 0.5rem; background: var(--surface); border: 1px solid var(--line); border-radius: 0; padding: 0.3rem 0.3rem 0.3rem 0.9rem; margin-bottom: 0.85rem; }
.view-bar-label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); white-space: nowrap; }
.view-bar select { width: auto; border: none; background: var(--cream); border-radius: 0; padding: 0.4rem 1.8rem 0.4rem 0.9rem; font-size: 0.85rem; font-weight: 600; color: var(--ink); }
.view-bar select:focus { outline: 2px solid var(--green-700); outline-offset: 1px; }

.booking-table { display: flex; flex-direction: column; background: var(--surface); border-radius: 0; border: 1px solid var(--line); overflow: hidden; }
.booking-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.85rem; padding: 0.5rem 0.85rem; border-bottom: 1px solid var(--line); font-size: 0.86rem; }
.booking-table .booking-row:last-child { border-bottom: none; }
.booking-row-head { background: var(--green-100); font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 700; padding-top: 0.4rem; padding-bottom: 0.4rem; }
.booking-row.status-cancelled, .booking-row.status-no-show, .booking-row.is-deleted { opacity: 0.6; }

.booking-row-covers { flex: 0 0 42px; display: flex; align-items: center; gap: 0.25rem; font-weight: 700; color: var(--green-ink); font-variant-numeric: tabular-nums; }
.booking-row-name { flex: 1 1 170px; min-width: 0; display: flex; align-items: center; gap: 0.45rem; }
.booking-row-name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.booking-row-time { flex: 0 0 100px; display: flex; flex-direction: column; line-height: 1.25; }
.booking-row-time-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.booking-row-due { white-space: nowrap; }
.booking-row-notes { flex: 1 1 120px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
.booking-row-table { flex: 0 0 84px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.booking-row-actions { flex: 0 0 auto; margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }
.booking-row-actions .status-select { font-size: 0.78rem; padding: 0.28rem 0.4rem; width: auto; }
.booking-row-actions .badge { white-space: nowrap; }

/* ---------- Find a booking (cross-date search) ---------- */
/* The view picker and the all-dates search sit side by side above the
   Parties list — same pill treatment, since they're two halves of the same
   question ("which bookings am I looking at?"), one within today and one
   across every day. Wraps rather than squashing on a narrow screen. */
.list-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.view-bar-search { width: auto; min-width: 210px; border: none; background: var(--cream); border-radius: 0; padding: 0.4rem 0.9rem; font-size: 0.85rem; color: var(--ink); }
.view-bar-search:focus { outline: 2px solid var(--green-700); outline-offset: 1px; }

.booking-search-form { padding: 0.9rem 1rem; margin-bottom: 0.85rem; }
.booking-search-fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem; }
.booking-search-field { flex: 1 1 260px; min-width: 0; }
.booking-search-field-narrow { flex: 0 1 180px; }
.booking-search-field input, .booking-search-field select { width: 100%; }

/* The date is the whole point of a search result — a party on the wrong
   day is only obvious if the day is the thing you read first — so it gets
   its own column where the day view puts the notes. */
.booking-row-date { flex: 0 0 128px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.booking-row-date a { color: var(--green-ink); }
.booking-row-contact { flex: 1 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }

.status-dot { display: inline-block; width: 9px; height: 9px; border-radius: 0; flex: 0 0 auto; background: var(--muted); }
.status-dot.dot-pending { background: var(--amber-500); }
.status-dot.dot-confirmed { background: var(--green-700); }
.status-dot.dot-seated { background: var(--green-900); }
.status-dot.dot-completed { background: var(--blue-600); }
.status-dot.dot-cancelled, .status-dot.dot-noshow { background: var(--red-500); }

@media (max-width: 720px) {
  .booking-row-head { display: none; }
  .booking-row-notes { white-space: normal; order: 5; flex-basis: 100%; }
  .booking-row-contact { white-space: normal; order: 5; flex-basis: 100%; }
  .booking-row-table { order: 4; }
  .booking-row-actions { order: 6; flex-basis: 100%; margin-left: 0; justify-content: space-between; }
}

/* ---------- Settings hub ---------- */
.settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0.9rem; }
.settings-card {
  display: flex; align-items: flex-start; gap: 0.85rem;
  background: var(--surface); border-radius: 0; border: 1px solid var(--line);
  padding: 1.1rem; color: var(--ink);
}
.settings-card:hover { border-color: var(--green-700); }
.settings-card-icon { font-size: 1.4rem; line-height: 1; }
.settings-card-title { font-weight: 700; margin-bottom: 0.2rem; }
.settings-card-desc { font-size: 0.85rem; color: var(--muted); }
.settings-card-chevron { margin-left: auto; color: var(--muted); font-size: 1.3rem; align-self: center; }

/* ---------- Marketing materials ---------- */
.material-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.9rem; margin-bottom: 1rem; }
.material-tile { position: relative; border: 1px solid var(--line); border-radius: 0; overflow: hidden; background: var(--cream); display: flex; flex-direction: column; }
.material-thumb { width: 100%; height: 100px; object-fit: cover; background: var(--surface); display: block; }
.material-thumb-file { display: flex; align-items: center; justify-content: center; font-size: 2rem; }
.material-ai-badge { position: absolute; top: 6px; left: 6px; background: rgba(0, 71, 77, 0.85); color: #fff; font-size: 0.68rem; font-weight: 700; padding: 2px 7px; border-radius: 0; letter-spacing: 0.04em; }
.material-meta { padding: 0.5rem 0.6rem 0.3rem; }
.material-name { font-size: 0.82rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.material-actions { display: flex; justify-content: space-between; align-items: center; padding: 0.3rem 0.6rem 0.55rem; gap: 0.5rem; }
.material-upload-form { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.material-upload-btn { cursor: pointer; }
.material-generate { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--line); }
.material-generate-divider { margin: 0 0 0.75rem; font-size: 0.8rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.material-generate textarea { resize: vertical; }

/* ---------- Opening hours editor ---------- */
.hours-form { gap: 0.6rem; }
.hours-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; padding: 0.75rem 0; border-bottom: 1px solid var(--line); }
.hours-row:last-of-type { border-bottom: none; }
.hours-day { min-width: 180px; }
.hours-sessions { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.hours-session { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; }
.hours-session input[type="time"] { width: auto; }

/* ---------- Floor plan: table checkboxes ---------- */
.table-check-group { margin-bottom: 0.6rem; }
.table-check-group:last-child { margin-bottom: 0; }
.table-check-group-label { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 0.35rem; }
.checkbox-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.checkbox-chip { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; font-weight: 500; background: var(--cream); border: 1px solid var(--line); border-radius: 0; padding: 0.35rem 0.75rem; cursor: pointer; }
.checkbox-chip input { width: auto; }
.checkbox-chip:has(input:checked) { background: var(--green-100); border-color: var(--green-700); }

.subscriber-toolbar { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.subscriber-search { max-width: 280px; }
.subscriber-toolbar-actions { margin-left: auto; display: flex; gap: 0.4rem; }
#subscriberTable input[type="checkbox"] { width: auto; margin: 0; }

/* Search bar at the top of the stock take form. Sticks to the top of the
   page while scrolling a long count so it's always to hand; the inline
   script on the form filters the ingredient and batch rows as you type. */
.count-search-bar { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; padding: 0.5rem 0; background: var(--cream); }
.count-search-input { max-width: 360px; width: 100%; }

/* Interest-category filter chips above the subscriber table — clicking one
   just drives the existing search box (see the inline script), so a chip
   is really a shortcut for typing that category into search; "active"
   marks whichever one currently matches the search box's contents. */
.subscriber-category-filter { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.75rem; }
.chip-filter-btn { font: inherit; font-size: 0.82rem; font-weight: 600; background: var(--cream); border: 1px solid var(--line); border-radius: 0; padding: 0.3rem 0.85rem; cursor: pointer; color: var(--ink); }
.chip-filter-btn:hover { border-color: var(--green-700); }
.chip-filter-btn.active { background: var(--green-100); border-color: var(--green-700); color: var(--green-ink); }

/* The per-subscriber "Edit interests" <details> in the table — kept
   compact when closed, and the checkbox row doesn't need to stretch to
   the full table-cell width once it's open. */
.interest-editor { margin-top: 0.3rem; }
.interest-editor summary { font-size: 0.78rem; color: var(--muted); cursor: pointer; }
.interest-editor summary:hover { color: var(--green-ink); }
.interest-editor-form { margin-top: 0.5rem; gap: 0.5rem; min-width: 220px; }

/* ---------- Events (Bookings → Events) ---------- */
/* The override/alongside picker on the event form — two big, self-
   explanatory cards rather than a plain select, since which one someone
   picks meaningfully changes what the guest booking page does. */
.event-mode-choice { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.75rem; }
.event-mode-card {
  position: relative; display: flex; flex-direction: column; gap: 0.3rem; cursor: pointer;
  background: var(--cream); border: 1.5px solid var(--line); border-radius: 0;
  padding: 0.85rem 1rem;
}
.event-mode-card input { position: absolute; opacity: 0; width: 0; height: 0; }
.event-mode-card.selected, .event-mode-card:has(input:checked) { background: var(--green-100); border-color: var(--green-700); }
.event-mode-card strong { font-size: 0.95rem; color: var(--ink); }

/* ---------- Floor plan (visual view + drag-and-drop editor) ---------- */
.fp-canvas-wrap { overflow-x: auto; margin-bottom: 0.75rem; }
.fp-canvas {
  position: relative;
  width: 100%;
  min-width: 340px;
  aspect-ratio: 1000 / 560;
  /* Lets .fp-table size itself in cqw (a % of THIS element's own rendered
     width) below, matching how each table's x/y position is already a %
     of the 1000-unit-wide canvas — see .fp-table for why that keeps
     tables correctly spaced at any canvas width instead of overlapping. */
  container-type: inline-size;
  background-color: var(--cream);
  background-image:
    linear-gradient(0deg, var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 40px 40px;
  background-position: -1px -1px;
  border: 1px solid var(--line);
  border-radius: 0;
}
.fp-table {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Sized as a % of the canvas's own width (cqw), not a fixed px box — on
     a narrow phone the canvas itself shrinks to fit the screen, and a
     fixed-px table stayed the same size regardless, so tables ended up
     relatively much bigger than their spacing and overlapped/ran off the
     edge. Scaling both together fixes that; the clamp() floor keeps a
     tappable minimum size on very small screens (can reintroduce a little
     crowding right at that floor — the wrap's overflow-x:auto above is
     the fallback for anything narrower still). */
  width: clamp(38px, 6.4cqw, 64px);
  height: clamp(38px, 6.4cqw, 64px);
  background: var(--green-100);
  border: 2px solid var(--green-700);
  color: var(--green-ink);
  font-size: clamp(0.56rem, 1.7cqw, 0.7rem);
  font-weight: 700;
  text-align: center;
  line-height: 1.15;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  touch-action: none;
}
.fp-table-covers { display: block; font-size: clamp(0.48rem, 1.4cqw, 0.6rem); font-weight: 500; opacity: 0.8; }
.fp-shape-round { border-radius: 50%; }
.fp-shape-square { border-radius: 0; }
.fp-shape-rect { width: clamp(48px, 9.2cqw, 92px); height: clamp(30px, 5.8cqw, 58px); border-radius: 0; }
.fp-shape-bench { width: clamp(56px, 11.6cqw, 116px); height: clamp(26px, 4.4cqw, 44px); border-radius: 0; }
.fp-table-inactive { opacity: 0.4; }
.fp-table.fp-dragging { z-index: 5; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25); cursor: grabbing; }
.fp-status-available { background: var(--green-100); border-color: var(--green-700); color: var(--green-ink); }
.fp-status-inuse { background: var(--amber-100); border-color: var(--amber-600); color: var(--amber-600); }
.fp-table:hover { filter: brightness(0.97); }
.fp-legend { display: flex; gap: 1rem; margin-bottom: 0.75rem; font-size: 0.85rem; color: var(--muted); }
.fp-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.fp-dot { width: 12px; height: 12px; border-radius: 0; display: inline-block; border: 2px solid; box-sizing: border-box; }


/* ---------- Customers (profiles built from booking history) ---------- */
/* Reuses .booking-table / .booking-row for the shell so a customer list and
   a bookings list feel like the same kind of object; only the columns
   differ. */
.cu-cell-name { flex: 1 1 190px; min-width: 0; display: flex; flex-direction: column; gap: 0; line-height: 1.3; overflow: hidden; }
.cu-cell-name a { color: var(--ink); }
.cu-cell-name a:hover { color: var(--green-700); }
.cu-cell-contact { flex: 1 1 200px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
.cu-cell-stat { flex: 0 0 104px; font-variant-numeric: tabular-nums; }
.cu-cell-last { flex: 0 0 128px; font-weight: 600; white-space: nowrap; }
/* No-shows are the one number on these pages a venue reacts to, so they get
   the only colour — everything else stays neutral rather than turning the
   list into a traffic-light board. */
.cu-noshow { color: var(--red-500); }

.cu-stats { display: flex; flex-wrap: wrap; gap: 1.5rem; padding: 1rem 1.25rem; margin-bottom: 1rem; }
.cu-stat { display: flex; flex-direction: column; gap: 0.15rem; min-width: 96px; }
.cu-stat-value { font-size: 1.6rem; font-weight: 700; color: var(--green-ink); line-height: 1.1; font-variant-numeric: tabular-nums; }
.cu-stat-value-small { font-size: 0.95rem; font-weight: 600; }

.cu-note-list { list-style: none; margin: 1rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.cu-note { background: var(--cream); border: 1px solid var(--line); border-radius: 0; padding: 0.6rem 0.75rem; }
.cu-note-text { margin: 0 0 0.35rem; white-space: pre-wrap; }
.cu-note-meta { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }

/* The covers-per-timeslot warning on the add/edit booking form. Deliberately
   louder than a normal flash — it is the one thing on that page staff must
   not skim past — but still a warning, not an error: the booking is allowed
   through on a second press. */
.capacity-warning { border: 1px solid var(--amber-600); }
.capacity-warning p { margin: 0.4rem 0 0; }
.capacity-warning p:last-child { margin-bottom: 0; }

@media (max-width: 720px) {
  .cu-cell-contact { white-space: normal; order: 5; flex-basis: 100%; }
  .cu-cell-stat { flex-basis: 30%; }
}

/* ---------- Planner (whole-day timeline / gantt view) ---------- */
/* Status colour tokens shared by the legend dots (.fp-dot.pl-xxx) and the
   timeline blocks themselves (.pl-block.pl-xxx) — each context supplies its
   own shape/position, these just supply background + border-color. */
.pl-pending { background: var(--amber-100); border-color: var(--amber-600); }
.pl-confirmed { background: var(--green-100); border-color: var(--green-700); }
.pl-seated { background: var(--blue-100); border-color: var(--blue-600); }
.pl-completed { background: #ececec; border-color: var(--muted); }

.pl-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: 0; background: var(--surface); }
.pl-inner { position: relative; display: flex; flex-direction: column; }

.pl-ruler-row { display: flex; height: 34px; position: sticky; top: 0; z-index: 3; background: var(--surface); border-bottom: 1px solid var(--line); }
.pl-ruler { position: relative; height: 34px; }
.pl-tick {
  position: absolute; top: 0; height: 100%; padding-left: 6px; padding-bottom: 4px;
  border-left: 1px solid var(--line); font-size: 0.72rem; color: var(--muted);
  display: flex; align-items: flex-end; white-space: nowrap;
}

.pl-row { display: flex; border-bottom: 1px solid var(--line); }
.pl-row:last-child { border-bottom: none; }
/* Denser than it was: the label column carries a table name and its cover
   range, and at this size both still read fine while the row as a whole
   loses the padding that was making the planner scroll. */
.pl-row-label {
  width: 168px; flex-shrink: 0; position: sticky; left: 0; z-index: 2; background: var(--surface);
  border-right: 1px solid var(--line); padding: 0.2rem 0.75rem; display: flex; flex-direction: column;
  justify-content: center; gap: 0; font-size: 0.8rem; line-height: 1.25;
}
.pl-ruler-label { z-index: 4; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 700; justify-content: flex-end; padding-bottom: 4px; }
.pl-row-timeline {
  position: relative; flex-shrink: 0;
  background-image: linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-repeat: repeat-x;
}
/* A table's row (or Unallocated's) while a party is being dragged over it
   as a drop target — see public/app.js's initPlanner(). Same visual
   language as the rota grid's .rota-cell.drag-over. */
.pl-drop-target.drag-over { background: var(--green-100); outline: 2px dashed var(--green-700); outline-offset: -2px; }
/* Click an empty space on a table's row to add a walk-in there (public/app.js's initPlanner()). */
.pl-addable { cursor: copy; }
.pl-addable:hover { background-color: rgba(0, 0, 0, 0.025); }
.pl-label-top { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem; }
.pl-add-link { font-size: 0.68rem; font-weight: 700; text-decoration: none; white-space: nowrap; }
/* A seated party past their allocated time: the block keeps its length and
   reads as overdue instead (routes/admin.js's bookingBlockRange). */
.pl-block.pl-overdue { border-color: var(--red-500); box-shadow: inset 0 0 0 2px var(--red-500); }

/* Sized to sit inside PLANNER_ROW_LANE_HEIGHT (routes/admin.js) with a
   couple of pixels either side. Name and meta stay on their own two lines —
   the party size and arrival time are what staff scan for — just tighter. */
.pl-block {
  position: absolute; border-radius: 0; border: 1px solid var(--line);
  padding: 0.1rem 0.4rem; overflow: hidden; text-decoration: none; color: var(--ink);
  display: flex; flex-direction: column; justify-content: center; gap: 0;
  height: 30px; cursor: pointer; cursor: grab;
}
.pl-block:hover { filter: brightness(0.97); }
.pl-block:active { cursor: grabbing; }
/* Left behind at a party's original table/time slot for as long as it's
   being dragged (public/app.js's initPlanner()) — a "ghost" marking where
   it came from, since the block itself never actually moves in the DOM
   until a successful drop reloads the page with the new table applied. */
.pl-block-dragging { opacity: 0.4; border-style: dashed; box-shadow: none; }
/* The guest's name and their visit badge share the block's first line, the
   name taking whatever's left and still truncating with an ellipsis — on a
   narrow block the number is the thing worth keeping. */
.pl-block-head { display: flex; align-items: center; min-width: 0; }
.pl-block-name { font-size: 0.72rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.25; min-width: 0; }
.pl-block-meta { font-size: 0.64rem; opacity: 0.85; white-space: nowrap; line-height: 1.2; }
/* Smaller than the badge beside a name on the Parties list: a planner block
   is 30px tall and often only a couple of hours wide. */
.pl-block .visit-badge {
  margin-left: 0.25rem; min-width: 1.05rem; padding: 0 0.25rem;
  font-size: 0.62rem; line-height: 1.45;
}

.pl-nowline { position: absolute; top: 34px; bottom: 0; width: 2px; background: var(--red-500); z-index: 1; pointer-events: none; }
.pl-nowline-label {
  position: absolute; top: -1.55rem; left: 0; transform: translateX(-50%); background: var(--ink); color: white;
  font-size: 0.68rem; font-weight: 700; padding: 0.15rem 0.45rem; border-radius: 0; white-space: nowrap;
}

/* ---------- Legal pages (privacy policy) ---------- */
/* A separate, wider wrapper from .booking-wrap — that one's deliberately
   narrow for a one-field-at-a-time booking form, but a legal document
   needs a readable line length, not a form's width. */
.legal-wrap { max-width: 760px; margin: 0 auto; }
.legal-card { background: var(--surface); border-radius: 0; padding: 2rem; border: 1px solid var(--line); line-height: 1.65; }
.legal-card h1 { font-size: 1.6rem; margin-bottom: 0.25rem; }
.legal-card h2 { font-size: 1.15rem; margin-top: 2rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.legal-card h2:first-of-type { margin-top: 1.5rem; padding-top: 0; border-top: none; }
.legal-card h3 { font-size: 0.95rem; margin-top: 1rem; }
.legal-card ul { margin: 0 0 0.75rem; padding-left: 1.25rem; }
.legal-card li { margin-bottom: 0.35rem; }
.legal-card dl { margin: 0.75rem 0; }
.legal-card dt { font-weight: 700; margin-top: 0.85rem; }
.legal-card dd { margin: 0.2rem 0 0; color: var(--ink); }

/* ---------- Booking widget (?embed=1, iframed on a venue's own site —
   see /admin/settings/widget) ---------- */
/* No top bar to offset, no long page to leave room to scroll past — the
   widget is the whole visible surface, so the generous page padding and
   the shadow/border that make the booking card read as "a card on a page"
   elsewhere would just look like wasted space and a stray box outline
   inside someone else's layout. */
body.is-embed { padding-bottom: 0; }
body.is-embed .content { padding: 0.75rem; max-width: none; }
body.is-embed .booking-card { box-shadow: none; border: none; padding: 0; margin-bottom: 0; }

/* ---------- Widget settings page (/admin/settings/widget) ---------- */
.widget-copy-row { display: flex; gap: 0.6rem; align-items: center; }
.widget-copy-row input { flex: 1; min-width: 0; font-family: 'SFMono-Regular', Consolas, monospace; font-size: 0.85rem; }
.widget-qr { display: flex; align-items: center; justify-content: center; min-height: 160px; margin-bottom: 0.75rem; padding: 1rem; background: var(--green-100); border-radius: 0; }
.widget-qr img { display: block; image-rendering: pixelated; border-radius: 0; }
.widget-code { width: 100%; font-family: 'SFMono-Regular', Consolas, monospace; font-size: 0.82rem; resize: vertical; margin-bottom: 0.6rem; }

/* ---------- Guest booking flow ---------- */
.booking-wrap { max-width: 480px; margin: 0 auto; }
.booking-card { background: var(--surface); border-radius: 0; padding: 1.5rem; margin-bottom: 1rem; border: 1px solid var(--line); }
.booking-card h1 { font-size: 1.3rem; }
/* A second card on the guest page ('Prefer to talk to us?') sits under the booking form, so its heading reads a step below the page's own. */
.booking-card h2 { font-size: 1.1rem; }
.slot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 0.5rem; margin-top: 0.5rem; }
.slot-btn { display: block; text-align: center; padding: 0.6rem 0.4rem; border-radius: 0; border: 1px solid var(--green-700); background: var(--green-100); color: var(--green-ink); font-weight: 600; font-size: 0.9rem; }
.slot-btn:hover { background: var(--green-900); color: white; }
.event-chip-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.event-chip { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.45rem 0.85rem; border-radius: 0; background: var(--amber-100); border: 1px solid var(--amber-500); color: var(--amber-600); font-weight: 600; font-size: 0.88rem; text-decoration: none; }
.event-chip:hover { background: var(--amber-600); color: white; }
.event-chip .muted { color: inherit; font-weight: 500; }
.booking-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.75rem; background: var(--cream); border-radius: 0; padding: 1rem; margin: 1rem 0; }
.booking-summary > div { display: flex; flex-direction: column; gap: 0.15rem; }
.booking-summary .muted { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; }

/* ---------- Availability ---------- */
.availability-day { border: 1px solid var(--line); border-radius: 0; padding: 0.75rem; }
.availability-day-head { font-weight: 700; margin-bottom: 0.5rem; }
.avail-tag { font-size: 0.72rem; font-weight: 700; border-radius: 0; padding: 0.15rem 0.4rem; margin-bottom: 0.25rem; display: block; }
.avail-tag small { display: block; font-weight: 400; }
.avail-yes { background: var(--green-100); color: var(--green-ink); }
.avail-no { background: var(--red-100); color: var(--red-500); }
.rota-cell-unavailable { background: #fdf3f2; }

/* An approved holiday/sick/other leave request, shown automatically on the
   rota grid — informational only (like availability), doesn't block a shift
   being added the same day. Not a link/draggable, unlike a real shift chip,
   since it's derived from the Requests page rather than editable here. */
.leave-chip { font-size: 0.78rem; font-weight: 700; border-radius: 0; padding: 0.3rem 0.45rem; margin-bottom: 0.3rem; background: var(--violet-100); color: var(--violet-700); }

/* ---------- Rota grid ---------- */
.rota-grid { border-collapse: collapse; width: 100%; min-width: 720px; }
.rota-grid th, .rota-grid td { border: 1px solid var(--line); padding: 0.4rem; vertical-align: top; }
/* Sticks just below the top bar (not at top:0, which would sit exactly
   underneath it and get hidden) — --topbar-h is measured in app.js since the
   top bar's height varies (its nav row can wrap on narrow screens). On
   pages using the sidebar shell instead of a topbar, --topbar-h is simply
   never set and the fallback (0px, effectively no offset) applies. */
.rota-grid th { background: var(--green-100); position: sticky; top: var(--topbar-h, 0px); z-index: 5; }
/* .table-wrap's overflow-x:auto (needed for narrow screens, since the grid
   has a 720px min-width) has a side effect: per the CSS overflow spec, any
   non-"visible" overflow-x forces overflow-y to compute as "auto" too, which
   turns .table-wrap into its own scroll container — and that breaks the
   sticky day header above, since it then sticks relative to .table-wrap's
   (never-scrolled) internal scrollport instead of the page. On screens wide
   enough that the grid fits without needing to scroll horizontally, drop
   overflow-x back to visible so the sticky header tracks the page scroll
   as expected. */
/* Below 800px, .table-wrap can't drop overflow-x (the grid genuinely needs
   to scroll sideways there) — so instead of fighting the sticky-in-a-
   scroll-container quirk above, lean into it: cap .rota-table-wrap's own
   height and let IT be the thing that scrolls vertically, not the page.
   That makes it the real scroll container the day header sticks within
   (rather than a container that's never actually scrolled), so the dates
   stay pinned in view while staff rows scroll past underneath — the same
   "frozen header" result the ≥800px rule below gets for free, just reached
   the opposite way because here the horizontal scroll can't be given up.
   Scoped to .rota-table-wrap (the rota builder's grid specifically), not
   every .table-wrap, since other tables using that class don't have this
   sticky-header problem to begin with. This rule must come BEFORE the
   min-width:800px block below — same specificity, so source order is what
   lets the desktop rule win there and restore the ordinary full-page-scroll
   behaviour once the grid no longer needs to scroll sideways. */
.rota-table-wrap { max-height: calc(100vh - var(--topbar-h, 0px) - 2.5rem); overflow-y: auto; -webkit-overflow-scrolling: touch; }
@media (min-width: 800px) {
  .table-wrap { overflow-x: visible; }
  .rota-table-wrap { max-height: none; overflow-y: visible; }
}
.rota-summary { font-size: 0.76rem; margin-top: 0.15rem; line-height: 1.3; }
.dept-group-row td { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.3rem 0.6rem; border: none; }
.dept-publish-btn {
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  opacity: 0.85;
}
.dept-publish-btn:hover { opacity: 1; }
.row-drag-handle { cursor: grab; color: var(--muted); margin-right: 0.3rem; user-select: none; }
.row-drag-handle:active { cursor: grabbing; }
tr[data-user-id].row-drag-over { outline: 2px dashed var(--green-700); outline-offset: -2px; }
.dept-badge-0, .dept-row-0 { background: var(--dept-0-bg); color: var(--dept-0-fg); }
.dept-badge-1, .dept-row-1 { background: var(--dept-1-bg); color: var(--dept-1-fg); }
.dept-badge-2, .dept-row-2 { background: var(--dept-2-bg); color: var(--dept-2-fg); }
.dept-badge-3, .dept-row-3 { background: var(--dept-3-bg); color: var(--dept-3-fg); }
.dept-badge-4, .dept-row-4 { background: var(--dept-4-bg); color: var(--dept-4-fg); }
.dept-badge-5, .dept-row-5 { background: var(--dept-5-bg); color: var(--dept-5-fg); }
.dept-badge-6, .dept-row-6 { background: var(--dept-6-bg); color: var(--dept-6-fg); }
.dept-badge-7, .dept-row-7 { background: var(--dept-7-bg); color: var(--dept-7-fg); }
.dept-badge-0, .dept-badge-1, .dept-badge-2, .dept-badge-3, .dept-badge-4, .dept-badge-5, .dept-badge-6, .dept-badge-7 {
  display: inline-block; padding: 0.15rem 0.55rem; border-radius: 0; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
.dept-accent-0 { border-left: 4px solid var(--dept-0-fg); }
.dept-accent-1 { border-left: 4px solid var(--dept-1-fg); }
.dept-accent-2 { border-left: 4px solid var(--dept-2-fg); }
.dept-accent-3 { border-left: 4px solid var(--dept-3-fg); }
.dept-accent-4 { border-left: 4px solid var(--dept-4-fg); }
.dept-accent-5 { border-left: 4px solid var(--dept-5-fg); }
.dept-accent-6 { border-left: 4px solid var(--dept-6-fg); }
.dept-accent-7 { border-left: 4px solid var(--dept-7-fg); }
.open-shifts-header td { background: var(--amber-100); color: var(--amber-600); }
.open-shifts-row td:first-child { border-left: 4px solid var(--amber-500); }
.open-shift-chip { background: var(--amber-100); color: var(--amber-600); border: 1px dashed var(--amber-500); }
.open-shift-chip .badge-pending { margin-left: 0.3rem; }
.rota-cell { min-height: 56px; transition: background 0.1s ease; }
.rota-cell.drag-over { background: var(--green-100); outline: 2px dashed var(--green-700); outline-offset: -2px; }
.shift-chip-wrap { position: relative; display: flex; align-items: stretch; gap: 0.2rem; margin-bottom: 0.3rem; cursor: grab; }
.shift-chip-wrap:active { cursor: grabbing; }
.shift-chip {
  display: block;
  flex: 1;
  background: var(--green-100);
  color: var(--green-ink);
  border-radius: 0;
  padding: 0.3rem 0.45rem;
  font-size: 0.78rem;
  line-height: 1.3;
}
.shift-chip.draft { background: #f1efe7; color: var(--muted); border: 1px dashed var(--line); }
.shift-chip small { display: block; color: var(--muted); }
/* A shift whose worked time has been approved on Timesheets — a solid,
   more saturated fill than the default pale chip so "approved" reads as
   a distinct state at a glance, not just the rota's normal styling. Shows
   the actual clocked time (not the scheduled time) as the headline, with
   the original scheduled time kept as a small reference underneath. */
.shift-chip.shift-chip-approved { background: var(--green-700); color: #fff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.shift-chip.shift-chip-approved small { color: rgba(255, 255, 255, 0.82); }
/* chip-edit-btn: the ✎ beside a clocked shift, whose chip itself opens its
   timesheet — styled like the copy button, but a plain link (app.js wires a
   copy action to every .chip-copy-btn). */
.chip-copy-btn,
.chip-edit-btn {
  flex-shrink: 0;
  width: 1.4rem;
  border: none;
  border-radius: 0;
  background: var(--green-100);
  color: var(--green-700);
  cursor: pointer;
  font-size: 0.8rem;
}
.chip-copy-btn:hover,
.chip-edit-btn:hover { background: var(--green-900); color: white; }
.chip-edit-btn { display: flex; align-items: center; justify-content: center; text-decoration: none; }
/* The shift opened from the rota (#shift-<id>) on a staff member's clock
   events, picked out so it's obvious which one was clicked. */
.clock-shift-row:target { background: var(--green-100); box-shadow: -0.5rem 0 0 var(--green-100), 0.5rem 0 0 var(--green-100); border-radius: 0; scroll-margin-top: 6rem; }
.paste-shift-btn {
  font-size: 0.78rem;
  color: var(--green-700);
  background: none;
  border: none;
  padding: 0;
  margin-top: 0.15rem;
  cursor: pointer;
  display: block;
}
.add-shift-link { font-size: 0.78rem; color: var(--green-700); display: inline-block; margin-top: 0.15rem; }
.clipboard-bar { background: var(--green-100); color: var(--green-ink); border-radius: 0; padding: 0.6rem 1rem; font-size: 0.85rem; }
.week-nav { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 1rem; flex-wrap: wrap; }
.week-nav .label { font-weight: 700; }

/* ---------- Misc ---------- */
.list-plain { list-style: none; margin: 0; padding: 0; }
.list-plain li { padding: 0.6rem 0; border-bottom: 1px solid var(--line); }
.list-plain li:last-child { border-bottom: none; }
.coworkers-inline { margin-top: 0.35rem; }
.notification-unread { background: var(--amber-100); margin: 0 -0.6rem; padding: 0.6rem; border-radius: 0; border-bottom-color: transparent; }
.empty-state { color: var(--muted); text-align: center; padding: 2rem 1rem; }
.pill-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
hr.sep { border: none; border-top: 1px solid var(--line); margin: 1rem 0; }
.text-right { text-align: right; }
.mt-0 { margin-top: 0; }

/* ---------- Guest AI help chat widget (routes/booking.js's chatWidgetHtml) ---------- */
.chat-widget { position: fixed; right: 1rem; bottom: 1rem; z-index: 40; }
.chat-fab {
  width: 56px; height: 56px; border-radius: 0; border: none;
  background: var(--green-900); color: white; font-size: 1.4rem; line-height: 1;
  border: 1px solid var(--line); cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.chat-fab:hover { background: var(--green-700); }
.chat-panel {
  position: absolute; right: 0; bottom: 68px;
  width: min(340px, calc(100vw - 2rem));
  height: min(460px, calc(100vh - 6rem));
  background: var(--surface); border-radius: 0; border: 1px solid var(--line);
  display: flex; flex-direction: column; overflow: hidden;
}
/* An author-stylesheet `display` on the same element always beats the
   browser's built-in `[hidden] { display: none }` rule, regardless of
   selector specificity — origin wins before specificity is even compared.
   Without this, toggling the `hidden` attribute in JS (public/app.js's
   setOpen()) has no visual effect once .chat-panel's own `display: flex`
   above applies, and the close button/FAB silently stop working. */
.chat-panel[hidden] { display: none; }
.chat-panel-header { background: var(--green-900); color: white; padding: 0.7rem 1rem; display: flex; align-items: center; justify-content: space-between; font-weight: 600; font-size: 0.95rem; }
.chat-close { background: none; border: none; color: white; font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0.1rem 0.3rem; }
.chat-messages { flex: 1; overflow-y: auto; padding: 0.85rem; display: flex; flex-direction: column; gap: 0.5rem; }
.chat-msg { max-width: 85%; padding: 0.55rem 0.75rem; border-radius: 0; font-size: 0.87rem; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
.chat-msg-bot { align-self: flex-start; background: var(--green-100); color: var(--ink); border-bottom-left-radius: 2px; }
.chat-msg-user { align-self: flex-end; background: var(--green-900); color: white; border-bottom-right-radius: 2px; }
.chat-msg-error { align-self: flex-start; background: #fbe9e7; color: #7a2c22; border-bottom-left-radius: 2px; }
.chat-msg-typing { align-self: flex-start; color: var(--muted); font-size: 0.85rem; font-style: italic; }
.chat-input-row { display: flex; gap: 0.5rem; padding: 0.65rem; border-top: 1px solid var(--line); }
.chat-input-row input { flex: 1; min-width: 0; }
.chat-input-row button:disabled { opacity: 0.6; cursor: default; }
@media (max-width: 480px) {
  .chat-widget { right: 0.6rem; bottom: 0.6rem; }
  .chat-panel { width: calc(100vw - 1.2rem); }
}

/* ---------- The Staff Room (noticeboard) ---------- */
.sr-avatar {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 2.1rem; height: 2.1rem; border-radius: 0;
  font-size: 0.78rem; font-weight: 700;
}
.sr-avatar-0 { background: var(--dept-0-bg); color: var(--dept-0-fg); }
.sr-avatar-1 { background: var(--dept-1-bg); color: var(--dept-1-fg); }
.sr-avatar-2 { background: var(--dept-2-bg); color: var(--dept-2-fg); }
.sr-avatar-3 { background: var(--dept-3-bg); color: var(--dept-3-fg); }
.sr-avatar-4 { background: var(--dept-4-bg); color: var(--dept-4-fg); }
.sr-avatar-5 { background: var(--dept-5-bg); color: var(--dept-5-fg); }
.sr-avatar-6 { background: var(--dept-6-bg); color: var(--dept-6-fg); }
.sr-avatar-7 { background: var(--dept-7-bg); color: var(--dept-7-fg); }

.sr-starboard { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.sr-starboard li { display: flex; align-items: center; gap: 0.4rem; background: var(--cream); border: 1px solid var(--line); border-radius: 0; padding: 0.25rem 0.75rem 0.25rem 0.25rem; font-size: 0.85rem; }
.sr-starboard .sr-avatar { width: 1.6rem; height: 1.6rem; font-size: 0.65rem; }
.sr-star-count { font-weight: 700; color: var(--amber-600); }

.sr-post { display: flex; flex-direction: column; gap: 0.6rem; }
.sr-post-star { border-left: 4px solid var(--amber-600); }
.sr-post-side-quest { border-left: 4px solid var(--blue-600); }
.sr-post-note { border-left: 4px solid var(--green-700); }
.sr-post-header { display: flex; align-items: center; gap: 0.65rem; }
.sr-post-meta { flex: 1; min-width: 0; }
.sr-kind-badge { font-size: 0.72rem; color: var(--muted); font-weight: 600; }
.sr-post-text { margin: 0; white-space: pre-wrap; word-break: break-word; }
.sr-post-actions { display: flex; gap: 0.75rem; }

.sr-reply-list { list-style: none; margin: 0.25rem 0 0; padding: 0.75rem 0 0; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 0.65rem; }
.sr-reply { display: flex; gap: 0.6rem; align-items: flex-start; }
.sr-reply .sr-avatar { width: 1.7rem; height: 1.7rem; font-size: 0.65rem; }
.sr-reply-body { flex: 1; min-width: 0; }
.sr-reply-body p { margin: 0.15rem 0 0; }
.sr-reply-form { display: flex; gap: 0.5rem; align-items: flex-start; margin-top: 0.25rem; }
.sr-reply-form textarea { flex: 1; min-height: 44px; }

@media (max-width: 480px) {
  .sr-reply-form { flex-direction: column; }
}

/* ---------- Print (used by the rota builder's Print button) ---------- */
@media print {
  @page { size: landscape; margin: 1cm; }
  .no-print,
  .topbar,
  .sidebar,
  .flash,
  .install-tip,
  .add-shift-link,
  .chip-copy-btn,
  .chip-edit-btn,
  .paste-shift-btn,
  .row-drag-handle,
  .chat-widget {
    display: none !important;
  }
  body { background: var(--surface); }
  .content, .app-main .content { padding: 0; max-width: none; }
  .card { box-shadow: none; border: none; padding: 0; }
  .rota-grid { min-width: 0; }
  .rota-grid th { position: static; background: var(--surface-2); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .shift-chip { color: inherit; text-decoration: none; }
  [class^="dept-row-"], [class*=" dept-row-"] { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ---------- Recipe box (routes/stock*.js) ---------- */
/* A metric quantity is always a number and its unit side by side — see
   lib/stockViews.js's qtyInputHtml. */
.qty-input { display: flex; gap: 0.35rem; align-items: stretch; }
.qty-input input { flex: 1 1 auto; min-width: 0; }
.qty-input select { flex: 0 0 auto; width: auto; }
.pack-input { display: flex; gap: 0.35rem; align-items: center; flex-wrap: wrap; }
.pack-input input { width: 5.5rem; flex: 0 0 auto; }
.pack-input select { width: auto; }

.stat-tile-link { display: block; color: inherit; text-decoration: none; }
.stat-tile-link:hover { filter: brightness(0.96); }
.recipe-box-actions { margin-bottom: 1rem; }
.recipe-box-actions > * { flex: 0 0 auto; min-width: 0; }
.getting-started { margin: 0; padding-left: 1.25rem; display: flex; flex-direction: column; gap: 0.4rem; }
.compact-table { min-width: 0; width: 100%; }
.plain-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.text-danger { color: var(--red-500); }
.pre-wrap { white-space: pre-wrap; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
@media (max-width: 900px) { .grid-3 { grid-template-columns: 1fr; } }

.allergen-pill { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 0; font-size: 0.72rem; font-weight: 700; margin: 0 0.2rem 0.2rem 0; }
.allergen-pill.allergen-contains { background: var(--red-100); color: var(--red-500); }
.allergen-pill.allergen-may_contain { background: var(--amber-100); color: var(--amber-600); }
.allergen-edit-table { min-width: 0; width: 100%; }
.allergen-edit-table select { width: auto; }

/* One delivery or till-report line per card, rather than a table row: each
   line is its own small form, and a <form> can't legally sit inside a <tr>. */
.delivery-line { padding: 1rem; }
.delivery-line-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
.delivery-line-posted, .delivery-line-ignored { opacity: 0.75; padding: 0.75rem 1rem; }
.delivery-line-result { align-self: end; padding-bottom: 0.4rem; }
.sales-line-form { align-items: end; }

.recipe-builder-table { min-width: 560px; }
.recipe-builder-table select, .recipe-builder-table input { width: 100%; }
.recipe-builder-table td:nth-child(2) { width: 7rem; }
.recipe-builder-table td:nth-child(3) { width: 6.5rem; }
.recipe-builder-table td:nth-child(4) { width: 5rem; white-space: nowrap; }
.recipe-builder-table td:last-child { width: 2rem; text-align: center; }
/* Searching the ingredient list. The box sits where the dropdown was, and
   its matches are fixed to the viewport so the sideways-scrolling table
   around them can't cut them off. */
.ing-combo { position: relative; }
.ing-combo-list { position: fixed; z-index: 45; list-style: none; margin: 0; padding: 0.25rem; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 8px 22px rgba(0, 71, 77, 0.14); max-height: 18rem; overflow-y: auto; }
.ing-combo-list li { padding: 0.4rem 0.55rem; cursor: pointer; display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; }
.ing-combo-list li[aria-selected="true"], .ing-combo-list li:hover { background: var(--green-100); }
.ing-combo-name { font-weight: 600; overflow-wrap: anywhere; }
.ing-combo-group { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); white-space: nowrap; }
.ing-combo-list .ing-combo-empty, .ing-combo-list .ing-combo-more { cursor: default; color: var(--muted); font-size: 0.82rem; font-weight: 400; }
.ing-combo-list .ing-combo-empty:hover, .ing-combo-list .ing-combo-more:hover { background: none; }
.recipe-live-costing { margin-top: 1rem; }
.section-row th { background: var(--cream); text-align: left; }
.qty-sold { max-width: 7rem; }
.alert-card .page-head { margin-bottom: 0.5rem; }

/* The allergen card. Loud on purpose where it matters: "contains" and an
   incomplete card must be impossible to miss at a glance behind the bar. */
.allergen-card { background: var(--surface); border: 2px solid var(--ink); border-radius: 0; padding: 1.25rem; max-width: 30rem; }
.allergen-card-venue { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.allergen-card-title { font-size: 1.4rem; margin: 0.15rem 0 0.75rem; }
.allergen-card-warning { background: var(--amber-100); border: 2px solid var(--amber-600); color: var(--ink); padding: 0.6rem 0.75rem; border-radius: 0; margin-bottom: 0.75rem; font-size: 0.9rem; }
.allergen-card-summary { margin: 0 0 0.75rem; }
.allergen-card-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0.25rem 1rem; }
.allergen-row { display: flex; justify-content: space-between; gap: 0.5rem; padding: 0.3rem 0.5rem; border-radius: 0; font-size: 0.88rem; }
.allergen-row-contains { background: var(--red-100); font-weight: 700; }
.allergen-row-contains .allergen-status { color: var(--red-500); }
.allergen-row-may_contain { background: var(--amber-100); font-weight: 700; }
.allergen-row-may_contain .allergen-status { color: var(--amber-600); }
.allergen-row-none .allergen-status { color: var(--muted); }
.allergen-row-unknown .allergen-status { color: var(--amber-600); font-style: italic; }
.allergen-card-foot { margin: 0.75rem 0 0; font-size: 0.75rem; color: var(--muted); }
@media (max-width: 480px) { .allergen-card-list { grid-template-columns: 1fr; } }

/* The standalone printable card page (/stock/recipes/:id/allergen-card). */
.print-page { background: var(--surface); padding: 1.5rem; }
.print-actions { display: flex; gap: 0.5rem; margin-bottom: 1rem; }

/* The printable stock count sheets (/stock/count/sheet) — a wet one and a dry
   one, carried round the cellar and the walk-in with a pen. */
.count-sheet-page { max-width: 48rem; }
.sheet-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; border-bottom: 2px solid var(--line); padding-bottom: 0.6rem; }
.sheet-venue { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.sheet-title { margin: 0.1rem 0 0; font-size: 1.35rem; }
.sheet-lines { font-size: 0.82rem; }
.sheet-lines > div { margin-bottom: 0.3rem; white-space: nowrap; }
.sheet-write { display: inline-block; width: 9rem; border-bottom: 1px solid var(--ink); }
.sheet-note { font-size: 0.8rem; color: var(--muted); margin: 0.6rem 0 1rem; }
.sheet-group { margin-bottom: 1.1rem; }
.sheet-group-name { font-size: 0.95rem; margin: 0 0 0.3rem; }
.count-sheet { background: var(--surface); border: 1px solid var(--line); font-size: 0.85rem; }
.count-sheet th, .count-sheet td { border: 1px solid var(--line); padding: 0.4rem 0.5rem; vertical-align: top; }
.count-sheet th { background: var(--green-100); }
.count-sheet .sheet-unit, .count-sheet .sheet-pack, .count-sheet .sheet-expected { width: 5.25rem; white-space: nowrap; }
.count-sheet .sheet-count { width: 6.5rem; }
/* A blank line to write an ingredient's name on. */
.count-sheet .sheet-blank { height: 1.6rem; }
.sheet-foot { font-size: 0.72rem; color: var(--muted); margin: 0.75rem 0 0; }

@media print {
  .sheet-group { break-inside: avoid; }
  .count-sheet th { background: var(--surface-2); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .count-sheet td { height: 1.5rem; }
}

/* The allergen matrix — the whole menu against the 14 on one page. */
.allergen-matrix { min-width: 900px; }
.allergen-matrix th[scope="row"] { text-align: left; min-width: 11rem; }
.matrix-head { vertical-align: bottom; height: 9rem; padding: 0.4rem 0.2rem; }
.matrix-head span { writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap; font-size: 0.75rem; }
.matrix-cell { text-align: center; font-size: 1.05rem; width: 2.4rem; }
.matrix-contains { color: var(--red-500); }
.matrix-may { color: var(--amber-600); }
.matrix-unknown { color: var(--amber-600); font-weight: 700; }
.matrix-row-incomplete { background: #fffaf0; }

@media print {
  .print-actions { display: none; }
  .print-page { padding: 0; }
  .allergen-card { max-width: none; }
  /* Browsers drop background colours when printing unless told otherwise —
     and on an allergen card the colour is the warning. */
  .allergen-row, .allergen-card-warning, .allergen-pill, .matrix-cell, .matrix-row-incomplete { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* An invoice's products (lib/invoiceReview.js): one line per product, the ones
   that need a person opened up, one Approve over the lot. */
.review-head { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem 1rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.review-line { border: 1px solid var(--line); border-radius: 0; background: var(--surface); margin-bottom: 0.5rem; }
.review-line.needs-attention { border-color: var(--amber-600); }
.review-line > summary { list-style: none; cursor: pointer; padding: 0.55rem 0.8rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.75rem; }
.review-line > summary::-webkit-details-marker { display: none; }
.review-line[open] > summary { border-bottom: 1px solid var(--line); }
.review-line-name { flex: 1 1 14rem; min-width: 0; }
.review-line-meta { flex: 2 1 16rem; min-width: 0; }
.review-line-body { padding: 0.75rem 0.8rem; }
.review-line-posted > summary, .review-line-ignored > summary { opacity: 0.8; }
.review-add { margin-top: 0.75rem; }
.review-add > summary { cursor: pointer; font-weight: 600; }
.section-tabs { margin-bottom: 0.75rem; }

/* Inventory → Shopping list: a tick box per line for going round the walk-in. */
.shopping-tick { width: 2rem; text-align: center; }
.shopping-tick input { width: 1.1rem; height: 1.1rem; }
@media print {
  .shopping-group { break-inside: avoid; }
}

/* Multi-page invoices: every page side by side, wrapping on a phone. */
.invoice-pages { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.75rem; margin-bottom: 0.75rem; }
.invoice-page { margin: 0; }
.invoice-page .invoice-photo-preview { width: 100%; height: auto; }
.invoice-page figcaption { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; margin-top: 0.25rem; }
.add-pages-form { margin-top: 0.5rem; }
.waste-reasons td:nth-child(2), .waste-reasons td:nth-child(3) { white-space: nowrap; }

/* Manager's office — reporting bars & date-range preset pills */
.report-presets { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0 1.25rem; }
.report-presets .preset-active { background: var(--green-900) !important; color: white !important; border-color: var(--green-900) !important; }
.meter { background: var(--green-100); border-radius: 0; height: 9px; overflow: hidden; margin-top: 0.35rem; }
.meter-fill { background: var(--green-900); height: 100%; border-radius: 0; }
.meter-fill.meter-warn { background: var(--amber-600); }
.meter-fill.meter-bad { background: var(--red-500); }
.report-metric-label { display: flex; justify-content: space-between; font-size: 0.82rem; color: var(--muted); margin-bottom: 0.15rem; }
.ocr-note { background: var(--green-100); color: var(--green-ink); border-radius: 0; padding: 0.75rem 0.9rem; font-size: 0.85rem; margin-bottom: 1rem; }
.invoice-photo-preview { max-width: 100%; border-radius: 0; border: 1px solid var(--line); display: block; margin-bottom: 0.75rem; }
.row-active { background: var(--green-100); }

/* ---------- Settings → Branding: colour swatch picker + logo ---------- */
.color-swatch-grid { display: flex; flex-wrap: wrap; gap: 0.6rem; }
/* .stack label (further up this file) turns every <label> inside a .stack
   form into a column flex box with bold text — fine for an ordinary
   field, wrong for a small clickable colour swatch, so this reclaims
   layout/sizing explicitly rather than fighting that rule's specificity. */
.color-swatch-grid .color-swatch { display: inline-flex !important; flex-direction: row !important; width: auto; font-weight: normal; gap: 0; cursor: pointer; }
.color-swatch input[type="radio"] { position: absolute; opacity: 0; width: 2.2rem; height: 2.2rem; margin: 0; cursor: pointer; }
.color-swatch-visual { display: block; width: 2.2rem; height: 2.2rem; border-radius: 0; border: 2px solid var(--line); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); }
.color-swatch input:checked + .color-swatch-visual { border-color: var(--ink); box-shadow: 0 0 0 2px white, 0 0 0 4px var(--ink); }
.color-swatch input:focus-visible + .color-swatch-visual { outline: 2px solid var(--green-700); outline-offset: 2px; }
.color-swatch-visual-custom { position: relative; display: flex; align-items: center; justify-content: center; background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); padding: 0; overflow: hidden; }
.color-swatch-visual-custom input[type="color"] { position: absolute; inset: 0; width: 100%; height: 100%; border: none; padding: 0; cursor: pointer; background: none; }
.branding-logo-current { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.5rem; flex-wrap: wrap; }
.branding-logo-preview { max-height: 3rem; max-width: 12rem; border-radius: 0; background: var(--cream); padding: 0.4rem; border: 1px solid var(--line); }
/* Light or dark pages (routes/admin.js's brandingFormHtml): two cards, each
   with a thumbnail of a page in that look — a brand-coloured menu down the
   side and two cards on the page — so the choice can be seen before it is
   saved. Same .stack label reclaim as the colour swatches above. */
.theme-mode-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 0.75rem; }
.theme-mode-grid .theme-mode-option { display: flex !important; flex-direction: row !important; align-items: flex-start; gap: 0.75rem; width: auto; font-weight: normal; padding: 0.75rem; border: 2px solid var(--line); background: var(--surface); cursor: pointer; }
.theme-mode-option:has(input:checked) { border-color: var(--green-700); }
.theme-mode-option:has(input:focus-visible) { outline: 2px solid var(--green-700); outline-offset: 2px; }
.theme-mode-option input[type="radio"] { width: auto; flex: none; margin: 0.25rem 0 0; }
.theme-mode-text { display: flex; flex-direction: column; gap: 0.15rem; }
.theme-mode-preview { flex: none; display: flex; width: 4.5rem; height: 3rem; border: 1px solid #d7e6e6; background: #f2f9f9; overflow: hidden; }
.theme-mode-preview-bar { width: 1.1rem; background: var(--green-900); flex: none; }
.theme-mode-preview-page { flex: 1; display: flex; flex-direction: column; gap: 0.25rem; padding: 0.3rem; }
.theme-mode-preview-card { display: block; height: 0.7rem; background: white; border: 1px solid #d7e6e6; }
.theme-mode-option[data-mode="dark"] .theme-mode-preview { background: #121a1b; border-color: #2f3d3f; }
.theme-mode-option[data-mode="dark"] .theme-mode-preview-card { background: #1b2426; border-color: #2f3d3f; }

/* ---------- Head office: finding one pub among hundreds ---------- */
/* The search box on the group dashboard and above the sites table. The input
   takes the room going and the button stays its own size, so on a phone the
   two still sit on one line instead of the button wrapping underneath. */
.site-search { display: flex; align-items: center; gap: 0.5rem; flex: 1 1 320px; max-width: 30rem; margin-bottom: 1rem; }
.site-search-input { flex: 1 1 auto; min-width: 0; }
.site-search .btn { flex: 0 0 auto; }
/* On the sites page the live count sits beside the box: "12 of 193 sites". */
.site-search-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.9rem; margin-bottom: 0.9rem; }
.site-search-bar .site-search { margin-bottom: 0; }

/* ---------- Timesheet: one person, one week ---------- */
/* A row is read left to right as "this is what we asked for, this is what we
   got, this is what we're paying" — so the columns stay narrow and fixed and
   the times don't wrap into each other the way they used to when they shared a
   cell with a Save button, a break box and an Approve. */
/* Below this the columns start squeezing the times and the approve button
   out of shape, so .table-wrap scrolls the table sideways instead — the
   same thing the rota does on a phone. */
.ts-table { min-width: 46rem; }
.ts-table td { vertical-align: top; }
.ts-table .ts-day { font-weight: 700; white-space: nowrap; }
.ts-row-off td { color: var(--muted); }
/* The number and its "min" stay on one line; left to itself the unit wraps
   underneath the box and reads as a stray word in the column. */
.ts-break-cell { white-space: nowrap; }
.ts-break { width: 4rem; display: inline-block; }
.ts-break-cell .small { white-space: normal; }
.ts-clocked .inline-form { display: flex; align-items: center; gap: 0.2rem; flex-wrap: nowrap; }
.ts-actions .btn, .ts-actions .link-btn-plain { white-space: nowrap; }
/* Status badge above, then the buttons — never side by side, or a green
   "Save & approve" ends up level with the badge it's about to change. */
.ts-action-buttons { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; margin-top: 0.35rem; }
.ts-links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.page-head-sub { font-weight: 400; color: var(--muted); }

/* How far off the rota someone actually clocked. Quiet by default, because
   three minutes either side of a shift is just what a pub looks like; the
   flagged colour is for the quarter-hour-plus gaps worth asking about. */
.ts-drift-line { margin-top: 0.15rem; }
.ts-drift { font-size: 0.78rem; color: var(--muted); }
.ts-drift-flag { color: var(--amber-600); font-weight: 600; }

/* The highlight a shift gets when the rota sent you straight to it. */
.ts-row:target td { background: var(--green-100); }

/* ---------- Dashboard: the to-do list ---------- */
/* The first thing on the dashboard, and the reason to open it — so the whole
   row is the link, not just the words, and the jobs that hold up money or
   payroll carry a colour the rest don't. */
.todo-card { margin-bottom: 1rem; }
.todo-list { list-style: none; margin: 0; padding: 0; }
.todo-item + .todo-item { border-top: 1px solid var(--line); }
.todo-item a { display: flex; flex-direction: column; gap: 0.15rem; padding: 0.65rem 0.75rem; border-left: 3px solid transparent; color: var(--ink); text-decoration: none; border-radius: 0; }
.todo-item a:hover { background: var(--cream); }
.todo-label { font-weight: 600; }
.todo-urgent a { border-left-color: var(--amber-500); }
.todo-normal a { border-left-color: var(--green-100); }

/* ---------- Settings → What you use ---------- */
/* A switch per section of the app. The tick box stays its own size beside the
   text rather than stretching, which is what .stack label would otherwise do
   to it. */
.feature-toggle { display: flex !important; flex-direction: row !important; align-items: flex-start; gap: 0.75rem; padding: 0.9rem; border: 1px solid var(--line); border-radius: 0; cursor: pointer; font-weight: normal; }
.feature-toggle:has(input:checked) { background: var(--green-100); border-color: var(--green-700); }
.feature-toggle input { width: auto; margin: 0.2rem 0 0; flex: 0 0 auto; }
.feature-toggle-body { display: flex; flex-direction: column; gap: 0.2rem; }
.feature-toggle-title { font-weight: 700; }
.feature-toggle-desc { font-size: 0.9rem; }

/* ---------- To-do list: collapsing it, and muting a job ---------- */
/* The card is a <details>, so its heading is the thing you click to fold it
   away. The marker is suppressed and replaced with a caret that turns, to
   match the sidebar's groups. */
.todo-card > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; font-size: 1.05rem; font-weight: 700; }
.todo-card > summary::-webkit-details-marker { display: none; }
.todo-card > summary::after { content: '\25BE'; margin-left: auto; color: var(--muted); transition: transform 0.15s; }
.todo-card[open] > summary::after { transform: rotate(180deg); }
.todo-card > summary + * { margin-top: 0.75rem; }
/* The job fills the row and Mute sits at the end of it, so the whole line is
   still a link to the page that clears the job. */
.todo-item { display: flex; align-items: center; gap: 0.5rem; }
.todo-item > a { flex: 1 1 auto; }
.todo-mute { flex: 0 0 auto; padding-right: 0.5rem; }
.todo-muted { margin-top: 0.75rem; }
.todo-muted > summary { cursor: pointer; color: var(--muted); font-size: 0.85rem; }
.todo-muted-item > a { color: var(--muted); }
.todo-muted-item > a .todo-label { font-weight: 500; text-decoration: line-through; }

/* ---------- Floor plan: which areas customers can book ---------- */
/* Jamie: "have a button that says 'allow customers to book this area online'".
   The tick box sits on its own row under the area's name, with its Save beside
   it — the area itself is unaffected either way, so nothing here dims or
   crosses anything out. */
.area-online-form { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 0.25rem 0 0.75rem; }
.area-online-form .checkbox-chip { margin: 0; }

/* ---------- Rota: covers booked, under each day ---------- */
/* Jamie: "Under the day and date on the rota put the number of covers that are
   booked on that date, this will help with building rotas." Sits under the day
   in the header cell, quieter than the date itself — it's the thing you glance
   at while deciding how many people to put on, not a heading. */
.rota-covers { font-weight: 400; font-size: 0.78rem; text-transform: none; letter-spacing: 0; margin-top: 0.15rem; white-space: nowrap; }
.rota-covers strong { font-weight: 700; }

/* ---------- Rota templates: on top of, or in place of ---------- */
/* Jamie: "pubsuite should ask if they want the template over the top of any
   existing shifts or in place of them." Two choices stacked, so neither can be
   missed on the way to the Apply button. */
.template-mode { border: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.template-mode legend { padding: 0; margin-bottom: 0.25rem; }
.template-mode .checkbox-chip { justify-content: flex-start; }

/* ---------- Rota: a shift that clashes with approved time off ---------- */
/* Jamie: "show a warning when a shift clashes with approved time off." The
   clash can be created from either side — rostering onto a booked day off, or
   approving leave over shifts already on the rota — so the chip carries it,
   which is where somebody will be looking when it matters. Marked rather than
   dimmed: the shift is still real and still needs covering. */
.shift-chip-clash .shift-chip { outline: 2px solid var(--amber-500); outline-offset: -2px; }
.clash-flag { color: var(--amber-600); font-weight: 700; }

/* ---------- Forecast: the wage budget bar on the rota ---------- */
/* Jamie: "On the rota it should warn you about going over budget according to
   the forecast." Sits directly above the grid — the decision it's about is
   made while looking at the grid, and a warning you have to go and find is one
   nobody sees. Amber rather than red until it's actually over. */
.budget-bar { margin-bottom: 1rem; }
.budget-bar-over { border-left: 3px solid var(--amber-500); }
.budget-bar .meter { margin-top: 0.5rem; }
/* The one number the stock budget bar is there for. */
.stock-budget-figure { font-size: 1.25rem; font-weight: 700; margin-left: 0.5rem; }
.input-suffix { display: inline-flex; align-items: center; gap: 0.4rem; }
.input-suffix input { width: 6rem; }

/* ---------- Doughnut charts (lib/charts.js) ----------
   Square swatches and ruled legend rows to match the rest of the app. The
   2px white edge on each segment is the gap between them — the card's own
   surface showing through — not an outline. Hovering a segment or its
   legend row dims the rest, with no script. */
.donut-chart { margin: 0 0 1rem; }
.donut-title { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.75rem; }
.donut-body { display: flex; align-items: center; gap: 2rem; flex-wrap: wrap; }
.donut-ring { position: relative; width: 190px; height: 190px; flex: 0 0 190px; }
.donut-ring svg { display: block; width: 100%; height: 100%; }
.donut-segments path { stroke: #fff; stroke-width: 2; stroke-linejoin: miter; transition: opacity 0.15s; }
.donut-segments:hover path { opacity: 0.35; }
.donut-segments path:hover { opacity: 1; }
.donut-centre { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; pointer-events: none; }
.donut-centre-value { font-weight: 700; font-size: 1.15rem; color: var(--ink); }
.donut-centre > div { max-width: 100px; }
.donut-centre-label { font-size: 0.66rem; line-height: 1.25; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-top: 0.15rem; }
.donut-legend { flex: 0 1 460px; min-width: 260px; border-collapse: collapse; font-size: 0.9rem; font-variant-numeric: tabular-nums; }
.donut-legend td { padding: 0.45rem 0.5rem; border-bottom: 1px solid var(--line); }
.donut-legend tr:last-child td { border-bottom: none; }
.donut-legend tr:hover td { background: var(--cream); }
.donut-swatch { display: inline-block; width: 10px; height: 10px; margin-right: 0.55rem; }
.donut-chart:has(tr[data-key="drinks"]:hover) path:not([data-key="drinks"]),
.donut-chart:has(tr[data-key="food"]:hover) path:not([data-key="food"]),
.donut-chart:has(tr[data-key="wages"]:hover) path:not([data-key="wages"]),
.donut-chart:has(tr[data-key="left"]:hover) path:not([data-key="left"]),
.donut-chart:has(tr[data-key="other"]:hover) path:not([data-key="other"]) { opacity: 0.35; }
.donut-note { margin: 0.75rem 0 0; }
/* Two doughnuts side by side on a wide screen, one above the other on a phone. */
.donut-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: 1.5rem 2.5rem; }

/* Columns over time — weekly takings against budget on the estate dashboard. */
.column-chart { margin: 0 0 1rem; }
.column-title { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.column-key { font-weight: 400; font-size: 0.8rem; color: var(--muted); display: inline-flex; align-items: center; gap: 0.4rem; }
.column-key-line { display: inline-block; width: 20px; border-top: 2px dashed var(--ink); opacity: 0.55; }
.column-scroll { overflow-x: auto; }
.column-chart svg { display: block; width: 100%; min-width: 640px; height: auto; }
.column-axis { stroke: var(--line); stroke-width: 1; }
.column-bar { transition: opacity 0.15s; }
.column-chart svg:hover .column-bar { opacity: 0.4; }
.column-chart svg .column-bar:hover { opacity: 1; }
.column-target { stroke: var(--ink); stroke-width: 2; stroke-dasharray: 4 3; opacity: 0.55; }
.column-value { font-size: 12px; font-weight: 700; fill: var(--ink); text-anchor: middle; font-variant-numeric: tabular-nums; }
.column-label { font-size: 12px; fill: var(--muted); text-anchor: middle; }
.column-note { margin-top: 0.4rem; }

/* Eight headline figures read as two rows of four, not six and a straggling two. */
.stat-grid-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
/* Buttons that sit side by side at their own width. */
.btn-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1.25rem; }

/* A line icon in front of a text link, e.g. the rota's Notify links. */
.link-btn-plain .icon { width: 14px; height: 14px; vertical-align: -2px; margin-right: 0.3rem; }

/* A line icon leading a button or chip's label. */
.btn .icon, .event-chip .icon { width: 16px; height: 16px; flex-shrink: 0; }
.event-chip .icon { vertical-align: -3px; margin-right: 0.35rem; }

/* The line icon beside each switch on Settings → What you use. */
.feature-toggle-title .icon { width: 16px; height: 16px; vertical-align: -3px; margin-right: 0.4rem; }

/* ---------- Group management (lib/groupPeopleHtml.js) ---------- */
.checkbox-chip-row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.35rem; }
.person-edit { display: inline-block; vertical-align: top; }
/* Open, the form takes its own line so the row doesn't widen and push Reset
   password and Remove out of view. */
.person-edit[open] { display: block; margin-bottom: 0.4rem; white-space: normal; }
/* .stack label would stack each chip's box above its text. */
.checkbox-chip-row .checkbox-chip { flex-direction: row; font-weight: 500; }
.person-edit > summary { list-style: none; cursor: pointer; }
.person-edit > summary::-webkit-details-marker { display: none; }
.person-edit[open] > summary { background: var(--green-900); color: white; border-color: var(--green-ink); }
.person-edit-form { margin-top: 0.5rem; padding: 0.75rem; border: 1px solid var(--line); background: var(--cream); min-width: 16rem; text-align: left; }
/* A temporary password, shown once — big enough to read out over the phone. */
.temp-password code { display: inline-block; font-size: 1.4rem; letter-spacing: 0.08em; padding: 0.5rem 0.9rem; background: var(--cream); border: 1px solid var(--line); }

/* Group Setup and Budgets (routes/groupEstate.js). */
.input-pct { width: 5.5rem; }
.input-money { width: 7rem; text-align: right; }
.region-rename { display: flex; gap: 0.4rem; align-items: center; }
.region-rename input { width: 16rem; max-width: 100%; }
.row-highlight td { background: var(--green-100); }
.budget-periods { flex-wrap: wrap; }
.budget-grid td, .budget-grid th { white-space: nowrap; vertical-align: top; }
.budget-grid tbody th[scope="row"] { font-weight: 600; text-align: left; }
.budget-grid .budget-ly { margin-top: 0.2rem; text-align: right; }
.budget-grid .budget-region th { background: var(--cream); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; }
.budget-grid tfoot th, .budget-grid tfoot td { border-top: 2px solid var(--line); }
.region-add { display: flex; gap: 0.4rem; margin-top: 0.75rem; flex-wrap: wrap; }
.region-add input { width: 16rem; max-width: 100%; }
.budget-grid tbody th[scope="row"], .budget-grid tfoot th { text-transform: none; letter-spacing: 0; font-size: 0.9rem; color: var(--ink); background: transparent; }
form.stack + h3 { margin-top: 1.5rem; }

/* Estate dashboard (routes/groupDashboard.js). */
.crumbs { font-size: 0.85rem; margin-bottom: 0.25rem; }
.estate-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 0.75rem; margin: 0.75rem 0 1rem; }
.estate-tile { display: flex; flex-direction: column; gap: 0.3rem; align-items: flex-start; padding: 0.9rem 1rem; background: var(--surface); border: 1px solid var(--line); color: var(--ink); text-decoration: none; }
.estate-tile:hover { border-color: var(--green-700); }
.estate-tile.active { border: 2px solid var(--green-900); padding: calc(0.9rem - 1px) calc(1rem - 1px); }
.estate-tile-label { font-size: 0.8rem; font-weight: 600; }
.estate-tile-num { font-size: 1.7rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.estate-tile-sub { font-size: 0.8rem; color: var(--muted); }
.kpi-table td, .kpi-table th, .estate-breakdown td, .estate-breakdown th { vertical-align: top; }
.kpi-table td.num, .estate-breakdown td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.kpi-table tbody th[scope="row"], .estate-breakdown tbody th[scope="row"] { text-transform: none; letter-spacing: 0; font-size: 0.9rem; color: var(--ink); background: transparent; text-align: left; font-weight: 600; }
.sparkline { display: block; overflow: visible; }
.sparkline path { fill: none; stroke: var(--green-700); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.sparkline circle { fill: var(--green-700); stroke: white; stroke-width: 1.5; }
.estate-howto summary { cursor: pointer; }
.estate-howto ul { margin: 0.75rem 0 0; padding-left: 1.2rem; }
.estate-howto li { margin-bottom: 0.4rem; }
.data-table th.num, .data-table td.num { text-align: right; }
.kpi-note { font-weight: 400; margin-top: 0.2rem; }
.kpi-table, .estate-breakdown { min-width: 760px; }
@media (max-width: 480px) { .estate-tile { padding: 0.7rem 0.75rem; } .estate-tile-num { font-size: 1.35rem; } }

/* League table and score (routes/groupLeague.js). */
.sort-link { color: inherit; text-decoration: none; white-space: nowrap; }
.sort-link:hover { text-decoration: underline; }
.league-table { min-width: 860px; }
.league-table tbody th[scope="row"], .score-table tbody th[scope="row"], .score-table tfoot th { text-transform: none; letter-spacing: 0; font-size: 0.9rem; color: var(--ink); background: transparent; text-align: left; font-weight: 600; }
.league-table td, .league-table th, .score-table td, .score-table th { vertical-align: top; }
.league-score a { text-decoration: none; font-size: 1.05rem; }
.league-summary { display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; align-items: center; }
.league-summary p { flex: 1; min-width: 16rem; margin: 0; }
.league-summary-score { font-size: 2rem; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.league-summary-score .badge { vertical-align: middle; }
.score-table { min-width: 720px; }
.score-table tr.muted th, .score-table tr.muted td { color: var(--muted); }
.estate-score-line { margin: 0 0 0.75rem; }
.league-table .badge { white-space: nowrap; }
.league-table tbody th[scope="row"] { min-width: 10rem; }

/* Alerts (routes/groupAlerts.js). */
.alerts-summary { font-size: 1.05rem; font-weight: 600; margin: 0 0 0.75rem; }
.alerts-banner { display: block; margin: 0 0 0.75rem; padding: 0.6rem 0.9rem; background: var(--amber-100); color: var(--amber-600); border-left: 4px solid var(--amber-500); font-weight: 600; text-decoration: none; }
.alerts-banner-act { background: var(--red-100); color: var(--red-500); border-left-color: var(--red-500); }
.alerts-banner:hover { text-decoration: underline; }
.alert-list { list-style: none; margin: 0 0 1rem; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.alert-item { background: var(--surface); border: 1px solid var(--line); border-left: 4px solid var(--amber-500); padding: 0.75rem 1rem; }
.alert-item.alert-act { border-left-color: var(--red-500); }
.alert-item.alert-overdue { box-shadow: inset 0 0 0 1px var(--red-500); }
.alert-head { display: flex; gap: 0.75rem; align-items: flex-start; }
.alert-head > .badge { flex: none; margin-top: 0.15rem; }
.alert-text { flex: 1; min-width: 0; }
.alert-title { font-weight: 600; color: var(--ink); }
.alert-meta { margin-top: 0.3rem; color: var(--muted); }
.alert-notes { list-style: none; margin: 0.5rem 0 0 0; padding: 0 0 0 0.75rem; border-left: 2px solid var(--line); }
.alert-notes li { margin-bottom: 0.4rem; }
.alert-manage { margin-top: 0.5rem; }
.alert-manage > summary { list-style: none; cursor: pointer; display: inline-block; }
.alert-manage > summary::-webkit-details-marker { display: none; }
.alert-manage-body { margin-top: 0.6rem; padding: 0.75rem; background: var(--cream); border: 1px solid var(--line); display: flex; flex-direction: column; gap: 0.75rem; }
.alert-assign { align-items: flex-end; }

/* A tick-box chip inside a .stack form keeps its box beside its words. */
.stack label.checkbox-chip { flex-direction: row; align-self: flex-start; font-weight: 500; }

/* Compliance checklists (routes/checklists.js). */
.check-card .card-header { margin-bottom: 0.35rem; }
.check-progress { height: 4px; background: var(--line); margin-bottom: 0.75rem; }
.check-progress span { display: block; height: 100%; background: var(--green-700); }
.check-section + .check-section { margin-top: 1rem; }
.check-section-name { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin: 0 0 0.25rem; }
.check-rows { list-style: none; margin: 0; padding: 0; }
.check-row { display: flex; gap: 0.6rem; align-items: center; padding: 0.5rem 0; border-bottom: 1px solid var(--line); }
.check-row:last-child { border-bottom: 0; }
.check-mark { flex: none; width: 1.5rem; height: 1.5rem; display: flex; align-items: center; justify-content: center; font-weight: 700; background: var(--green-100); color: var(--green-ink); }
.check-row.check-problem .check-mark { background: var(--red-100); color: var(--red-500); }
.check-mark-open { background: transparent; border: 2px solid var(--line); }
.check-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.check-label { font-weight: 600; }
.check-row.check-done .check-label, .check-row.check-problem .check-label { font-weight: 500; }
.check-who { font-size: 0.8rem; color: var(--muted); }
.check-actions { display: flex; gap: 0.4rem; align-items: center; flex: none; flex-wrap: wrap; justify-content: flex-end; }
.check-reading { display: flex; align-items: center; gap: 0.3rem; }
.check-reading input { width: 5rem; }
.check-note-input { width: 9rem; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.check-edit-section { border: 1px solid var(--line); background: var(--cream); padding: 0.75rem; }
.check-edit-section + .check-edit-section { margin-top: 0.5rem; }
.check-edit-table input[type=text] { width: 100%; }
.check-edit-table .input-unit, .check-edit-table .input-pct { width: 5rem; }
.input-unit { width: 4rem; }
@media (max-width: 640px) {
  .check-row { flex-wrap: wrap; }
  .check-actions { width: 100%; justify-content: flex-start; padding-left: 2.1rem; }
  .check-note-input { flex: 1; min-width: 6rem; }
}

.check-edit-row.is-tick td:nth-child(n+3) > * { visibility: hidden; }
.check-section-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.check-entry-table th, .check-entry-table td { vertical-align: middle; }
.check-entry-table .check-mark { display: inline-flex; }
.check-entry-new td { background: var(--cream); }
.check-entry-new input[type="text"] { width: 100%; min-width: 8rem; }
.check-entry-problem td { background: #fdf6f5; }

/* Area-manager visits (routes/groupVisits.js). */
.visit-up { color: var(--green-700); font-weight: 600; }
.visit-down { color: var(--red-500); font-weight: 600; }
.visit-chip { display: inline-block; font-size: 0.72rem; background: var(--cream); border: 1px solid var(--line); padding: 0.1rem 0.4rem; margin: 0 0.15rem 0.15rem 0; white-space: nowrap; }
.visit-rows { list-style: none; margin: 0; padding: 0; }
.visit-row { display: flex; gap: 0.75rem; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; padding: 0.6rem 0; border-bottom: 1px solid var(--line); }
.visit-row:last-child { border-bottom: 0; }
.visit-row.visit-answered { background: linear-gradient(90deg, var(--green-100) 0 3px, transparent 3px); padding-left: 0.6rem; }
.visit-row.visit-repeat { background: linear-gradient(90deg, var(--red-500) 0 3px, transparent 3px); padding-left: 0.6rem; }
.visit-q { display: flex; flex-direction: column; gap: 0.2rem; flex: 1; min-width: 14rem; }
.visit-q-text { font-weight: 600; }
.visit-q-meta { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.visit-note { font-size: 0.85rem; }
.visit-photos img { height: 3rem; width: 3rem; object-fit: cover; border: 1px solid var(--line); margin-right: 0.25rem; }
.visit-actions { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.visit-note-input { width: 14rem; }
.visit-scores { display: flex; gap: 0.2rem; }
.visit-scores .btn { min-width: 2.1rem; padding-left: 0.5rem; padding-right: 0.5rem; }
.visit-gallery { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.visit-gallery figure { margin: 0; width: 10rem; }
.visit-gallery img { width: 100%; height: 7rem; object-fit: cover; border: 1px solid var(--line); }
.visit-gallery figcaption { font-size: 0.8rem; color: var(--muted); }
.visit-edit-q { margin-top: 0.35rem; }
.visit-edit-q input { width: 100%; }
@media (max-width: 640px) { .visit-actions { width: 100%; } .visit-note-input { flex: 1; } }

/* Training: the grid of who holds what (routes/training.js). A cell's tint
   carries the same meaning as its chip, so the shape of the problem shows
   up before anything is read. */
.training-cell { white-space: nowrap; }
.training-cell.training-expired, .training-cell.training-missing { background: var(--red-100); }
.training-cell.training-expiring { background: var(--amber-100); }
.training-gap { padding: 0.4rem 0 0.4rem 0.6rem; border-bottom: 1px solid var(--line); border-left: 3px solid var(--line); }
.training-gap:last-child { border-bottom: 0; }
.training-gap-expired, .training-gap-rtw.expired { border-left-color: var(--red-500); }
.training-gap-missing, .training-gap-rtw.missing { border-left-color: var(--red-500); }
.training-gap-expiring, .training-gap-rtw.expiring { border-left-color: var(--amber-500); }

/* Next week (routes/groupForecast.js): the one tile that means somebody has
   to do something — a wage bill above what the week can afford. */
.estate-tile.estate-tile-act { border-color: var(--red-500); }
.estate-tile.estate-tile-act .estate-tile-num { color: var(--red-500); }

/* Till and accounts feeds (routes/feeds.js): a key is shown once, so it has
   to be easy to select, and the example has to be copyable as it stands. */
.feed-key { display: inline-block; padding: 0.5rem 0.7rem; background: var(--green-100); word-break: break-all; font-size: 0.95rem; user-select: all; }
.feed-example { padding: 0.75rem; background: var(--cream); border: 1px solid var(--line); overflow-x: auto; font-size: 0.8rem; white-space: pre; }

/* Head office's menu bar (lib/groupNav.js). The dropdowns are <details>, so
   they work with the stylesheet alone and keep working if the script never
   loads — public/app.js only adds "one open at a time" and Escape. */
.pill-tabs { position: relative; align-items: flex-start; }
.nav-menu { position: relative; }
.nav-menu > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 0.35rem; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::after { content: '▾'; font-size: 0.7em; opacity: 0.7; }
.nav-menu[open] > summary { background: var(--green-100); border-color: var(--green-700); color: var(--green-ink); }
.nav-menu.nav-menu-active > summary { border-color: var(--green-ink); color: var(--green-ink); }
.nav-menu-list { position: absolute; z-index: 30; top: calc(100% + 0.3rem); left: 0; min-width: 16rem; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 6px 20px rgba(0, 71, 77, 0.12); padding: 0.3rem; }
.nav-menu-item { display: block; padding: 0.45rem 0.6rem; text-decoration: none; color: var(--ink); }
.nav-menu-item:hover { background: var(--green-100); }
.nav-menu-item.active { background: var(--green-900); color: white; }
.nav-menu-item.active .nav-menu-blurb { color: rgba(255, 255, 255, 0.75); }
.nav-menu-label { display: block; font-weight: 600; font-size: 0.85rem; }
.nav-menu-blurb { display: block; font-size: 0.75rem; color: var(--muted); }
.pill-tab-ghost { margin-left: auto; background: transparent; border-style: dashed; }

/* Choosing what sits on the bar (routes/groupMenu.js). */
.menu-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.75rem; }
.menu-group { border: 1px solid var(--line); padding: 0.6rem 0.75rem; }
.menu-group legend { font-size: 0.8rem; font-weight: 700; padding: 0 0.3rem; }
.menu-choice { display: flex; gap: 0.5rem; align-items: flex-start; padding: 0.3rem 0; font-weight: normal; }
.menu-choice input { width: auto; margin-top: 0.2rem; }
/* Inside a .stack form (the platform console's group extras) the box stays
   beside its words rather than above them. */
.stack label.menu-choice { flex-direction: row; font-weight: normal; }
@media (max-width: 640px) { .nav-menu-list { position: static; min-width: 0; box-shadow: none; } .pill-tab-ghost { margin-left: 0; } }

/* Benchmark — pub against pub (routes/groupBenchmark.js). */
.benchmark-measure { margin-bottom: 1rem; }
.benchmark-measure h2 { font-size: 1.1rem; }
.benchmark-measure .page-head { align-items: baseline; gap: 0.5rem 1rem; }
.benchmark-headline { border-left: 4px solid var(--green-700); }
.benchmark-headline-line { font-size: 1.05rem; }
/* A pub on the right side of the middle is still worth seeing, just not
   worth reading first. */
.benchmark-ahead th[scope="row"] a, .benchmark-ahead td { color: var(--muted); }
.benchmark-ahead th[scope="row"] { font-weight: 600; }
ul.tight { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.4rem; }

/* What to do this week (routes/groupActions.js). */
.action-headline { border-left: 4px solid var(--green-700); }
.action-headline-line { font-size: 1.05rem; }
.action-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.action-item { border: 1px solid var(--line); border-left: 4px solid var(--green-700); padding: 0.7rem 0.9rem; background: var(--surface); }
.action-item.action-must { border-left-color: var(--red-500); }
.action-head { display: flex; gap: 0.75rem; align-items: flex-start; }
.action-text { flex: 1; min-width: 0; }
.action-title { font-weight: 600; display: block; }
.action-rank { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--muted); min-width: 1.5rem; }
/* The money reads down the right, so the list can be scanned by what it is
   worth without reading a word of it. */
.action-worth { text-align: right; min-width: 6.5rem; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) { .action-head { flex-wrap: wrap; } .action-worth { text-align: left; min-width: 0; } }

/* The other ways in (routes/feeds.js). */
.feed-endpoint { border-top: 1px solid var(--line); padding-top: 0.75rem; margin-top: 0.75rem; }
.feed-endpoint:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
.feed-endpoint h3 { font-size: 1rem; margin: 0 0 0.25rem; }

/* Connecting a till by its own API key (routes/feeds.js tillHtml). */
.till-provider { border: 1px solid var(--line); padding: 0.6rem 0.9rem; margin-top: 0.6rem; }
.till-provider > summary { cursor: pointer; font-size: 1.02rem; }
.till-connect { display: grid; gap: 0.75rem; margin-top: 0.75rem; max-width: 36rem; }
.till-connect label { display: grid; gap: 0.3rem; }
.till-connect .small { font-weight: normal; }

/* The week bar’s "go to a week" box (lib/layout.js’s weekNav). */
.week-jump { display: flex; align-items: center; gap: 0.35rem; margin-left: auto; }
.week-jump label { font-size: 0.8rem; color: var(--muted); }
.week-jump input[type="date"] { width: auto; padding: 0.25rem 0.4rem; font-size: 0.85rem; }
@media (max-width: 640px) { .week-jump { margin-left: 0; width: 100%; } .week-jump input[type="date"] { flex: 1 1 auto; min-width: 0; } }

/* Jamie: "the rota view on the mobile version is difficult to view now as
   before you could see the whole week."

   Seven days will not fit across a phone at any readable size, so the grid
   still scrolls sideways — what was wrong was how much of the screen was
   gone before the first day even started. The names column carried a full
   name, a job title, three lines of hours and money, and a Remove button, and
   took two thirds of a 375px screen with it, which left about a day and a
   half of the week visible.

   So on a phone that column is cut to six and a half rems and pinned to the
   left: the week scrolls past it and the names stay put, which is the bit
   that makes a wide grid usable on a small screen — you can always see whose
   row you are reading. That is four or five days a screen instead of one. */
@media (max-width: 700px) {
  .rota-grid { min-width: 0; }
  .rota-grid th, .rota-grid td { padding: 0.3rem; font-size: 0.84rem; }
  .rota-grid tr:not(.dept-group-row) > *:first-child {
    position: sticky;
    left: 0;
    z-index: 4;
    background: var(--surface);
    width: 6.5rem;
    min-width: 6.5rem;
    max-width: 6.5rem;
    word-break: break-word;
  }
  /* The day headings are already sticky downwards; the corner has to beat
     both, or the first name slides over the top of it. */
  .rota-grid thead th:first-child { z-index: 6; background: var(--green-100); }
  /* Capped as well as floored: a shift chip left to itself is as wide as
     "11:30–22:00 Supervisor · 30min break" wants to be, which put the day
     columns back up to 123px and undid most of what the names column just
     gave back. The chip wraps instead. */
  .rota-grid tr:not(.dept-group-row) > *:not(:first-child) { min-width: 5.5rem; max-width: 5.5rem; }
  /* The chip sits in a row with its edit and copy buttons, which in an 88px
     column left the text about forty pixels and broke it one letter to a
     line. On a phone the buttons drop underneath instead, so the time has
     the column to itself and still reads as a time. */
  .rota-grid .shift-chip-wrap { flex-wrap: wrap; }
  .rota-grid .shift-chip { flex: 1 1 100%; white-space: normal; overflow-wrap: anywhere; font-size: 0.72rem; padding: 0.25rem 0.3rem; }
  .rota-grid .add-shift-link { font-size: 0.72rem; }
  .rota-summary { font-size: 0.68rem; }
  .rota-grid td:first-child .link-btn-plain { font-size: 0.7rem; }
  /* A phone has no cursor to drag with, so the handle is only taking up room. */
  .rota-grid .row-drag-handle { display: none; }
}

/* Menu performance (routes/stockMenu.js). */
.menu-headline { border-left: 4px solid var(--green-700); }
.menu-headline-line { font-size: 1.05rem; }
.menu-corners { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 0.75rem; }
.menu-corner-card { margin: 0; }
/* The four corners read at a glance by their edge, before a word of them. */
.menu-corner-card-keep { border-left: 4px solid var(--green-700); }
.menu-corner-card-fix { border-left: 4px solid var(--amber-500); }
.menu-corner-card-push { border-left: 4px solid var(--blue-600); }
.menu-corner-card-drop { border-left: 4px solid var(--red-500); }
.menu-corner { font-size: 0.78rem; font-weight: 700; white-space: nowrap; }
.menu-corner-keep { color: var(--green-700); }
.menu-corner-fix { color: var(--amber-600); }
.menu-corner-push { color: var(--blue-600); }
.menu-corner-drop { color: var(--red-500); }

/* Guest satisfaction (routes/guests.js). */
.guest-headline { border-left: 4px solid var(--green-700); }
.guest-score { font-size: 1.6rem; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.guest-headline .stat-grid { margin-top: 0.75rem; }

/* PubSuite's own training courses (routes/training.js, lib/courseContent.js). */
.course-lesson h2 { margin-top: 0; }
.course-lesson p, .course-lesson li { line-height: 1.55; }
.course-callout { padding: 0.7rem 0.9rem; margin: 0.75rem 0; border-left: 4px solid; }
.course-callout-tip { background: var(--blue-100); color: var(--blue-600); border-color: var(--blue-600); }
.course-callout-warn { background: var(--amber-100); color: var(--amber-600); border-color: var(--amber-600); }
.quiz-q { border: 0; padding: 0; margin: 0 0 1.25rem; }
.quiz-q legend { font-weight: 600; margin-bottom: 0.4rem; padding: 0; }
.quiz-option { display: flex; gap: 0.5rem; align-items: flex-start; padding: 0.35rem 0; cursor: pointer; }
.quiz-option input { width: auto; flex: 0 0 auto; display: inline-block; margin: 0.25rem 0 0; }
.quiz-result { padding: 0.6rem 0; border-top: 1px solid var(--line, #e5e5e5); }
.quiz-result:first-child { border-top: 0; }
.course-callout-pass { background: var(--green-100); color: var(--green-ink); border-color: var(--green-700); }

/* Guest feedback and the PubSuite score (lib/feedback.js, routes/feedback.js, routes/guests.js). */
.feedback-stars { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: 0.25rem; font-size: 2.2rem; line-height: 1; }
.feedback-stars .feedback-star { cursor: pointer; color: #c9c9c9; font-size: 2.2rem; line-height: 1; margin: 0; font-weight: normal; }
.feedback-star input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.feedback-stars .feedback-star:hover, .feedback-stars .feedback-star:hover ~ .feedback-star, .feedback-stars .feedback-star:has(input:checked), .feedback-stars .feedback-star:has(input:checked) ~ .feedback-star { color: #e0a100; }
.feedback-star input:focus-visible + span { outline: 2px solid currentColor; outline-offset: 2px; }
.feedback-bars { margin: 0.5rem 0; max-width: 22rem; }
.feedback-bar { display: grid; grid-template-columns: 2.2rem 1fr 2.5rem; align-items: center; gap: 0.5rem; font-size: 0.85rem; }
.feedback-bar-track { height: 0.5rem; background: var(--line); display: block; }
.feedback-bar-fill { height: 100%; background: #e0a100; display: block; }
.pubsuite-score-badge { display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 0.35rem; padding: 0.45rem 0.75rem; border: 1px solid var(--line); background: var(--surface); margin: 0.25rem 0 0.75rem; }
.pubsuite-score-number { font-size: 1.5rem; font-weight: 700; line-height: 1; }
.pubsuite-score-of { font-weight: 600; opacity: 0.7; }
.pubsuite-score-label { font-size: 0.85rem; opacity: 0.8; }

/* The add-a-party drawer on the Parties list (September 2026 — routes/
   admin.js's bookingDrawerHtml, public/app.js's initBookingDrawer). Jamie
   wanted it "like a side bar" rather than a whole page: a white panel down
   the right, header and buttons fixed top and bottom, the day's parties
   still there and usable beside it. The app's own square corners and teal,
   except where the brief asked otherwise — round −/+ buttons and rounded
   time slots, the chosen one filled in the brand's dark teal. Full width on
   a phone. */
.bk-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 420px; max-width: 100%; background: var(--surface); border-left: 1px solid var(--line); box-shadow: -8px 0 28px rgba(0, 0, 0, 0.14); z-index: 50; display: flex; flex-direction: column; }
.bk-drawer[hidden], .bk-drawer [hidden] { display: none !important; }
.bk-form, .bk-screen { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.bk-head { display: flex; align-items: center; gap: 0.5rem; padding: 0.9rem 1rem; border-bottom: 1px solid var(--line); background: var(--surface); flex-shrink: 0; }
.bk-head h2 { flex: 1; margin: 0; font-size: 1.1rem; }
.bk-head h2:focus { outline: none; }
.bk-icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; flex-shrink: 0; border: 1px solid transparent; background: none; color: var(--ink); font-size: 1.5rem; line-height: 1; cursor: pointer; }
.bk-icon-btn:hover { background: var(--cream); border-color: var(--line); }
.bk-icon-btn:focus-visible, .bk-round:focus-visible, .bk-slot:focus-visible, .bk-tabs [role="tab"]:focus-visible, .bk-time-btn:focus-visible, .bk-link:focus-visible { outline: 2px solid var(--green-700); outline-offset: 1px; }
.bk-tabs { display: flex; border-bottom: 1px solid var(--line); flex-shrink: 0; padding: 0 1rem; gap: 1.25rem; }
.bk-tabs [role="tab"] { background: none; border: 0; border-bottom: 3px solid transparent; padding: 0.65rem 0.1rem 0.5rem; font: inherit; font-weight: 600; color: var(--muted); cursor: pointer; }
.bk-tabs [role="tab"][aria-selected="true"] { color: var(--green-ink); border-bottom-color: var(--green-ink); }
.bk-body { flex: 1 1 auto; overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: 1.1rem; overscroll-behavior: contain; }
.bk-foot { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.85rem 1rem; border-top: 1px solid var(--line); background: var(--surface); flex-shrink: 0; }
.bk-foot .btn { width: 100%; }
.bk-flash { margin: 0; }
.bk-field { display: flex; flex-direction: column; gap: 0.35rem; }
.bk-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.bk-label { font-size: 0.9rem; font-weight: 700; color: var(--ink); padding: 0; }
.bk-hint { margin: 0; font-size: 0.8rem; color: var(--muted); }
/* Editing a party: its reference, and the way to the full page. */
.bk-edit-note { margin: 0; padding: 0.6rem 1rem; font-size: 0.85rem; color: var(--muted); border-bottom: 1px solid var(--line); background: var(--surface); flex-shrink: 0; }
.bk-edit-note[hidden] { display: none; }
.bk-hint:empty { display: none; }
.bk-stepper { display: flex; align-items: center; gap: 0.6rem; }
.bk-stepper input { width: 5rem; text-align: center; }
.bk-stepper-value { min-width: 8.5rem; text-align: center; font-weight: 600; padding: 0.6rem 0.5rem; border: 1px solid var(--line); }
.bk-round { width: 2.4rem; height: 2.4rem; border-radius: 50%; border: 1px solid var(--line); background: var(--surface); color: var(--green-ink); font-size: 1.25rem; font-weight: 700; line-height: 1; cursor: pointer; flex-shrink: 0; }
.bk-round:hover { background: var(--green-100); border-color: var(--green-700); }
.bk-round[disabled] { opacity: 0.4; cursor: not-allowed; }
.bk-when { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
.bk-time-btn { font: inherit; text-align: left; padding: 0.6rem 0.7rem; border: 1px solid var(--line); background: var(--surface); color: var(--ink); cursor: pointer; }
.bk-time-btn:hover { border-color: var(--green-700); }
.bk-time-btn.is-empty { color: var(--muted); }
.bk-choice { display: flex; gap: 1rem; flex-wrap: wrap; font-size: 0.9rem; }
.bk-choice label { display: inline-flex; align-items: center; gap: 0.35rem; font-weight: 500; cursor: pointer; }
.bk-choice input { width: auto; }
.bk-tables { display: flex; flex-direction: column; gap: 0.6rem; }
.bk-tables .checkbox-row { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.bk-tables .checkbox-chip.is-busy, .bk-tables .checkbox-chip.is-unfit { opacity: 0.6; }
.bk-tables .checkbox-chip .bk-tag { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--amber-600); }
.bk-link { align-self: flex-start; background: none; border: 0; padding: 0.2rem 0; font: inherit; font-weight: 600; color: var(--green-700); cursor: pointer; }
.bk-link:hover { text-decoration: underline; }
.bk-guest-search { position: relative; }
.bk-guest-list { position: absolute; left: 0; right: 0; top: calc(100% + 2px); z-index: 2; list-style: none; margin: 0; padding: 0.25rem; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 8px 22px rgba(0, 71, 77, 0.14); max-height: 20rem; overflow-y: auto; }
.bk-guest-list li { padding: 0.5rem 0.6rem; cursor: pointer; display: flex; flex-direction: column; gap: 0.1rem; }
.bk-guest-list li[aria-selected="true"], .bk-guest-list li:hover { background: var(--green-100); }
.bk-guest-name { font-weight: 700; }
.bk-guest-meta { font-size: 0.8rem; color: var(--muted); overflow-wrap: anywhere; }
.bk-guest-list .bk-guest-empty { cursor: default; color: var(--muted); font-size: 0.85rem; }
.bk-guest-list .bk-guest-empty:hover { background: none; }
.bk-guest-card { border: 1px solid var(--green-700); background: var(--green-100); padding: 0.7rem 0.8rem; display: flex; flex-direction: column; gap: 0.4rem; }
.bk-guest-card .bk-guest-name { color: var(--green-ink); }
.bk-guest-card .bk-guest-meta { color: var(--ink); }
.bk-guest-card-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.bk-new-guest { display: flex; flex-direction: column; gap: 0.6rem; }
.bk-new-guest label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; font-weight: 600; }
.bk-lookalike { background: var(--blue-100); color: var(--blue-600); padding: 0.6rem 0.75rem; font-size: 0.85rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.bk-lookalike span { flex: 1 1 12rem; }
.bk-check { font-size: 0.88rem; margin-top: 0.35rem; }
.bk-datebar { display: flex; align-items: center; gap: 0.5rem; }
.bk-datebar input { flex: 1; text-align: center; }
.bk-datebar-label { margin: -0.6rem 0 0; text-align: center; font-weight: 700; }
.bk-slots { display: flex; flex-direction: column; gap: 0.6rem; }
.bk-slot-group { border: 1px solid var(--line); }
.bk-slot-group > summary { cursor: pointer; padding: 0.65rem 0.8rem; font-weight: 600; font-size: 0.9rem; }
.bk-slot-group > summary:focus-visible { outline: 2px solid var(--green-700); outline-offset: -2px; }
.bk-slot-group.is-closed > summary { color: var(--muted); background: var(--cream); }
.bk-slot-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.45rem; padding: 0.3rem 0.8rem 0.8rem; }
.bk-slot { font: inherit; font-size: 0.85rem; font-weight: 600; padding: 0.55rem 0.2rem; border-radius: 8px; border: 1px solid #e3e8e8; background: #eef1f1; color: var(--ink); cursor: pointer; display: flex; flex-direction: column; align-items: center; line-height: 1.15; }
.bk-slot:hover { border-color: var(--green-700); }
.bk-slot small { font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--amber-600); }
.bk-slot.is-full, .bk-slot.is-past, .bk-slot.is-outside { background: var(--surface); color: var(--muted); border-style: dashed; }
.bk-slot[aria-pressed="true"] { background: var(--green-900); border-color: var(--green-ink); border-style: solid; color: white; }
.bk-slot[aria-pressed="true"] small { color: white; }
.bk-slot[disabled] { opacity: 0.45; cursor: not-allowed; text-decoration: line-through; }
.bk-slot-note { margin: 0; font-size: 0.82rem; color: var(--amber-600); }
.bk-drawer .is-loading { opacity: 0.55; pointer-events: none; }
/* Wide screens keep the whole Parties list in view beside the drawer
   rather than under it. */
@media (min-width: 1100px) {
  body.bk-drawer-open .app-main { margin-right: 420px; }
}
@media (max-width: 480px) {
  .bk-drawer { width: 100%; border-left: 0; }
  .bk-slot-grid { gap: 0.35rem; padding: 0.3rem 0.5rem 0.6rem; }
  .bk-when { grid-template-columns: 1fr; }
}

/* ---------- Softer corners and gold (October 2026) ----------
   Jamie: "a lot of the boxes like 'add a walk in' 'seat' etc are very sharp,
   can you make them all a bit softer and also add some gold in the overall
   theme of the page and show me what that would look like in a preview
   before deciding what to do?"

   At the end of the file on purpose, so it overrides the square corners
   set throughout everything above. Two parts:
   softer corners (controls 6px, cards 10px, badges fully round — full-height
   panels like the sidebar and booking drawer stay square), and gold as an
   accent rather than a second main colour. */

:root {
  --gold-500: #c9a24a;
  --gold-300: #e3c77d;
  --gold-100: #f7efdc;
  --radius-sm: 6px;
  --radius-lg: 10px;
}

/* ---------- Softer corners ---------- */

/* Buttons, fields and the small things you press. */
.btn, .link-btn, .time-input-inline,
input:not([type="checkbox"]):not([type="radio"]), select, textarea,
.status-select, .view-bar select, .view-bar-search,
.nav-link, .pill-tab, .chip-filter-btn, .checkbox-chip, .slot-btn,
.bk-slot, .bk-time-btn, .bk-icon-btn, .clock-btn, .chip-edit-btn,
.shift-chip, .event-chip, .leave-chip, .todo-item a,
.sidebar-add-btn, .sidebar-link, .sidebar-nav-heading, .sidebar-venue, .sidebar-logout-btn {
  border-radius: var(--radius-sm);
}

/* Cards, panels and messages. */
.card, .form-card, .fieldset, .settings-card, .auth-card, .demo-box,
.party-card, .info-box, .flash, .install-tip, .event-mode-card,
.booking-card, .booking-summary, .legal-card, .allergen-card,
.feature-toggle, .view-bar, .stat-tile, .covers-summary-chip,
.material-tile, .availability-day, .chat-panel {
  border-radius: var(--radius-lg);
}

/* Labels: fully round. */
.badge, .allergen-pill, .avail-tag, .material-ai-badge,
.dept-badge-0, .dept-badge-1, .dept-badge-2, .dept-badge-3,
.dept-badge-4, .dept-badge-5, .dept-badge-6, .dept-badge-7 {
  border-radius: 999px;
}

/* The planner's bookings and the floor plan's tables: just off square. */
.pl-block { border-radius: 4px; }
.fp-shape-square, .fp-shape-rect, .fp-shape-bench { border-radius: var(--radius-sm); }

/* ---------- Gold ---------- */

/* The sidebar: the main button gold, the page you're on marked in gold,
   and the section headings a soft gold rather than grey. */
/* Text on gold is a shade darker than --green-900 (#00474d was 4.36:1 on
   the gold, just under WCAG AA's 4.5; #00353a is 5.6:1). */
.sidebar-add-btn { background: var(--gold-500); color: #00353a; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); }
.sidebar-add-btn:hover { background: var(--gold-300); }
.sidebar-add-btn-secondary { background: none; color: white; border-color: rgba(227, 199, 125, 0.6); box-shadow: none; }
.sidebar-add-btn-secondary:hover { background: rgba(227, 199, 125, 0.14); }
.sidebar-link.active { box-shadow: inset 4px 0 0 var(--gold-500); }
.sidebar-nav-heading { color: rgba(227, 199, 125, 0.8); }
.sidebar-nav-heading:hover { color: var(--gold-300); }
.sidebar-footer { border-top-color: rgba(227, 199, 125, 0.3); }

/* A short gold rule under each page's title, in the staff app. */
.app-main .content h1::after {
  content: '';
  display: block;
  width: 2.5rem;
  height: 3px;
  margin-top: 0.4rem;
  border-radius: 2px;
  background: var(--gold-500);
}

/* Figure tiles: a gold line across the top (the coloured ones keep theirs). */
.stat-tile:not(.stat-tile-green):not(.stat-tile-amber):not(.stat-tile-blue):not(.stat-tile-violet) { border-top-color: var(--gold-500); }

/* The booking drawer's tab you're on. */
.bk-tabs [role="tab"][aria-selected="true"] { border-bottom-color: var(--gold-500); }

/* Jamie: "make the main buttons gold too." The staff app's main buttons
   (Seat, Save, Create booking, + Add a party…) and the booking drawer's,
   gold with the dark teal for the text. Guest booking pages keep the
   venue's own colour. */
.app-main .btn-primary, .bk-drawer .btn-primary { background: var(--gold-500); border-color: var(--gold-500); color: #00353a; }
.app-main .btn-primary:hover, .bk-drawer .btn-primary:hover { background: var(--gold-300); border-color: var(--gold-300); }
.app-main .btn-primary:focus-visible, .bk-drawer .btn-primary:focus-visible { outline: 2px solid var(--green-900); outline-offset: 2px; }

/* ======================================================================
   Dark pages (Settings → Branding → "Light or dark pages").
   Jamie, October 2026: "Give pubsuite tenants the option of a dark theme
   in branding. The white will be too bright for some people."

   lib/layout.js puts data-theme="dark" on <html> for a venue on dark pages
   and writes the venue's own colour out as the dark-page ramp (lighter
   links, a deep tint, pale brand-coloured text — lib/theme.js shadesFor).
   This block swaps the page, cards, fields and the pale status tints for
   dark ones and lightens the text that sits on them; the venue's colour
   still fills the menu, top bar and primary buttons exactly as on light
   pages. Screen only: a dark-page venue still prints on white.
   ====================================================================== */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;
    --cream: #121a1b;
    --surface: #1b2426;
    --surface-2: #283436;
    --ink: #e4ebeb;
    --muted: #9db0b0;
    --line: #2f3d3f;
    /* The default colour's dark-page ramp (lib/theme.js shadesFor(…, 'dark'));
       lib/layout.js writes the venue's own over these. */
    --green-700: #47c6d1;
    --green-100: #214245;
    --green-ink: #9cd9de;
    --amber-500: #d9a24a;
    --amber-600: #e6bd6a;
    --amber-100: #3a2d12;
    --red-500: #f0897c;
    --red-100: #3d1e1a;
    --blue-100: #1b2a40;
    --blue-600: #7fb0ff;
    --violet-100: #2d1f35;
    --violet-700: #d4a6ea;
    --gold-100: #3a3118;
    --dept-0-bg: #214245; --dept-0-fg: #9cd9de;
    --dept-1-bg: #3a2d12; --dept-1-fg: #e6bd6a;
    --dept-2-bg: #232a4a; --dept-2-fg: #aab4f0;
    --dept-3-bg: #3d1e1a; --dept-3-fg: #f0897c;
    --dept-4-bg: #1b3634; --dept-4-fg: #8fd6c8;
    --dept-5-bg: #2d1f35; --dept-5-fg: #d4a6ea;
    --dept-6-bg: #3b2a14; --dept-6-fg: #f0b070;
    --dept-7-bg: #2a3336; --dept-7-fg: #b6c3c8;
  }

  /* The menu's current page and the venue switcher's current venue: a
     white pill on the brand colour is the one bright thing left on a dark
     page, so they become a soft highlight with white text instead. */
  :root[data-theme="dark"] .sidebar-link.active,
  :root[data-theme="dark"] .nav-link.active,
  :root[data-theme="dark"] .brand-switch-current,
  :root[data-theme="dark"] .brand-switch-current:hover,
  :root[data-theme="dark"] .brand-switch-current:focus { background: rgba(255, 255, 255, 0.16); color: white; }
  /* "+ Add a party" keeps its white face (it is the menu's main button) and
     so keeps the dark brand colour for its text. */
  :root[data-theme="dark"] .sidebar-add-btn { background: white; color: var(--green-900); }
  :root[data-theme="dark"] .sidebar-add-btn:hover { background: #e6eeee; }
  :root[data-theme="dark"] .sidebar-add-btn-secondary { background: none; color: white; }
  :root[data-theme="dark"] .sidebar-add-btn-secondary:hover { background: rgba(255, 255, 255, 0.12); }

  /* Hovers and tints that were hardcoded pale. */
  :root[data-theme="dark"] .btn:hover { background: var(--surface-2); }
  :root[data-theme="dark"] .link-btn-plain:hover { background: var(--green-100); border-color: var(--green-100); color: var(--green-ink); filter: brightness(1.3); }
  :root[data-theme="dark"] .link-btn-danger:hover { background: var(--red-100); border-color: var(--red-100); color: var(--red-500); filter: brightness(1.3); }
  :root[data-theme="dark"] .shift-chip.draft { background: var(--surface-2); }
  :root[data-theme="dark"] .pl-completed { background: var(--surface-2); }
  :root[data-theme="dark"] .rota-cell-unavailable { background: #2e1f1d; }
  :root[data-theme="dark"] .check-entry-problem td { background: #2e1f1d; }
  :root[data-theme="dark"] .matrix-row-incomplete { background: #2e2816; }
  :root[data-theme="dark"] .chat-msg-error { background: var(--red-100); color: var(--red-500); }
  :root[data-theme="dark"] .bk-slot { border-color: var(--line); background: var(--surface-2); }
  :root[data-theme="dark"] .time-input-inline { border-color: var(--line); }
  :root[data-theme="dark"] .flash-info { color: var(--blue-600); }
  :root[data-theme="dark"] .color-swatch input:checked + .color-swatch-visual { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--ink); }
  :root[data-theme="dark"] .donut-segments path { stroke: var(--surface); }
  :root[data-theme="dark"] .sparkline circle { stroke: var(--surface); }
  :root[data-theme="dark"] .pl-nowline-label { color: var(--cream); }
  :root[data-theme="dark"] .visit-badge { color: #0d1a0f; }
  :root[data-theme="dark"] .stat-tile-green .num { color: #3fd49a; }
  :root[data-theme="dark"] .stat-tile-amber .num { color: #e6bd6a; }
  :root[data-theme="dark"] .stat-tile-blue .num { color: #7fb0ff; }
  :root[data-theme="dark"] .stat-tile-violet .num { color: #b7a6f5; }

  /* Fills that are lighter on dark pages (amber, the mid brand shade) take
     dark text instead of white. */
  :root[data-theme="dark"] .btn-amber,
  :root[data-theme="dark"] .event-chip:hover,
  :root[data-theme="dark"] .clock-btn.out { color: #1a1205; }
  :root[data-theme="dark"] .clock-btn.out:hover { background: var(--amber-500); }
  :root[data-theme="dark"] .shift-chip.shift-chip-approved { color: #0b1a1b; }
  :root[data-theme="dark"] .app-main .btn-primary:focus-visible,
  :root[data-theme="dark"] .bk-drawer .btn-primary:focus-visible { outline-color: var(--green-700); }
}
