: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;
  --amber-600: #9c6f2f;
  --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: 4px;
  --shadow: 0 2px 10px rgba(0, 71, 77, 0.12);

  /* 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; }
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; }
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: #eee; padding: 0.1rem 0.35rem; border-radius: 2px; 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; box-shadow: var(--shadow); }
.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;
}
.brand-suffix { font-weight: 400; opacity: 0.75; }
.brand-logo { height: 34px; width: 34px; border-radius: 3px; object-fit: cover; flex-shrink: 0; }
.brand-title .brand-logo { height: 64px; width: 64px; border-radius: 14px; }
.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: 3px; 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-900); padding: 0.35rem 0.7rem; border-radius: 4px; 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-900); }
.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: 4px; padding: 0.15rem 0.3rem; font-size: 0.85rem; font-family: inherit; color: inherit; background: white; 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: 4px; font-size: 0.88rem; white-space: nowrap; flex-shrink: 0; }
.nav-link.active { background: white; color: var(--green-900); 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;
}
.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; }
/* "+ 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: white; color: var(--green-900); font-weight: 700; font-size: 0.9rem;
  padding: 0.6rem 0.5rem; border-radius: 4px; 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); }
.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: 4px; }
.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: 4px; font-size: 0.92rem; white-space: nowrap; }
.sidebar-link.active { background: white; color: var(--green-900); font-weight: 600; }
.sidebar-link:hover:not(.active) { background: rgba(255,255,255,0.1); }
.sidebar-icon { font-size: 1.05rem; width: 1.2rem; text-align: center; flex-shrink: 0; }
.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: 4px; }
.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: 4px; 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) {
  .app-shell { flex-direction: column; }
  .sidebar { width: 100%; height: auto; position: static; padding: 0.75rem 1rem; }
  .sidebar-brand { padding: 0.3rem 0.5rem 0.6rem; }
  .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: 999px; 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; }
@media (max-width: 640px) { .grid-2 { grid-template-columns: 1fr; } }

.form-card { background: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: var(--radius); 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; }
.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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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(140px, 1fr)); gap: 0.75rem; }
.stat-tile { background: var(--green-100); border-radius: var(--radius); padding: 1rem; }
.stat-tile .num { font-size: 1.6rem; font-weight: 700; color: var(--green-900); }
.stat-tile .label { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }

/* ---------- Buttons & forms ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; padding: 0.6rem 1.1rem; border-radius: 4px; border: 1px solid var(--line); background: white; 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-900); }
.btn-primary:hover { background: var(--green-700); }
.btn-secondary { background: var(--green-100); color: var(--green-900); border-color: var(--green-100); }
.btn-secondary:hover { background: #c8e6e8; }
.btn-ghost { background: none; border-color: var(--line); }
.btn-amber { background: var(--amber-500); color: white; border-color: var(--amber-500); }
.btn-amber:hover { background: var(--amber-600); }
.btn-danger { background: white; 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: 4px; border: 1px solid var(--line); background: white; 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-900); border-radius: var(--radius); 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-900); cursor: pointer; padding: 0.25rem; }

/* ---------- Flash / badges ---------- */
.flash { padding: 0.75rem 1rem; border-radius: 4px; margin-bottom: 1rem; font-size: 0.92rem; }
.flash-success { background: var(--green-100); color: var(--green-900); }
.flash-error { background: var(--red-100); color: var(--red-500); }
.flash-info { background: var(--blue-100); color: var(--blue-600); }
.flash-warning { background: #fdf1de; color: var(--amber-600); }

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

/* ---------- Auth page ---------- */
.auth-wrap { display: flex; justify-content: center; padding-top: 2rem; }
.auth-card { background: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: 4px; 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-900); margin-bottom: 0.25rem; font-variant-numeric: tabular-nums; }
.clock-btn {
  width: 180px;
  height: 180px;
  border-radius: 20px;
  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-500); }
.clock-btn.out:hover { background: var(--amber-600); }
.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; }

/* ---------- 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: white; border-radius: var(--radius); box-shadow: var(--shadow); border: 1px solid var(--line); border-spacing: 0; overflow: hidden; }
.data-table th { background: var(--green-100); }
.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: 4px; font-size: 0.82rem; font-weight: 600; background: white; color: var(--muted); border: 1px solid var(--line); }
.pill-tab.active { background: var(--green-900); color: white; border-color: var(--green-900); }
.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-900); }
.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: 4px; 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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: 3px; border: 1px solid var(--line); background: white; 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: 4px; 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: 4px; 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: white; border: 1px solid var(--line); border-radius: 999px; 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: 999px; 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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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-900); 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: 999px; 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-900); }
.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: 50%; 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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: 4px; overflow: hidden; background: var(--cream); display: flex; flex-direction: column; }
.material-thumb { width: 100%; height: 100px; object-fit: cover; background: white; 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: 4px; 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: 4px; 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; }

/* ---------- 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: var(--radius);
  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: var(--radius);
}
.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-900);
  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;
  box-shadow: var(--shadow);
}
.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: 4px; }
.fp-shape-rect { width: clamp(48px, 9.2cqw, 92px); height: clamp(30px, 5.8cqw, 58px); border-radius: 4px; }
.fp-shape-bench { width: clamp(56px, 11.6cqw, 116px); height: clamp(26px, 4.4cqw, 44px); border-radius: 4px; }
.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-900); }
.fp-status-inuse { background: #fdf1de; 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: 50%; 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-900); 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: var(--radius); 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: #fdf1de; 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: var(--radius); background: white; box-shadow: var(--shadow); }
.pl-inner { position: relative; display: flex; flex-direction: column; }

.pl-ruler-row { display: flex; height: 34px; position: sticky; top: 0; z-index: 3; background: white; 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: white;
  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; }

/* 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: 3px; border: 1px solid var(--line); box-shadow: var(--shadow);
  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; }
.pl-block-name { font-size: 0.72rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.25; }
.pl-block-meta { font-size: 0.64rem; opacity: 0.85; white-space: nowrap; line-height: 1.2; }

.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: 2px; 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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: var(--radius); }
.widget-qr img { display: block; image-rendering: pixelated; border-radius: 2px; }
.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: white; border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.5rem; margin-bottom: 1rem; border: 1px solid var(--line); }
.booking-card h1 { font-size: 1.3rem; }
.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: 4px; border: 1px solid var(--green-700); background: var(--green-100); color: var(--green-900); 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: 999px; background: #fdf1de; 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-500); color: white; }
.event-chip .muted { color: inherit; opacity: 0.75; font-weight: 500; }
.booking-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.75rem; background: var(--cream); border-radius: var(--radius); 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: var(--radius); padding: 0.75rem; }
.availability-day-head { font-weight: 700; margin-bottom: 0.5rem; }
.avail-tag { font-size: 0.72rem; font-weight: 700; border-radius: 2px; 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-900); }
.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: 3px; 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: 4px; 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: #fdf1de; color: var(--amber-600); }
.open-shifts-row td:first-child { border-left: 4px solid var(--amber-500); }
.open-shift-chip { background: #fdf1de; 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-900);
  border-radius: 3px;
  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-copy-btn {
  flex-shrink: 0;
  width: 1.4rem;
  border: none;
  border-radius: 3px;
  background: var(--green-100);
  color: var(--green-700);
  cursor: pointer;
  font-size: 0.8rem;
}
.chip-copy-btn:hover { background: var(--green-900); color: white; }
.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-900); border-radius: var(--radius); 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: #fdf1de; margin: 0 -0.6rem; padding: 0.6rem; border-radius: 2px; 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: 16px; border: none;
  background: var(--green-900); color: white; font-size: 1.4rem; line-height: 1;
  box-shadow: var(--shadow); 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: white; border-radius: var(--radius); box-shadow: var(--shadow); 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: 4px; 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: 50%;
  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: 999px; 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,
  .paste-shift-btn,
  .row-drag-handle,
  .chat-widget {
    display: none !important;
  }
  body { background: white; }
  .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: #eee; -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; }
}

/* 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: 999px; height: 9px; overflow: hidden; margin-top: 0.35rem; }
.meter-fill { background: var(--green-900); height: 100%; border-radius: 999px; }
.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-900); border-radius: var(--radius); padding: 0.75rem 0.9rem; font-size: 0.85rem; margin-bottom: 1rem; }
.invoice-photo-preview { max-width: 100%; border-radius: var(--radius); 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: 50%; 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: 4px; background: var(--cream); padding: 0.4rem; border: 1px solid var(--line); }
