/* Fort Fareham Garage — admin styles. Modern, dense, businesslike.
 * Builds on the public-site tokens but adds an admin chrome of its own. */

/* Self-hosted Inter (variable, weights 100-900) — replaces the Google Fonts
 * CDN <link> on every admin page. Google Fonts' CSS rotates, so SRI isn't
 * possible there; self-hosting removes the third-party dependency entirely
 * (LOW sweep, 2026-05-30). Same font/weights as before — rendering unchanged. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter/InterVariable.woff2') format('woff2');
}

:root {
  /* Admin is light-only — don't follow OS/Chrome dark mode. */
  color-scheme: light;
  /* Force form controls to brand blue — without this the user's installed
   * Chrome theme (e.g. pink) paints every checkbox / radio / range slider. */
  accent-color: #0e1ea0;

  --adm-bg:        #f5f6f9;
}
/* Defensive baseline: any input/select/textarea not styled by .adm-form still
 * gets a white background so Chrome's user theme can't tint it. */
body.admin input, body.admin select, body.admin textarea {
  background-color: #fff;
  color: var(--adm-text);
}
:root {
  --adm-surface:   #ffffff;
  --adm-border:    #e2e6ee;
  --adm-text:      #1f2937;
  --adm-muted:     #6b7280;
  --adm-blue:      #0e1ea0;    /* same brand blue as public site */
  --adm-blue-dark: #0a1577;
  --adm-blue-tint: #eef0ff;
  --adm-green:     #059669;
  --adm-green-tint:#d1fae5;
  /* "amber" is kept as a variable name for code-history reasons but the
   * actual hue is now sky/teal — Annie didn't want any yellow on the site.
   * Used for in-progress, warnings, and other "active intermediate" states. */
  --adm-amber:     #0284c7;     /* sky-600 */
  --adm-amber-tint:#e0f2fe;     /* sky-100 */
  --adm-red:       #dc2626;
  --adm-red-tint:  #fee2e2;
  --adm-radius:    8px;
  --adm-radius-sm: 4px;
  /* Layered shadow stack — bumped from the v1 values so cards/buttons feel
   * "lifted" off the page rather than painted on. Annie thought the admin
   * looked plain; depth is the cheapest fix.
   *   adm-shadow-1: resting state (subtle but visible)
   *   adm-shadow-2: hover / focused state (more lift)
   *   adm-shadow-3: floating overlays (modals, popovers) */
  --adm-shadow-1:  0 1px 2px rgba(15, 23, 42, .06),
                   0 2px 6px rgba(15, 23, 42, .08),
                   inset 0 1px 0 rgba(255, 255, 255, .6);
  --adm-shadow-2:  0 2px 6px rgba(15, 23, 42, .08),
                   0 12px 28px rgba(15, 23, 42, .12),
                   inset 0 1px 0 rgba(255, 255, 255, .7);
  --adm-shadow-3:  0 8px 16px rgba(15, 23, 42, .12),
                   0 24px 48px rgba(15, 23, 42, .18);
  /* Soft surface gradient — applied to .card, .adm-panel, .side-panel so
   * surfaces look lit-from-above instead of flat white. */
  --adm-surface-gradient: linear-gradient(180deg, #ffffff 0%, #f9fafd 100%);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; min-height: 100%; }
body.admin {
  background: var(--adm-bg);
  color: var(--adm-text);
  font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
  /* Annie asked for easier-to-read fonts across the admin — bumped the
   * base from 13.5px to 15px with a roomier line-height. Component-level
   * sizes scale automatically from these tokens. */
  font-size: 15px;
  line-height: 1.55;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
body.admin a { color: var(--adm-blue); text-decoration: none; }
body.admin a:hover { text-decoration: underline; }

/* ===== Top bar ===== */
.adm-topbar {
  position: sticky; top: 0; z-index: 50;
  background: linear-gradient(180deg, #ffffff 0%, #f5f7fb 100%);
  border-bottom: 1px solid var(--adm-border);
  padding: 0 1.5rem;
  height: 56px;
  display: flex; align-items: center; gap: 1.5rem;
  /* Soft drop shadow + faint top highlight = "ribbon" floats above content */
  box-shadow: 0 1px 0 rgba(15, 23, 42, .04),
              0 4px 12px rgba(15, 23, 42, .06);
}
.adm-topbar .adm-brand {
  display: flex; align-items: center; gap: .6rem;
  font-weight: 700; color: var(--adm-blue);
  font-size: 1rem; letter-spacing: -.01em;
  white-space: nowrap;
}
.adm-topbar .adm-brand img { height: 28px; }
.adm-nav {
  /* overflow-y MUST stay visible so the pill shadows aren't clipped at the
   * top/bottom of the 56px topbar — CSS specifies overflow-y as 'visible'
   * is only honoured when overflow-x is also 'visible', so we drop the
   * old `overflow-x: auto` and let the responsive media queries handle
   * narrow viewports (compact padding + smaller fonts kick in <1100px,
   * which fits everything without horizontal scroll). */
  display: flex; gap: 4px; flex: 1; min-width: 0;
  overflow: visible;
  align-items: center;
  justify-content: center;       /* centre the pill group in the topbar */
}
.adm-nav a {
  padding: 8px 14px;
  border-radius: var(--adm-radius-sm);
  color: var(--adm-muted);
  font-weight: 500;
  white-space: nowrap;
}
.adm-nav a:hover { background: var(--adm-bg); text-decoration: none; }
.adm-nav a.is-current {
  background: var(--adm-blue-tint);
  color: var(--adm-blue);
  font-weight: 600;
}
.adm-user {
  display: flex; align-items: center; gap: .75rem;
  white-space: nowrap;
}
.adm-user .who { color: var(--adm-muted); font-size: 14px; }
.adm-user .out { color: var(--adm-muted); font-size: 14px; }
.adm-user .out:hover { color: var(--adm-red); }

/* ===== Mobile nav: hamburger + off-canvas drawer (≤1080px) =====
 * Desktop (≥1081px) keeps the pill row; below that the 13-item nav can't
 * fit any viewport without breaking, so the row + user block hide and the
 * burger/drawer take over. Markup in admin/_partials/header.php, behaviour
 * in assets/js/admin.js. */
.adm-burger {
  display: none;               /* shown ≤1080px */
  flex-direction: column; justify-content: center; gap: 4px;
  width: 40px; height: 40px;
  padding: 9px;
  background: none; border: 0; border-radius: var(--adm-radius-sm);
  cursor: pointer;
  flex-shrink: 0;
}
.adm-burger span {
  display: block; height: 2px; width: 100%;
  background: var(--adm-text); border-radius: 1px;
  transition: transform .2s ease, opacity .2s ease;
}
.adm-burger:hover { background: var(--adm-bg); }
.adm-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.adm-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.adm-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.adm-drawer-backdrop {
  position: fixed; inset: 0; z-index: 98;
  background: rgba(15, 23, 42, .45);
  opacity: 0; transition: opacity .25s ease;
}
.adm-drawer-backdrop.is-open { opacity: 1; }
.adm-drawer {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 99;
  width: min(300px, 85vw);
  background: var(--adm-surface, #fff);
  box-shadow: 4px 0 24px rgba(15, 23, 42, .18);
  transform: translateX(-100%);
  transition: transform .25s ease;
  display: flex; flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.adm-drawer.is-open { transform: translateX(0); }
/* Author display:flex above would otherwise beat the UA's [hidden]{display:none}
 * (author rules win regardless of specificity), leaving the closed drawer in
 * the tab order — restate the hidden contract explicitly. */
.adm-drawer[hidden], .adm-drawer-backdrop[hidden] { display: none; }
.adm-drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .9rem 1rem .9rem 1.25rem;
  border-bottom: 1px solid var(--adm-border);
  background: var(--adm-bg);
}
.adm-drawer-who { font-size: 14px; color: var(--adm-muted); font-weight: 600; min-width: 0; }
.adm-drawer-close {
  background: none; border: 0; cursor: pointer;
  font-size: 26px; line-height: 1; color: var(--adm-muted);
  padding: .25rem .5rem;
}
body.admin a.adm-drawer-link {
  display: flex; align-items: center; gap: .5rem;
  padding: 13px 1.25rem;
  color: var(--adm-text); font-weight: 500; font-size: 15px;
  border-bottom: 1px solid var(--adm-bg);
}
body.admin a.adm-drawer-link:hover { text-decoration: none; background: var(--adm-bg); }
body.admin a.adm-drawer-link.is-current {
  background: var(--adm-blue-tint); color: var(--adm-blue); font-weight: 600;
  box-shadow: inset 3px 0 0 var(--adm-blue);
}
/* Drawer badges sit inline after the label, not absolutely positioned. */
.adm-drawer-link .adm-nav-badge { position: static; margin-left: auto; }
body.admin a.adm-drawer-out { color: var(--adm-muted); margin-top: auto; border-top: 1px solid var(--adm-border); }
body.adm-drawer-lock { overflow: hidden; }   /* scroll lock while drawer is open */

@media (max-width: 1080px) {
  .adm-burger { display: flex; }
  .adm-topbar .adm-nav { display: none; }
  .adm-topbar .adm-user { display: none; }   /* user + sign-out live in the drawer */
}
@media (min-width: 1081px) {
  /* Belt & braces: drawer never renders on desktop even if JS left it open. */
  .adm-drawer, .adm-drawer-backdrop { display: none; }
}

/* Public-site button reset for admin */
body.admin .btn {
  display: inline-block;
  background: linear-gradient(180deg, #152dc7 0%, var(--adm-blue) 60%, var(--adm-blue-dark) 100%);
  color: #fff;
  padding: 8px 16px; border: 1px solid var(--adm-blue-dark);
  border-radius: var(--adm-radius-sm);
  font-weight: 500; font-size: 14px;
  cursor: pointer; text-decoration: none;
  text-transform: none; letter-spacing: 0;
  /* Inner highlight + drop shadow → physical "button" feel rather than flat slab */
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22),
              0 1px 2px rgba(15, 23, 42, .12),
              0 2px 6px rgba(13, 24, 111, .15);
  transition: background .12s ease, transform .08s ease, box-shadow .12s ease, border-color .12s ease;
}
body.admin .btn:hover {
  background: linear-gradient(180deg, var(--adm-blue) 0%, var(--adm-blue-dark) 100%);
  border-color: var(--adm-blue-dark);
  text-decoration: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28),
              0 2px 4px rgba(15, 23, 42, .16),
              0 6px 14px rgba(13, 24, 111, .22);
}
body.admin .btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.18);
}
body.admin .btn.ghost { background: #fff; color: var(--adm-text); border-color: var(--adm-border); }
body.admin .btn.ghost:hover { background: var(--adm-bg); border-color: var(--adm-muted); color: var(--adm-text); }
body.admin .btn.danger { background: var(--adm-red); border-color: var(--adm-red); }
body.admin .btn.danger:hover { background: #b91c1c; border-color: #b91c1c; }
body.admin .btn.sm { padding: 4px 10px; font-size: 12px; }
body.admin .btn.xs { padding: 2px 8px; font-size: 11px; border-radius: 999px; line-height: 1.4; }
body.admin .btn.danger { background: #b91c1c; border-color: #b91c1c; color: #fff; }
body.admin .btn.danger:hover { background: #991b1b; border-color: #991b1b; }
body.admin .btn.ghost.danger { background: transparent; border-color: #fecaca; color: #b91c1c; }
body.admin .btn.ghost.danger:hover { background: #fef2f2; border-color: #ef4444; color: #991b1b; }
body.admin .btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ===== Layout ===== */
.adm-main { padding: 1.5rem; max-width: 1480px; margin: 0 auto; }
.adm-page-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; margin-bottom: 1.5rem;
}
.adm-page-head h1 {
  font-size: 1.5rem; font-weight: 600; margin: 0;
  color: var(--adm-text);
}
.adm-page-head .crumbs { color: var(--adm-muted); font-size: 14px; }

/* Screen-reader-only utility (visually hidden, still announced). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}

/* ===== Cards ===== */
.card {
  background: var(--adm-surface-gradient);
  border: 1px solid var(--adm-border);
  border-radius: 12px;
  box-shadow: var(--adm-shadow-1);
  padding: 1.25rem 1.5rem;
  transition: box-shadow .18s ease, transform .18s ease;
}
.card:hover { box-shadow: var(--adm-shadow-2); }
.card + .card { margin-top: 1.25rem; }
.card h2 { font-size: 16px; font-weight: 600; margin: 0 0 1rem; }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
}
/* Inside a grid the two cards are DOM siblings, so `.card + .card`
   was firing and pushing the second column's card down 1.25rem.
   Reset it here — within a card-grid, top-alignment is handled by
   the grid itself, not by inter-card stacking margins. */
.card-grid > .card + .card { margin-top: 0; }

/* Pricing page: indented sub-rows under General Repairs that show
   each repair_categories entry — so admin sees what the customer
   sub-picker is offering without leaving Pricing. Slight tint + tree
   bullet to distinguish from top-level services. */
.pricing-repair-row {
  background: #fafbfd;
}
.pricing-repair-row td:first-child {
  padding-left: 2rem;
}
.pricing-repair-bullet {
  display: inline-block;
  color: var(--adm-muted);
  margin-right: .5rem;
  font-family: ui-monospace, 'SF Mono', monospace;
  font-size: 14px;
}
.pricing-repair-row td { font-size: 14px; }

/* Scrollable card body — used for the By-day table on the reports
   page where 200+ rows would otherwise sprawl the page. Pair with
   sticky thead so the column headers don't scroll out of view. */
.card-scroll {
  max-height: 480px;
  overflow-y: auto;
  margin: 0 -1.5rem;   /* edge-to-edge inside .card padding so the
                          scrollbar nestles against the card border */
}
.card-scroll table { margin: 0; }
.card-scroll thead th {
  position: sticky; top: 0;
  background: var(--adm-surface);
  box-shadow: inset 0 -1px 0 var(--adm-border);
  z-index: 1;
}
.stat {
  background: var(--adm-surface);
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius);
  padding: 1rem 1.25rem;
}
.stat .label { color: var(--adm-muted); font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: .04em; }
.stat .value { font-size: 1.75rem; font-weight: 700; color: var(--adm-text); margin-top: .25rem; line-height: 1.2; }
.stat .delta { font-size: 12px; color: var(--adm-muted); margin-top: .25rem; }

/* ===== Tables ===== */
.adm-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--adm-surface);
}
.adm-table th {
  text-align: left;
  font-weight: 600; font-size: 12px; text-transform: uppercase;
  color: var(--adm-muted); letter-spacing: .04em;
  padding: 10px 12px;
  border-bottom: 1px solid var(--adm-border);
  background: var(--adm-bg);
}
.adm-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--adm-border);
  vertical-align: top;
}
.adm-table tr:hover td { background: #fbfbfd; }
.adm-table .actions { white-space: nowrap; text-align: right; }
.adm-table .muted { color: var(--adm-muted); font-size: 14px; }

/* ===== Forms (admin) — condensed for high-density data entry ===== */
.adm-form .row { margin-bottom: .65rem; }
.adm-form label {
  display: block; font-weight: 500; font-size: 12px;
  color: #4b5563; margin-bottom: 3px;
  letter-spacing: .01em;
}
.adm-form input:not([type]), .adm-form input[type=text], .adm-form input[type=email],
.adm-form input[type=password], .adm-form input[type=number], .adm-form input[type=tel],
.adm-form input[type=date], .adm-form input[type=time], .adm-form select, .adm-form textarea {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font: inherit;
  font-size: 14px; line-height: 1.4;
  background: #fff;
  -webkit-font-smoothing: antialiased;
}
.adm-form input:focus, .adm-form select:focus, .adm-form textarea:focus {
  outline: 2px solid var(--adm-blue);
  outline-offset: -1px; border-color: var(--adm-blue);
}
.adm-form .grid { display: grid; gap: .65rem 1rem; grid-template-columns: 1fr 1fr; }
.adm-form .grid .full { grid-column: 1 / -1; }
@media (max-width: 700px) { .adm-form .grid { grid-template-columns: 1fr; } }
.adm-form .help { color: var(--adm-muted); font-size: 12px; margin-top: 4px; }
.adm-form fieldset {
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius);
  padding: .85rem 1.1rem;     /* was 1rem 1.25rem */
  background: var(--adm-surface);
}
.adm-form fieldset legend {
  font-weight: 600; font-size: 11px;     /* was 13px */
  color: var(--adm-muted); text-transform: uppercase; letter-spacing: .05em;
  padding: 0 .4rem;
}
.adm-check {
  display: flex; align-items: center; gap: .5rem;
  padding: 6px 10px;
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  background: #fff;
  cursor: pointer;
}
.adm-check:hover { border-color: var(--adm-blue); }
.adm-check input { width: auto !important; flex: 0 0 auto; }
.adm-check input:checked + span { font-weight: 600; }
.adm-check span:last-child { color: var(--adm-muted); font-size: 11px; margin-left: auto; }
.mot-soon { color: #0369a1 !important; font-weight: 600; }

/* Customers table: checkbox column + per-row action pills + bulk-action bar */
.customers-table .cb-col {
  width: 32px; text-align: center; padding-left: 12px; padding-right: 4px;
}
.customers-table .cb-col input { vertical-align: middle; cursor: pointer; }
.customers-table .row-actions {
  white-space: nowrap;
  display: flex; gap: 4px; justify-content: flex-end;
  padding-right: 12px;
}
.customers-table tr.is-archived td {
  color: var(--adm-muted);
  background: #fafafa;
}
.customers-table tr.is-archived td strong { color: var(--adm-muted); }

.bulk-bar {
  position: sticky; bottom: 12px;
  margin-top: 1rem;
  background: var(--adm-blue-dark);
  color: #fff;
  border-radius: var(--adm-radius);
  box-shadow: var(--adm-shadow-2);
  padding: 8px 16px;
  display: flex; align-items: center; gap: .5rem;
  z-index: 50;
}
.bulk-bar[hidden] { display: none; }
.bulk-bar .bulk-count {
  font-weight: 600;
  margin-right: .5rem;
}
.bulk-bar .btn {
  background: #fff;
  border-color: #fff;
  color: var(--adm-blue-dark);
}
.bulk-bar .btn.ghost {
  background: transparent;
  border-color: rgba(255,255,255,.4);
  color: #fff;
}
.bulk-bar .btn.danger {
  background: #dc2626; border-color: #dc2626; color: #fff;
}
.bulk-bar a.btn { text-decoration: none; }

/* Customer history page: each vehicle is a card containing a bookings table */
.history-vehicle { padding: 1.25rem 1.5rem; }
.history-vehicle-head { margin-bottom: 1rem; padding-bottom: .75rem; border-bottom: 1px solid var(--adm-border); }
.history-vehicle-head h2 { margin: 0 0 .25rem; font-size: 18px; }
.history-bookings { width: 100%; }
.history-bookings td, .history-bookings th { padding: 8px 12px; }
.history-bookings .actions { text-align: right; }

.pricing-grid {
  width: 100%; border-collapse: collapse;
  font-size: 14px;
}
.pricing-grid th, .pricing-grid td {
  padding: 6px 8px;
  border: 1px solid var(--adm-border);
  text-align: center;
}
.pricing-grid thead th { background: var(--adm-bg); font-weight: 600; }
.pricing-grid tbody th { background: var(--adm-bg); text-align: left; font-weight: 600; }
.pricing-grid td input {
  width: 100%;
  text-align: right;
  padding: 6px 8px !important;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.pricing-grid thead th, .pricing-grid tbody th { font-size: 12px; padding: 6px 8px; white-space: nowrap; }

/* Wide variant of the side panel — used by the pricing editor so the
   4x4 grid has room to breathe. */
.side-panel.wide { max-width: 640px; }
@media (max-width: 720px) { .side-panel.wide { max-width: 100%; } }

/* Service sheets */
.sheet-section legend { font-size: 14px; }
.sheet-row {
  display: grid;
  grid-template-columns: 1fr 220px 1fr;
  gap: .75rem;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px dashed var(--adm-border);
}
.sheet-row:last-child { border-bottom: 0; }
.sheet-label { font-weight: 500; font-size: 14px; }
.sheet-note { font-size: 13px !important; }

/* Photo uploader per sheet item — fills the full row width via grid-column. */
.sheet-photos {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .35rem;
}
.sheet-photo-strip {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.sheet-photo-tile {
  position: relative;
  width: 80px; height: 80px;
  border-radius: 6px; overflow: hidden;
  border: 1px solid var(--adm-border);
  background: #f3f4f6;
}
.sheet-photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sheet-photo-del {
  position: absolute; top: 2px; right: 2px;
  width: 22px; height: 22px;
  border-radius: 50%; border: 0;
  background: rgba(15,23,42,.78); color: #fff;
  font-size: 14px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}
.sheet-photo-del:hover { background: #b91c1c; }
.sheet-photo-add {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 80px; height: 80px; padding: 0 14px;
  border: 2px dashed var(--adm-border); border-radius: 6px;
  cursor: pointer; color: var(--adm-muted); font-size: 12px; font-weight: 500;
  background: #f9fafb;
  transition: border-color .12s ease, color .12s ease;
}
.sheet-photo-add:hover { border-color: var(--adm-blue); color: var(--adm-blue); }
.sheet-photo-add.is-uploading { border-style: solid; color: var(--adm-blue); }
@media (max-width: 740px) {
  .sheet-row { grid-template-columns: 1fr; gap: .5rem; }
  .sheet-label { font-size: 15px; font-weight: 600; }
}
.sheet-severity { display: flex; gap: .25rem; flex-wrap: wrap; }
.sev {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 4px;
  padding: 8px 12px;
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  font-size: 14px; font-weight: 500;
  background: #fff; cursor: pointer; user-select: none;
  min-width: 56px;
}
.sev input { display: none; }
.sev.sev-satisfactory.is-checked { background: var(--adm-green-tint); border-color: var(--adm-green); color: #064e3b; }
.sev.sev-monitoring.is-checked   { background: var(--adm-amber-tint); border-color: var(--adm-amber); color: #075985; }
.sev.sev-urgent.is-checked       { background: var(--adm-red-tint);   border-color: var(--adm-red);   color: #7f1d1d; }
.sev.sev-clear.is-checked        { background: var(--adm-bg); border-color: var(--adm-border-strong); }
.sheet-tread { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .5rem; }
.sheet-tread label { display: flex; flex-direction: column; gap: 2px; }

/* ===== Status pills ===== */
.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  background: var(--adm-bg);
  color: var(--adm-muted);
}
.pill.confirmed                  { background: var(--adm-blue-tint);  color: var(--adm-blue); }
/* Booking status palette — Rich's high-contrast spec (2026-05-18) */
.pill.onsite                     { background: #fcb900; color: #000; }
.pill.in_progress                { background: #6d28d9; color: #fff; }
.pill.completed                  { background: #22c55e; color: #000; }
.pill.customer_called_to_collect { background: #0E1EA0; color: #fff; }
.pill.collected                  { background: #991b1b; color: #fff; }
.pill.cancelled                  { background: var(--adm-red-tint); color: var(--adm-red); }
.pill.no_show                    { background: #111827; color: #fff; font-weight: 700; }
.pill.mot                      { background: #e0e7ff;               color: #3730a3; }
.pill.service                  { background: var(--adm-green-tint); color: var(--adm-green); }
.pill.forecourt                { background: var(--adm-amber-tint); color: var(--adm-amber); }

/* ===== Login page ===== */
.adm-login-shell {
  min-height: 100vh;
  display: grid; place-items: center;
  padding: 2rem;
  background: linear-gradient(135deg, #f5f6f9 0%, #e8eaf3 100%);
}
.adm-login-card {
  width: 100%;
  max-width: 420px;
  background: #fff;
  border-radius: 14px;
  border: 1px solid var(--adm-border);
  padding: 2.5rem 2.25rem;
  box-shadow: 0 4px 12px rgba(0,0,0,.08), 0 20px 48px rgba(0,0,0,.12);
  text-align: center;
}
.adm-login-card .logo { display: block; margin: 0 auto 1rem; height: 56px; width: auto; }
.adm-login-card h1 { font-size: 1.4rem; font-weight: 700; margin: 0 0 .25rem; }
.adm-login-card .sub { color: var(--adm-muted); margin: 0 0 1.5rem; font-size: 14px; }
.adm-login-card .adm-form .row { text-align: left; }
.adm-login-card .btn { width: 100%; padding: 12px; font-size: 14px; }
.adm-login-card .qr { display: block; margin: 1rem auto; max-width: 220px; width: 100%; }
.adm-login-card .secret-text {
  display: inline-block;
  font-family: ui-monospace, 'SF Mono', monospace;
  padding: .5rem .75rem;
  background: var(--adm-bg);
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  word-break: break-all;
  letter-spacing: 1px;
  font-size: 14px;
}
.adm-login-card .totp-input {
  font-family: ui-monospace, 'SF Mono', monospace;
  font-size: 1.6rem; letter-spacing: 8px;
  text-align: center;
}
.adm-login-card .backup-codes {
  display: grid; grid-template-columns: 1fr 1fr; gap: .5rem;
  font-family: ui-monospace, 'SF Mono', monospace; font-size: 14px;
  text-align: center; margin: 1rem 0;
}
.adm-login-card .backup-codes code {
  display: block; padding: .5rem; background: var(--adm-bg);
  border: 1px solid var(--adm-border); border-radius: var(--adm-radius-sm);
}

/* ===== Alerts ===== */
.alert {
  padding: 10px 14px;
  border-radius: var(--adm-radius-sm);
  margin-bottom: 1rem;
  font-size: 14px;
  border-left: 3px solid;
}
.alert.error { background: var(--adm-red-tint);   border-color: var(--adm-red);   color: #7f1d1d; }
.alert.ok    { background: var(--adm-green-tint); border-color: var(--adm-green); color: #064e3b; }
.alert.warn  { background: var(--adm-amber-tint); border-color: var(--adm-amber); color: #075985; }
.alert.info  { background: var(--adm-blue-tint);  border-color: var(--adm-blue);  color: var(--adm-blue-dark); }

/* ===== Diary ===== */
.diary-toolbar {
  display: flex; align-items: center; gap: .75rem;
  margin-bottom: 1rem; flex-wrap: wrap;
}
.diary-toolbar .nav-arrow {
  width: 32px; height: 32px;
  display: inline-grid; place-items: center;
  background: #fff; border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  font-size: 16px; color: var(--adm-text);
}
.diary-toolbar .date-picker {
  font-weight: 600; font-size: 1rem;
  padding: 6px 12px;
  border: 1px solid var(--adm-border); border-radius: var(--adm-radius-sm);
  background: #fff;
}
/* Big day label next to the date picker — Annie wants it readable across
   the room. Roughly double the old .muted.small size. */
.diary-toolbar .diary-day-label {
  font-size: 1.6rem; font-weight: 700;
  color: var(--adm-text);
  letter-spacing: .2px;
  line-height: 1.1;
}
.diary-grid {
  display: grid;
  grid-template-columns: 60px 1fr 1fr;
  gap: 0;
  background: var(--adm-surface);
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius);
  overflow: hidden;
}
.diary-grid .col-head {
  padding: 10px;
  background: var(--adm-bg);
  border-bottom: 1px solid var(--adm-border);
  font-weight: 600; font-size: 14px;
  text-align: center;
}
/* Day-note row — operator scratchpad sat above the 9:00 row. */
.diary-grid .diary-daynote {
  border-bottom: 1px solid var(--adm-border);
  padding: 6px;
  position: relative;
  background: #fffdf5;
}
.diary-grid .diary-daynote.diary-daynote-label {
  background: var(--adm-bg);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--adm-muted);
  display: flex; align-items: center; justify-content: center;
}
.diary-grid .diary-daynote textarea {
  width: 100%; min-height: 44px; max-height: 120px;
  border: 1px solid transparent;
  background: transparent;
  font: inherit; font-size: 13.5px; font-weight: 600; line-height: 1.35;
  padding: 6px 8px; resize: vertical;
  border-radius: 8px;
  transition: border-color .15s ease, background .15s ease;
}
.diary-grid .diary-daynote textarea:hover { border-color: var(--adm-border); background: #fff; }
.diary-grid .diary-daynote textarea:focus { outline: 0; border-color: var(--adm-blue); background: #fff; }
/* Red bordered box when there's any text — high-visibility so Annie can't
   miss a day's notes. The .has-content class is toggled by JS on input. */
.diary-grid .diary-daynote textarea.has-content {
  background: #fff;
  border-color: #dc2626;
  border-width: 2px;
  box-shadow: 0 0 0 1px rgba(220, 38, 38, .15);
}
.diary-grid .diary-daynote-status {
  position: absolute; right: 8px; bottom: 4px;
  font-size: 10px; color: var(--adm-muted);
  opacity: 0; transition: opacity .2s ease;
}
.diary-grid .diary-daynote-status.is-saving { opacity: 1; }
.diary-grid .diary-daynote-status.is-saved  { opacity: 1; color: #15803d; }

.diary-grid .time-col { border-right: 1px solid var(--adm-border); }
.diary-grid .time-cell {
  /* Bumped 40→56 on 2026-05-18 so 60-min cards fit four content rows
     + pills without clipping. Must stay in sync with PHP constant
     FFG_DIARY_PIXELS_PER_30MIN and JS PX_PER_30. */
  height: 56px;
  padding: 4px 6px;
  font-size: 11px;
  color: var(--adm-muted);
  border-bottom: 1px dashed #eef0f4;
  text-align: right;
  font-family: ui-monospace, monospace;
}
.diary-grid .ramp-col {
  position: relative;
  border-right: 1px solid var(--adm-border);
  background:
    repeating-linear-gradient(to bottom,
      transparent 0,
      transparent 55px,
      #eef0f4 55px,
      #eef0f4 56px);
}
/* Specificity note: body.admin a:hover at the top of this file forces
   text-decoration:underline on every <a> in the admin. The diary-booking
   rules need to be at least equal-or-higher specificity to win, so we
   qualify with `body.admin` here. Without that the booking cards keep
   their underline on hover and look broken. */
body.admin a.diary-booking {
  position: absolute;
  left: 4px; right: 4px;
  background: var(--adm-blue-tint);
  border-left: 3px solid var(--adm-blue);
  border-radius: var(--adm-radius-sm);
  padding: 5px 9px;
  font-size: 14px;        /* was 12px — slightly easier to scan */
  line-height: 1.3;
  overflow: hidden;
  cursor: pointer;
  text-decoration: none;  /* it's an <a>; no underline on hover or default */
  color: var(--adm-ink);
  box-shadow: var(--adm-shadow-1);
  transition: box-shadow .15s ease, transform .1s ease;
  /* Flex column so pills row sits at the bottom via margin-top:auto +
     the body+notes row gets the remaining vertical space. */
  display: flex;
  flex-direction: column;
}
body.admin a.diary-booking .diary-booking-body {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;          /* allow flex children to shrink + clip */
  gap: 6px;
  overflow: hidden;
  /* Right gutter reserved for the absolutely-positioned pills stack. Pills
     are tiny (10px font, 1-3 short words) — even three stacked pills only
     need ~110px on a ~525px card, ≈21%. Reserving more was making the
     notes column end well before the right edge of the card with empty
     space below the pills. Pills max-width capped at 22% in tandem so
     long pill stacks can't overflow the reserved gutter. */
  padding-right: 22%;
}
/* Cards with no notes also don't need to reserve right space — pills
   absolute, main fills the rest. Re-claim the padding. */
body.admin a.diary-booking .diary-booking-body:has(.diary-booking-main:only-child) {
  padding-right: 0;
}
body.admin a.diary-booking .diary-booking-main {
  /* Hard width cap when sat next to a notes sibling. Flex-basis:auto on
     a single-line-ellipsis container still reports the FULL pre-ellipsis
     content width as the intrinsic size, so main was hogging ~75% of the
     body width whenever any row had a long string (e.g. "NISSAN JUKE
     ACENTA PREMIUM") — leaving notes wrapping per word in 80px.
     55% gives the notes sibling a guaranteed ~45% of body to wrap into. */
  flex: 0 1 55%;
  min-width: 0;
  max-width: 55%;
  overflow: hidden;
}
/* When there's no notes column (main is only child of the body), main
   should grow to fill the full body width instead of staying at 55%. */
body.admin a.diary-booking .diary-booking-main:only-child {
  flex: 1 1 auto;
  max-width: 100%;
}
body.admin a.diary-booking:hover { box-shadow: var(--adm-shadow-2); transform: translateY(-1px); text-decoration: none; }
body.admin a.diary-booking { cursor: grab; }
body.admin a.diary-booking.is-moving {
  cursor: grabbing;
  box-shadow: 0 8px 24px rgba(18, 34, 157, .25);
  opacity: .85;
  z-index: 9;
  pointer-events: none;     /* so mousemove targets the column, not the card */
  transition: none;         /* free-follow during drag — no hover transition */
}
body.is-dragging-booking { user-select: none; cursor: grabbing; }

/* Drop-target outline shown during a diary card drag. Positioned in viewport
   coords by JS — fixed so it ignores page scroll. Non-interactive so it
   never steals events from the card or the column underneath. */
.diary-snap-indicator {
  position: fixed;
  z-index: 8;
  border: 2px dashed var(--adm-blue);
  border-radius: var(--adm-radius-sm);
  background: rgba(14, 30, 160, 0.08);
  pointer-events: none;
}
body.admin a.diary-booking strong {
  display: block;
  color: var(--adm-blue-dark);
  font-weight: 700;
  font-size: 13.5px;
  line-height: 1.2;
  /* Single-line: time + reg never wrap. Make/model lives on its own row
     below (.diary-card-veh). */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
body.admin a.diary-booking .muted { color: var(--adm-muted); font-size: 12px; }   /* was 11px */
/* Job type (services) — bold + a notch bigger so it reads at a glance.
   Previously this was muted/12px; Annie wanted it to stand out. Single-
   line truncate so 'General Repairs' doesn't get clipped at 'Repaira'. */
body.admin a.diary-booking .diary-booking-services {
  margin-top: 2px;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--adm-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Extras line — shown inline below services. Single-line truncate. */
body.admin a.diary-booking .diary-booking-extras {
  margin-top: 1px;
  font-size: 11.5px;
  font-style: italic;
  color: var(--adm-muted);
  line-height: 1.15;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Notes column sits immediately to the right of the main content (no
   fixed width — flex:1 fills whatever room is left in the body). Soft
   amber left border separates it visually from the booking details.
   Line-clamped by card duration. Pills row sits below via flex, so
   notes never push the pills out of view. */
body.admin a.diary-booking .diary-booking-notes {
  flex: 1 1 0;
  min-width: 0;
  align-self: stretch;
  font-size: 11.5px;
  line-height: 1.3;
  /* White rounded-corner box with black text — high contrast against the
     coloured card background so notes are immediately readable. Was muted
     amber italic on a tinted card, much harder to scan. */
  color: #111;
  font-style: normal;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, .08);
  border-radius: 6px;
  word-break: normal;
  overflow-wrap: break-word;
  padding: 4px 7px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;   /* fallback when card is tall — visible-line cap */
}
body.admin a.diary-booking[data-duration="30"] .diary-booking-notes {
  font-size: 10.5px;
  -webkit-line-clamp: 2;
}
body.admin a.diary-booking[data-duration="60"] .diary-booking-notes {
  -webkit-line-clamp: 3;
}

/* Pills row pinned to the bottom of the card. flex-shrink:0 means it
   never collapses to make room for notes — bookings must always show
   their status / VHC / Get-email / Review tags. */
body.admin a.diary-booking .booking-pills {
  flex-shrink: 0;
  margin-top: auto;
  display: flex;
  flex-direction: column;        /* stack the pills — the absolute-positioned
                                    container is only 22% wide, so a row of
                                    "No-show" + "Get email" would overflow
                                    and overlap (Rich, 2026-05-21). */
  align-items: flex-end;
  /* No flex-wrap in column mode — wrap was making the pills lay out in a
     second column at the same vertical position, causing the visible
     overlap. Stack and overflow if you must. */
  gap: 5px;
  padding-top: 3px;
}
/* 30-min card (≈48px tall after 2026-05-18 row-height bump 40→56) —
   still only enough room for strong + services + pills. Hide the
   make/model and customer-name rows to keep the job type visible.
   Full info still on hover popup + side panel. */
body.admin a.diary-booking[data-duration="30"] {
  padding: 3px 8px;
  font-size: 12px;
  line-height: 1.15;
}
body.admin a.diary-booking[data-duration="30"] strong { font-size: 12.5px; }
body.admin a.diary-booking[data-duration="30"] .muted { font-size: 11px; }
body.admin a.diary-booking[data-duration="30"] .diary-booking-services { font-size: 12.5px; margin-top: 1px; }
body.admin a.diary-booking[data-duration="30"] .diary-booking-extras { font-size: 10.5px; }
body.admin a.diary-booking[data-duration="30"] .diary-card-veh,
body.admin a.diary-booking[data-duration="30"] .diary-card-cust {
  display: none;
}
/* 60-min card — show make/model but keep customer row hidden if extras
   exist (extras + services + strong + make/model = 4 lines, already
   tight at 80px). Otherwise show all. */
body.admin a.diary-booking[data-duration="60"] .diary-card-veh {
  font-size: 11px;
}
body.admin a.diary-booking[data-duration="60"] .diary-card-cust {
  font-size: 11.5px;
  line-height: 1.15;
}
body.admin a.diary-booking.status-onsite     { background: #ddd6fe; border-left-color: #6d28d9; }
body.admin a.diary-booking.status-in_progress { background: var(--adm-amber-tint); border-left-color: var(--adm-amber); }
body.admin a.diary-booking.status-completed   { background: #ccfbf1; border-left-color: #0f766e; }
body.admin a.diary-booking.status-customer_called_to_collect { background: #fce7f3; border-left-color: #be185d; }
body.admin a.diary-booking.status-collected   { background: var(--adm-green-tint); border-left-color: var(--adm-green); }
/* Cancelled bookings don't render on the diary any more — slot is freed
   and they live only in the customer history. The rule stays in case a
   stale page renders one. */
body.admin a.diary-booking.status-cancelled {
  background: var(--adm-red-tint); border-left-color: var(--adm-red);
  text-decoration: line-through; opacity: .7;
}
/* No-show: customer didn't turn up but the slot is gone (tech's time
   already paid for). Distinct from cancelled — strong red, diagonal
   stripes, prominent NO-SHOW banner so it's obvious at a glance and
   doesn't get mistaken for an active booking. */
body.admin a.diary-booking.status-no_show {
  background:
    repeating-linear-gradient(135deg,
      #fecaca 0, #fecaca 8px,
      #fee2e2 8px, #fee2e2 16px);
  border-left-color: #991b1b;
  color: #7f1d1d;
  text-decoration: line-through;
}
/* The "NO-SHOW" ::after pseudo-element used to render a duplicate label
   in the top-right corner — overlapping the PHP-rendered .bpill-status-no_show
   chip that lives in .booking-pills. Removed 2026-05-21 (Rich caught it
   while debugging a separate pill-overlap issue). The bpill carries the
   label now; the diagonal stripes + strikethrough already make it
   unmistakable at a glance. */
/* Forecourt column inside the diary grid */
.forecourt-col {
  position: relative;       /* contains .ramp-closed-note's inset:0 — without
                               this it escapes to <html> and the diagonal mesh
                               covers the entire page on closed days. */
  padding: 8px 6px;
  display: flex; flex-direction: column; gap: .5rem;
  background:
    repeating-linear-gradient(to bottom,
      transparent 0,
      transparent 55px,
      #eef0f4 55px,
      #eef0f4 56px);
}
/* Forecourt capacity-hold control (admin reservation of count-based capacity). */
.forecourt-hold {
  display: flex; align-items: center; flex-wrap: wrap; gap: .4rem;
  padding: 6px 8px;
  border-radius: var(--adm-radius-sm);
  background: #fff;
  border: 1px dashed var(--adm-border, #cdd3dd);
  font-size: 13px;
}
.forecourt-hold.has-hold {
  background: var(--adm-amber-tint, #fff6e5);
  border: 1px solid var(--adm-amber, #e0a106);
}
.forecourt-hold-label { color: var(--adm-ink); }
.forecourt-hold-controls { display: inline-flex; gap: .3rem; margin-left: auto; }
.btn-mini {
  font: inherit; font-size: 12px; line-height: 1;
  padding: 4px 8px;
  border: 1px solid var(--adm-border, #cdd3dd);
  border-radius: var(--adm-radius-sm);
  background: var(--adm-bg, #f4f6fa);
  color: var(--adm-ink);
  cursor: pointer;
}
.btn-mini:hover { background: #e7ebf2; }
.btn-mini.danger { color: #b3261e; border-color: #e6b4b0; }
.btn-mini.danger:hover { background: #fbeae8; }
/* Same specificity story as .diary-booking — qualify with body.admin a so
   body.admin a:hover (with underline) doesn't beat us on the cascade. */
body.admin a.forecourt-card {
  display: block;
  position: relative;          /* anchor for absolute .booking-pills */
  background: var(--adm-blue-tint);
  border-left: 3px solid var(--adm-blue);
  border-radius: var(--adm-radius-sm);
  padding: 8px 10px;
  font-size: 14px;
  text-decoration: none;
  color: var(--adm-ink);
  cursor: pointer;
  box-shadow: var(--adm-shadow-1);
  transition: box-shadow .15s ease, transform .1s ease;
}
body.admin a.forecourt-card:hover { box-shadow: var(--adm-shadow-2); transform: translateY(-1px); text-decoration: none; }
body.admin a.forecourt-card strong { color: var(--adm-blue-dark); font-weight: 700; font-size: 13.5px; }
body.admin a.forecourt-card .muted { color: var(--adm-muted); font-size: 12px; }
body.admin a.forecourt-card .diary-card-veh { font-size: 11.5px; margin-top: 1px; }
body.admin a.forecourt-card .diary-card-cust {
  font-size: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
body.admin a.forecourt-card .forecourt-card-services {
  font-size: 13.5px; font-weight: 600; line-height: 1.2;
  margin-top: 2px; color: var(--adm-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
body.admin a.forecourt-card .forecourt-card-extras {
  font-size: 11.5px; font-style: italic; color: var(--adm-muted);
  line-height: 1.15; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
body.admin a.forecourt-card.status-onsite                     { background: #ddd6fe; border-left-color: #6d28d9; }
body.admin a.forecourt-card.status-in_progress                { background: var(--adm-amber-tint); border-left-color: var(--adm-amber); }
body.admin a.forecourt-card.status-completed                  { background: #ccfbf1; border-left-color: #0f766e; }
body.admin a.forecourt-card.status-customer_called_to_collect { background: #fce7f3; border-left-color: #be185d; }
body.admin a.forecourt-card.status-collected                  { background: var(--adm-green-tint); border-left-color: var(--adm-green); }
body.admin a.forecourt-card.status-cancelled {
  background: var(--adm-red-tint); border-left-color: var(--adm-red);
  text-decoration: line-through; opacity: .7;
}
body.admin a.forecourt-card.status-no_show {
  background:
    repeating-linear-gradient(135deg,
      #fecaca 0, #fecaca 8px,
      #fee2e2 8px, #fee2e2 16px);
  border-left-color: #991b1b;
  color: #7f1d1d;
  text-decoration: line-through;
  position: relative;
}
/* See diary-booking.status-no_show::after note above — same dedup. */
.forecourt-empty {
  padding: 1rem;
  color: var(--adm-muted); font-style: italic; font-size: 14px;
  text-align: center;
}

/* Pills shown ON a booking card. Default flex-wrap layout for forecourt cards
 * (which have plenty of room). On diary cards we absolute-position pills in
 * the top-right column — preferred layout per Rich 2026-05-17. The
 * .diary-booking-body adds right-padding to keep the notes column from
 * running underneath the pills. */
.booking-pills {
  display: flex; flex-wrap: wrap; gap: 3px;
  margin-top: 2px;
}
.diary-booking .booking-pills {
  position: absolute;
  top: 4px; right: 4px;
  margin-top: 0;
  flex-direction: column; align-items: flex-end;
  z-index: 2;
  /* Pill container width — wide enough for any single pill to fit on
     its own line. Was 22% but "No-show" (the widest status label) at
     10px font + 7px padding lands at ~62px and overflowed leftward
     INTO the card content (Rich, 2026-05-21). max-content + a
     reasonable cap stops the overflow without letting an absurdly
     long future pill push the body content out. */
  max-width: max-content;
}
.bpill {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10px; font-weight: 600;
  line-height: 1.3;
  letter-spacing: .02em;
  color: #fff;
  text-decoration: none;
}
/* Pills stack — plain block flow + explicit margin between, no
   positioning tricks. The previous attempt set position:relative on each
   .bpill which created a stacking context per pill and (with flex-wrap)
   actually caused the No-show pill to paint ON TOP of the Get email pill
   below it. Removed: position:relative, flex-wrap (on the container).
   Kept: display:block + margin-top so they stack reliably. */
.diary-booking .booking-pills .bpill,
.forecourt-card .booking-pills .bpill {
  position: static !important;   /* defeat any inherited positioning */
  display: block;
  width: max-content;            /* shrink to content, ignore flex stretching */
  margin-left: auto;             /* keep right-aligned even with display:block */
}
.diary-booking .booking-pills .bpill:not(:first-child),
.forecourt-card .booking-pills .bpill:not(:first-child) {
  margin-top: 6px !important;    /* clear visible gap, override any inline */
}
.bpill.bpill-clickable { cursor: pointer; }
.bpill.bpill-clickable:hover { filter: brightness(1.1); transform: translateY(-1px); }
.bpill-status { background: var(--adm-blue); }
/* Status-variant overrides — match the .pill.X palette so the diary card,
   side-panel pill, and customer-facing account view all read the same. */
.bpill-status-onsite                     { background: #fcb900; color: #000; }
.bpill-status-in_progress                { background: #6d28d9; color: #fff; }
.bpill-status-completed                  { background: #22c55e; color: #000; }
.bpill-status-customer_called_to_collect { background: #0E1EA0; color: #fff; }
.bpill-status-collected                  { background: #991b1b; color: #fff; }
.bpill-status-no_show                    { background: #111827; color: #fff; }
.bpill-status-cancelled                  { background: var(--adm-red-tint); color: var(--adm-red); }
.bpill-extras { background: #ea580c; }   /* orange */
.bpill-sheet  { background: #0f766e; }   /* teal — visual cue that a sheet exists */
.bpill-keybox { background: #6d28d9; }   /* purple — key in numbered box */
.bpill-notes  { background: #0891b2; }   /* cyan — customer has internal notes */
.bpill-review { background: #ca8a04; }   /* amber — tagged for Google review request */
.bpill-needemail { background: #dc2626; } /* red — customer email missing / @noemail.local placeholder */

/* ===== Top-nav unread badges (live-polled) ============================== */
.adm-nav a { position: relative; }
.adm-nav-badge {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  margin-left: 6px;
  height: 18px; line-height: 18px;
  font-size: 11px; font-weight: 700;
  background: #dc2626;     /* red — Annie wants this loud */
  color: #fff;
  border-radius: 999px;
  text-align: center;
  vertical-align: 1px;
  box-shadow: 0 0 0 2px #fff;
  animation: adm-badge-pop .25s ease;
}
@keyframes adm-badge-pop {
  from { transform: scale(.6); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}

/* ===== Floating iPhone-style new-message popup ========================== */
.adm-msg-popup[hidden] { display: none; }
.adm-msg-popup {
  position: fixed;
  right: 1.25rem; bottom: 1.25rem;
  z-index: 200;
  width: min(340px, calc(100% - 2rem));
  background: linear-gradient(180deg, #ffffff 0%, #f5f7fb 100%);
  border-radius: 18px;
  border: 1px solid var(--adm-border);
  box-shadow: 0 16px 40px rgba(13, 24, 111, .22),
              0 32px 64px rgba(13, 24, 111, .14);
  overflow: hidden;
  transform: translateY(20px) scale(.96);
  opacity: 0;
  transition: transform .25s ease, opacity .25s ease;
}
.adm-msg-popup.is-visible {
  transform: translateY(0) scale(1);
  opacity: 1;
}
.adm-msg-popup-bar {
  display: flex; align-items: center; gap: .5rem;
  padding: .5rem .75rem;
  background: var(--adm-blue);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.adm-msg-popup-dot {
  width: 8px; height: 8px;
  background: #34d399;
  border-radius: 50%;
  box-shadow: 0 0 8px rgba(52, 211, 153, .8);
  animation: adm-msg-pulse 1.4s ease-in-out infinite;
}
@keyframes adm-msg-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .4; }
}
.adm-msg-popup-title { flex: 1; }
.adm-msg-popup-close {
  background: transparent; border: 0;
  color: rgba(255,255,255,.85);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
}
.adm-msg-popup-close:hover { color: #fff; }
.adm-msg-popup-body {
  display: block;
  padding: .75rem 1rem 1rem;
  color: var(--adm-text);
  text-decoration: none;
}
.adm-msg-popup-name { font-size: 15px; font-weight: 700; color: var(--adm-blue-dark); }
.adm-msg-popup-from { display: block; font-size: 11px; color: var(--adm-muted); margin: 2px 0 .5rem; font-variant-numeric: tabular-nums; }
.adm-msg-popup-text {
  background: var(--adm-blue-tint);
  border-radius: 14px 14px 14px 4px;
  padding: .55rem .8rem;
  margin: 0 0 .5rem;
  font-size: 14px;
  line-height: 1.4;
  /* Keep the bubble from overflowing for huge messages. */
  max-height: 7em;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
}
.adm-msg-popup-cta {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--adm-blue);
  text-align: right;
}

/* ===== VGM-style unified search panel (admin booking-new) =============== */
.vgm-search {
  background: var(--adm-surface-gradient);
  border: 1px solid var(--adm-border);
  border-radius: 12px;
  padding: .85rem 1rem;
  box-shadow: var(--adm-shadow-1);
  margin: 0 0 1rem;
}
.vgm-search-row { display: flex; gap: .75rem; align-items: stretch; flex-wrap: wrap; }
.vgm-search .vgm-search-input { flex: 1; min-width: 220px; }
.vgm-search .vgm-search-input input[type="search"] { width: 100%; }

.vgm-search-input {
  display: flex; gap: .5rem; flex: 1; min-width: 220px;
}
.vgm-search-input input[type="search"] {
  flex: 1;
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font: inherit;
  font-size: 14px;
  background: #fff;
}
.vgm-search-input input[type="search"]:focus {
  outline: 2px solid var(--adm-blue);
  outline-offset: -1px;
  border-color: var(--adm-blue);
}

.vgm-search-results {
  list-style: none; margin: .75rem 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
  max-height: 380px; overflow-y: auto;
}
.vgm-search-hit-row {
  display: flex; flex-wrap: wrap;
  gap: .5rem 1rem;
  align-items: center;
  width: 100%;
  padding: .65rem .85rem;
  background: #fff;
  border: 1px solid var(--adm-border);
  border-radius: 8px;
}
.vgm-search-hit-row:hover { border-color: var(--adm-blue); background: var(--adm-blue-tint); }
.vgm-hit-info {
  display: grid; grid-template-columns: 1fr 1.4fr;
  gap: .2rem 1rem;
  flex: 1; min-width: 240px;
}
.vgm-hit-veh, .vgm-hit-cust { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; min-width: 0; }
.vgm-hit-cust { font-size: 14px; }
.vgm-hit-actions { display: flex; gap: .35rem; flex-wrap: wrap; }
.vgm-hit-actions .btn { white-space: nowrap; }
.vgm-search-hit-row .reg-tag {
  display: inline-block;
  background: #fcb900; color: #000;
  font-family: 'Charles Wright', 'Arial Black', sans-serif;
  font-weight: 700; letter-spacing: 1.5px;
  padding: 1px 6px; border: 1.5px solid #000; border-radius: 3px;
  font-size: 12px;
}
@media (max-width: 720px) {
  .vgm-search-row { flex-direction: column; }
  .vgm-hit-info { grid-template-columns: 1fr; }
}

/* Service-sheet extras section (top of sheet form) */
.sheet-extras { background: linear-gradient(180deg, #fff8e7 0%, #ffffff 100%); border-color: #fcb900; }
.sheet-extras legend { color: #6b4500; font-weight: 700; }
.sheet-extras-list { list-style: none; margin: 0; padding: 0; }
.sheet-extra-row { padding: .35rem 0; border-bottom: 1px dashed #e5e7eb; }
.sheet-extra-row:last-child { border-bottom: 0; }
.sheet-extra-row label { display: flex; align-items: center; gap: .5rem; cursor: pointer; }
.sheet-extra-row.is-confirmed { background: #ecfdf5; border-radius: 4px; padding: .35rem .5rem; }
.sheet-extra-row.is-confirmed strong { text-decoration: line-through; color: #064e3b; }

/* Extras modal: same .adm-modal styling but force visible on load (PHP only
 * renders it if pending extras exist + sheet isn't complete). is-hidden
 * class lets the JS dismiss it after all are ticked. */
#extrasModal { display: flex; }
#extrasModal.is-hidden { display: none; }

/* ===== Generic admin modal (used by reserve-slot dialog) ===== */
.adm-modal[hidden] { display: none; }
.adm-modal {
  position: fixed; inset: 0;
  z-index: 1000;
  display: flex; align-items: center; justify-content: center;
}
.adm-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(15, 23, 42, .55);
  backdrop-filter: blur(2px);
}
.adm-modal-panel {
  position: relative;
  background: var(--adm-surface);
  border-radius: var(--adm-radius);
  padding: 1.25rem 1.5rem 1.25rem;
  max-width: 460px;
  width: calc(100% - 2rem);
  box-shadow: var(--adm-shadow-2);
}
.adm-modal-panel .row { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .75rem; }
.adm-modal-panel label { font-weight: 500; font-size: 14px; color: var(--adm-text); }
.adm-modal-panel select,
.adm-modal-panel textarea,
.adm-modal-panel input {
  font: inherit;
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: #fff;
  font-size: 14px; line-height: 1.4;
}
.adm-modal-panel select:focus,
.adm-modal-panel textarea:focus,
.adm-modal-panel input:focus {
  outline: 2px solid var(--adm-blue);
  outline-offset: -1px; border-color: var(--adm-blue);
}

/* Right-click context menu */
.ctx-menu {
  position: fixed;
  z-index: 200;
  min-width: 220px;
  background: #fff;
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  box-shadow: var(--adm-shadow-2);
  padding: 4px 0;
  font-size: 14px;
}
.ctx-menu[hidden] { display: none !important; }
.ctx-item {
  display: block;
  padding: 7px 14px;
  color: var(--adm-text);
  cursor: pointer;
  user-select: none;
}
.ctx-item:hover { background: var(--adm-bg); color: var(--adm-blue-dark); text-decoration: none; }
.ctx-item.is-disabled {
  color: var(--adm-muted);
  pointer-events: none;
  opacity: .55;
}
.ctx-item.danger { color: #b91c1c; }
.ctx-item.danger:hover { background: var(--adm-red-tint); color: #7f1d1d; }
.ctx-item.is-current::before { content: '✓ '; color: var(--adm-green); font-weight: 700; margin-right: 2px; }
.ctx-divider { height: 1px; background: var(--adm-border); margin: 4px 0; }

/* Submenu: hover or click to open, opens to the right by default */
.ctx-has-submenu {
  position: relative;
  display: flex; justify-content: space-between; align-items: center;
}
.ctx-has-submenu > .ctx-arrow {
  margin-left: 1rem;
  color: var(--adm-muted);
}
.ctx-submenu {
  position: absolute;
  left: 100%; top: -5px;     /* aligns first item with the parent item */
  min-width: 220px;
  background: #fff;
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  box-shadow: var(--adm-shadow-2);
  padding: 4px 0;
  display: none;
}
.ctx-has-submenu:hover > .ctx-submenu,
.ctx-has-submenu.is-open > .ctx-submenu { display: block; }
.ctx-has-submenu:hover { background: var(--adm-bg); }

/* Flip submenu to the left if it would go off-screen — JS adds .flip when
   the natural-position submenu would extend past the right edge of the
   viewport. Default leans right. */
.ctx-has-submenu.flip > .ctx-submenu { left: auto; right: 100%; }
/* Flip submenu UPWARDS (anchor to parent's bottom) when its natural position
   would extend below the viewport. JS adds .flip-up. */
.ctx-has-submenu.flip-up > .ctx-submenu { top: auto; bottom: -5px; }

/* Resize handle on diary bookings */
body.admin a.diary-booking { padding-bottom: 4px; }   /* tight — keeps content visible in a 60min card */
.diary-booking .resize-handle {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 5px;
  cursor: ns-resize;
  background: linear-gradient(to bottom, transparent 0, rgba(15,23,42,.18) 100%);
  border-bottom-left-radius: var(--adm-radius-sm);
  border-bottom-right-radius: var(--adm-radius-sm);
  opacity: 0;
  transition: opacity .12s ease;
}
.diary-booking:hover .resize-handle { opacity: 1; }
.diary-booking.is-resizing { box-shadow: var(--adm-shadow-2); z-index: 5; }
.diary-booking.is-resizing .resize-handle { opacity: 1; background: rgba(18,34,157,.35); }

/* ===== Side panel / modal ===== */
.side-panel-backdrop {
  position: fixed; inset: 0;
  background: rgba(15,23,42,.4);
  z-index: 100;
  display: none;
}
.side-panel-backdrop.open { display: block; }
.side-panel {
  position: fixed;
  top: 1.25rem; right: 1.25rem; bottom: 1.25rem;
  width: calc(100% - 2.5rem); max-width: 480px;
  background: var(--adm-surface-gradient);
  border: 1px solid #e5e7eb;
  border-radius: 14px;
  box-shadow: var(--adm-shadow-3);
  z-index: 101;
  transform: translateX(calc(100% + 1.5rem));
  transition: transform .25s ease;
  display: flex;
  flex-direction: column;
  overflow: hidden;       /* body handles its own scroll */
}
@media (max-width: 720px) {
  .side-panel {
    top: 0; right: 0; bottom: 0;
    width: 100%; border-radius: 0; border: 0;
    transform: translateX(100%);
  }
}
/* Always-visible thin scrollbar so it's obvious the panel scrolls (macOS
   hides them by default and the cue gets lost on long content). */
.side-panel-body { scrollbar-width: thin; scrollbar-color: rgba(0,0,0,.25) transparent; }
.side-panel-body::-webkit-scrollbar { width: 8px; }
.side-panel-body::-webkit-scrollbar-thumb {
  background: rgba(0,0,0,.25); border-radius: 4px;
}
.side-panel-body::-webkit-scrollbar-track { background: transparent; }
.side-panel.open { transform: translateX(0); }
.side-panel-head {
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--adm-border);
  display: flex; justify-content: space-between; align-items: center;
  background: #fff;
  flex: 0 0 auto;       /* fixed-height inside flex column */
}
.side-panel-head h2 { margin: 0; font-size: 16px; font-weight: 600; }
.side-panel-head .close { background: none; border: 0; cursor: pointer; font-size: 24px; color: var(--adm-muted); padding: 0; line-height: 1; }
.side-panel-body {
  padding: 1.25rem 1.5rem;
  flex: 1 1 auto;       /* grows + shrinks; scrolls when content overflows */
  overflow-y: auto;
  overflow-x: hidden;
}
/* Tighten the spacing between cards inside the side panel so more fits at once. */
.side-panel-body .card { padding: .75rem 1rem; }
.side-panel-body .card.mb-2 { margin-bottom: .75rem; }
.side-panel-body .card-title { margin-bottom: .4rem; }

/* Tabs */
.adm-tabs {
  display: flex; gap: 0;
  border-bottom: 1px solid var(--adm-border);
  margin-bottom: 1rem;
}
.adm-tabs a {
  padding: 10px 16px;
  color: var(--adm-muted);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.adm-tabs a:hover { color: var(--adm-text); text-decoration: none; }
.adm-tabs a.is-current { color: var(--adm-blue); border-bottom-color: var(--adm-blue); font-weight: 600; }

/* Utility */
.flex { display: flex; align-items: center; gap: .75rem; }
.flex.between { justify-content: space-between; }
.flex.wrap { flex-wrap: wrap; }
.spacer { flex: 1; }
.muted { color: var(--adm-muted); }
.small { font-size: 12px; }
.right { text-align: right; }
.center { text-align: center; }
.mt-1 { margin-top: .5rem; } .mt-2 { margin-top: 1rem; } .mt-3 { margin-top: 1.5rem; }
.mb-1 { margin-bottom: .5rem; } .mb-2 { margin-bottom: 1rem; }
.nowrap { white-space: nowrap; }
.adm-empty {
  text-align: center; padding: 3rem 1rem; color: var(--adm-muted);
  font-size: 14px; font-style: italic;
}
.flex.end { justify-content: flex-end; }
.gap-1 { gap: .5rem; }
.gap-2 { gap: 1rem; }
.kv { display: grid; grid-template-columns: 1fr; gap: 2px; font-size: 14px; }
.kv > div { display: flex; gap: .5rem; }
.kv .muted { min-width: 60px; }
.card-title {
  font-size: 12px; font-weight: 600; color: var(--adm-muted);
  text-transform: uppercase; letter-spacing: .04em;
  margin: 0 0 .5rem;
}
.adm-clean-list { list-style: none; padding: 0; margin: 0; }
.adm-clean-list li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 4px 0; border-bottom: 1px dashed var(--adm-border);
}
.adm-clean-list li:last-child { border-bottom: 0; }
.grid-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: center; }
@media (max-width: 540px) { .grid-2col { grid-template-columns: 1fr; } }

/* Diary extras */
.ramp-closed-note {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--adm-muted); font-style: italic; font-size: 14px;
  background: repeating-linear-gradient(135deg,
    transparent 0, transparent 8px,
    rgba(15,23,42,.04) 8px, rgba(15,23,42,.04) 16px);
}
/* Stacking inside a ramp column (smallest → topmost):
     .ramp-slot-cell (z:1)  — empty-slot hover/right-click target
     .diary-booking  (z:2)  — booking cards
     .diary-block    (z:3)  — reservation blocks
     .is-resizing    (z:5)  — whichever's being dragged */
.diary-block {
  position: absolute;
  left: 4px; right: 4px;
  background: repeating-linear-gradient(135deg,
    #f1f5f9 0, #f1f5f9 6px, #e2e8f0 6px, #e2e8f0 12px);
  border: 1px dashed var(--adm-border);
  border-radius: var(--adm-radius-sm);
  padding: 6px 8px;
  font-size: 11px; color: var(--adm-muted);
  overflow: hidden;
  z-index: 3;
  cursor: default;
}
.diary-block:hover { border-style: solid; }
.diary-block .resize-handle {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 8px; cursor: ns-resize;
  background: rgba(15,23,42,.08);
  opacity: 0; transition: opacity .12s ease;
  border-radius: 0 0 var(--adm-radius-sm) var(--adm-radius-sm);
}
.diary-block:hover .resize-handle { opacity: 1; }
.diary-block.is-resizing { box-shadow: var(--adm-shadow-2); z-index: 5; border-style: solid; }

/* Bookings sit ABOVE slot cells so hover/right-click/mouseenter
   target the booking, not the slot underneath. */
.diary-booking { z-index: 2; }
.diary-booking.is-resizing { z-index: 5; }

/* ===== Empty ramp slot cells — subtle hover + right-click target ===== */
.ramp-slot-cell {
  position: absolute;
  left: 4px; right: 4px;
  border-top: 1px dashed transparent;
  background: transparent;
  cursor: context-menu;
  z-index: 1;          /* below bookings (z:2) + blocks (z:3) */
  transition: background .12s ease, border-color .12s ease;
}
.ramp-slot-cell:hover {
  background: rgba(18, 34, 157, 0.06);
  border-top: 1px dashed rgba(18, 34, 157, 0.25);
}
/* Past dates: ramp-col gets .is-past, slot cells become inert + invisible. */
.ramp-col.is-past .ramp-slot-cell { display: none; }

/* ===== Booking hover tooltip ===== */
.booking-tooltip {
  position: fixed;
  z-index: 200;
  background: #0f172a;
  color: #f8fafc;
  border-radius: 10px;
  padding: 14px 16px;
  width: 380px;
  max-width: calc(100vw - 24px);
  max-height: calc(100vh - 24px);
  overflow: auto;
  font-size: 14px;
  line-height: 1.5;
  box-shadow: 0 6px 16px rgba(0,0,0,.22), 0 18px 40px rgba(0,0,0,.22);
  pointer-events: none;
}
.booking-tooltip .tt-name    { font-weight: 600; font-size: 15px; margin-bottom: 3px; }
.booking-tooltip .tt-contact { color: #cbd5e1; font-size: 12px; margin-bottom: 8px; }
.booking-tooltip .tt-row     { margin-top: 6px; }
.booking-tooltip .tt-row strong { color: #cbd5e1; font-weight: 500; }
.booking-tooltip .tt-notes   { padding: 8px 10px; margin-top: 10px;
                               background: rgba(255,255,255,.06); border-radius: 6px;
                               white-space: pre-wrap; }

/* ===== Inline customer-edit toggle on booking side panel ===== */
.customer-card .cust-edit { display: none; }
.customer-card.is-editing .cust-view { display: none; }
.customer-card.is-editing .cust-edit { display: block; }
.diary-forecourt-row {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: .75rem; align-items: center;
  padding: 8px 12px;
  background: #fff;
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius-sm);
  transition: box-shadow .15s ease, transform .1s ease;
}
.diary-forecourt-row:hover { box-shadow: var(--adm-shadow-1); transform: translateY(-1px); text-decoration: none; }
.diary-forecourt-row.status-cancelled,
.diary-forecourt-row.status-no_show { text-decoration: line-through; opacity: .65; }
@media (max-width: 600px) {
  .diary-forecourt-row { grid-template-columns: 1fr; gap: 4px; }
}

/* Side panel: support .is-open in addition to .open */
.side-panel-backdrop.is-open { display: block; }
.side-panel.is-open { transform: translateX(0); }
.side-panel-close {
  background: none; border: 0; cursor: pointer;
  font-size: 24px; color: var(--adm-muted);
  text-decoration: none; padding: 0 .25rem; line-height: 1;
}
.side-panel-close:hover { color: var(--adm-text); }

/* Diary card vehicle make/model — own compact row beneath the time/reg
   strong line. Single-line ellipsis: long names like "NISSAN QASHQAI DCI
   N-TEC PLUS" truncate gracefully instead of wrapping the strong line
   and pushing notes/services off the bottom of short cards. Full text
   stays in the title attribute (browser tooltip) and the hover popup. */
.diary-card-veh {
  font-size: 11.5px;
  font-weight: 600;
  color: #4b5563;
  letter-spacing: .15px;
  line-height: 1.15;
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Single-line ellipsis on the customer-name row too. Was wrapping under
   long names + filling rows that pushed the services line off-card. */
.diary-card-cust {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Pill colours that mirror booking statuses — Rich's spec 2026-05-18 */
.pill.confirmed                  { background: var(--adm-blue-tint);  color: var(--adm-blue-dark); }
.pill.onsite                     { background: #fcb900; color: #000; }
.pill.in_progress                { background: #6d28d9; color: #fff; }
.pill.completed                  { background: #22c55e; color: #000; }
.pill.customer_called_to_collect { background: #0E1EA0; color: #fff; }
.pill.collected                  { background: #991b1b; color: #fff; }
.pill.cancelled                  { background: var(--adm-red-tint);   color: #7f1d1d; }
.pill.no_show                    { background: #111827; color: #fff; }
.pill.mot                        { background: var(--adm-blue-tint);  color: var(--adm-blue-dark); }
.pill.service                    { background: var(--adm-amber-tint); color: #075985; }
.pill.forecourt                  { background: #e0e7ff; color: #3730a3; }
.pill.new                        { background: var(--adm-amber-tint); color: #075985; font-weight: 700; }
.pill.contacted                  { background: var(--adm-blue-tint);  color: var(--adm-blue-dark); }
.pill.booked                     { background: #ccfbf1; color: #0f5045; }
.pill.closed                     { background: #f1f5f9; color: #475569; }


/* ===== Invoice-creation line cards =================================
   /admin/invoices/new/ — one card per invoice line. Replaces the
   old narrow table layout so descriptions can be edited freely
   (especially important for General Repairs where the operator
   needs to write what was actually done).
   ================================================================= */
.invoice-line {
  border: 1px solid var(--adm-border);
  border-radius: var(--adm-radius);
  padding: .85rem 1rem .75rem;
  margin-bottom: .85rem;
  background: var(--adm-surface);
  position: relative;
}
.invoice-line-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: .5rem;
}
.invoice-line-tag {
  display: inline-block;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 8px; border-radius: 4px;
}
.invoice-line-tag.tag-service { background: var(--adm-blue-tint);  color: var(--adm-blue-dark); }
.invoice-line-tag.tag-extra   { background: var(--adm-amber-tint); color: #075985; }
.invoice-line-tag.tag-adhoc   { background: var(--adm-bg);         color: var(--adm-muted); }
.invoice-line-remove {
  border: 1px solid var(--adm-border);
  background: #fff;
  color: var(--adm-red);
  width: 28px; height: 28px;
  border-radius: 6px;
  font-size: 18px; line-height: 1;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s ease, border-color .12s ease;
}
.invoice-line-remove:hover {
  background: var(--adm-red-tint);
  border-color: var(--adm-red);
}
.invoice-line-grid {
  display: grid;
  gap: .55rem .9rem;
  grid-template-columns: 1fr 1fr 1fr 1fr;
}
.invoice-line-grid > .row { margin-bottom: 0; }
.invoice-line-grid > .row.full { grid-column: 1 / -1; }
@media (max-width: 800px) {
  .invoice-line-grid { grid-template-columns: 1fr 1fr; }
  .invoice-line-grid > .row { grid-column: span 2; }
}
.invoice-line-foot {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 1rem;
  margin-top: .55rem;
  padding-top: .5rem;
  border-top: 1px dashed var(--adm-border);
  font-size: 14px;
}
.invoice-line-foot .adm-check { font-weight: 400; color: var(--adm-muted); }
.invoice-line-foot .adm-check input:checked + span ~ * { color: var(--adm-ink); }


/* =====================================================================
   Welcome modal — fires once per 24h per admin via
   lib/admin_welcome.php. Same pulsing conic-gradient border trick we
   use on the booking-flow .when-card so the look is consistent.
   ===================================================================== */
.welcome-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 1000;
  display: grid; place-items: center;
  padding: 1.5rem;
  animation: welcome-fade-in .25s ease;
}
.welcome-backdrop.is-closing { animation: welcome-fade-out .2s ease forwards; }
@keyframes welcome-fade-in {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes welcome-fade-out {
  to { opacity: 0; transform: scale(.98); }
}

.welcome-card {
  position: relative;
  max-width: 520px;
  width: 100%;
  background: #fff;
  border-radius: 22px;
  padding: 5.25rem 2rem 2rem;   /* top-padding leaves room for the
                                    overlapping photo */
  box-shadow:
    0 20px 40px -10px rgba(0,0,0,0.4),
    0 8px 16px -6px rgba(0,0,0,0.25);
  isolation: isolate;
}
/* Pulsing conic-gradient border. ::before is the rotating colour ring;
   ::after is the inner white fill that hides everything except the
   exposed gradient edge — same technique as .when-card. */
.welcome-card::before {
  content: "";
  position: absolute; inset: -3px; z-index: -2;
  background: conic-gradient(
    from 0deg,
    rgba(14, 30, 160, 0.0)   0%,
    rgba(14, 30, 160, 0.85) 25%,
    rgba(255, 212, 0,  0.85) 50%,
    rgba(14, 30, 160, 0.85) 75%,
    rgba(14, 30, 160, 0.0) 100%
  );
  border-radius: 26px;
  animation: welcome-spin 6s linear infinite;
}
.welcome-card::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: #fff;
  border-radius: 22px;
}
@keyframes welcome-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .welcome-card::before { animation: none; opacity: .8; }
}

/* Photo overlapping the top-left corner. circle crop + dark border so
   it pops off the white card. drop-shadow underneath for depth. */
.welcome-photo {
  position: absolute;
  top: -42px; left: -42px;
  width: 130px; height: 130px;
  border-radius: 50%;
  object-fit: cover;
  background: #111;
  border: 4px solid #fff;
  box-shadow:
    0 8px 18px -4px rgba(0,0,0,.35),
    0 2px 6px rgba(0,0,0,.2);
  z-index: 1;
}

/* Toy-style red close button — chunky circle, white X, soft shadow. */
.welcome-close {
  position: absolute;
  top: -16px; right: -16px;
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 3px solid #fff;
  background: #e11d48;
  color: #fff;
  font-size: 28px; line-height: 1;
  font-weight: 700;
  cursor: pointer;
  display: grid; place-items: center;
  box-shadow:
    0 6px 14px -2px rgba(225, 29, 72, .55),
    0 2px 4px rgba(0,0,0,.18),
    inset 0 -3px 0 rgba(0,0,0,.18);
  transition: transform .12s ease, box-shadow .12s ease;
  z-index: 2;
  padding-bottom: 4px;
}
.welcome-close:hover {
  transform: rotate(90deg) scale(1.05);
  background: #be123c;
}
.welcome-close:active { transform: rotate(90deg) scale(.96); }

.welcome-inner { text-align: center; }
.welcome-title {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 700;
  color: var(--adm-blue-dark);
  margin: 0 0 1rem;
  letter-spacing: -.01em;
}
.welcome-quote {
  font-family: 'Courier New', 'Courier', ui-monospace, monospace;
  font-size: clamp(1rem, 2.2vw, 1.15rem);
  color: #111;
  line-height: 1.55;
  margin: 0 auto 1.25rem;
  max-width: 44ch;
  text-wrap: pretty;
}
.welcome-footer {
  margin: 0;
  color: var(--adm-muted);
  font-size: 11px;
  letter-spacing: .05em;
  text-transform: uppercase;
}

@media (max-width: 540px) {
  .welcome-card { padding: 4rem 1.25rem 1.5rem; }
  .welcome-photo {
    top: -30px; left: 50%;
    transform: translateX(-50%);
    width: 90px; height: 90px;
  }
  .welcome-close { width: 36px; height: 36px; font-size: 22px; top: -12px; right: -12px; }
}

/* =========================================================================
 * Lower-resolution / tablet responsive pass (Annie's W4: "Entire theme needs
 * to be made more responsive and condensed on lower resolution devices").
 * Two tiers: <1100px tightens the admin chrome; <720px takes it down further
 * to phone width.
 * ========================================================================= */
@media (max-width: 1100px) {
  body.admin { font-size: 14px; }
  .adm-main { padding: 1.25rem 1rem; }
  .adm-topbar { padding: 0 1rem; gap: 1rem; }
  .adm-topbar .adm-brand span { display: none; }   /* logo only — saves room */
  .adm-nav a { padding: 5px 11px; font-size: 12.5px; }
  .adm-page-head h1 { font-size: 1.3rem; }
  .card { padding: 1rem 1.1rem; border-radius: 10px; }
  .card-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: .75rem; }
  /* Tables get an internal scroll container so they don't push the layout. */
  .card .adm-table { display: block; overflow-x: auto; }
  /* 3-column compose grid (admin/diary/new) → 2 columns */
  .ffg-panel-cols { grid-template-columns: 1fr 1fr; gap: 1rem; }
  /* Floating message popup gets a bit smaller. */
  .adm-msg-popup { right: .75rem; bottom: .75rem; width: min(300px, calc(100% - 1.5rem)); }
}

@media (max-width: 720px) {
  body.admin { font-size: 13.5px; line-height: 1.5; }
  .adm-main { padding: 1rem .75rem; }
  .adm-topbar { height: 50px; padding: 0 .75rem; gap: .5rem; }
  /* (The pill nav is hidden ≤1080px — the burger drawer replaces it, so the
   * old flex-wrap fallback that overflowed the fixed-height topbar is gone.) */
  .adm-page-head { gap: .5rem; margin-bottom: 1rem; }
  .adm-page-head h1 { font-size: 1.15rem; }
  .card { padding: .85rem .9rem; }
  .ffg-panel-cols { grid-template-columns: 1fr; gap: .75rem; }
  /* Buttons tighten on phone. */
  body.admin .btn { padding: 6px 12px; font-size: 13px; }
  body.admin .btn.sm { padding: 4px 9px; font-size: 12px; }
  /* Diary grid is intentionally wide — leave it scrollable rather than
   * cramming columns into a phone screen. */
  .diary-grid { overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* ---- Generic phone hardening (2026-06-04 mobile pass) ---- */
  /* Every data table scrolls inside its container, not the page — covers
   * the tables that sit outside a .card (history, pricing, reports). */
  .adm-table, .history-bookings, .pricing-grid {
    display: block; overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  /* Form controls never force the page wider than the viewport. */
  body.admin input, body.admin select, body.admin textarea { max-width: 100%; }
  /* Log/debug output (admin/server) wraps instead of running off-screen. */
  body.admin pre { white-space: pre-wrap; word-break: break-word; max-width: 100%; }
  /* Utility flex rows wrap rather than overflow. */
  .flex { flex-wrap: wrap; }
  .bulk-bar { flex-wrap: wrap; gap: .5rem; }
  /* Content images scale down. */
  .adm-main img { max-width: 100%; height: auto; }
}

/* =========================================================================
 * Modern input pills + soft shadows (Annie: "rectangular boxes with harsh
 * black borders need to look like modern pill boxes with drop shadows").
 * Scope: every input/select/textarea on an admin page, not just inside
 * .adm-form. Heavier specificity (body.admin …) so it overrides earlier
 * narrower rules in this file. Excludes checkboxes / radios / search
 * (the search box has its own treatment).
 * ========================================================================= */
body.admin input[type="text"],
body.admin input[type="email"],
body.admin input[type="password"],
body.admin input[type="number"],
body.admin input[type="tel"],
body.admin input[type="url"],
body.admin input[type="search"],
body.admin input[type="date"],
body.admin input[type="time"],
body.admin input[type="datetime-local"],
body.admin input:not([type]),
body.admin select,
body.admin textarea {
  padding: 9px 14px;
  border: 1px solid #dfe3ec;
  border-radius: 999px;                          /* full pill */
  background: #fff;
  color: var(--adm-text);
  font: inherit;
  font-size: 14px;
  line-height: 1.35;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .05),
              0 2px 6px rgba(15, 23, 42, .04),
              inset 0 1px 0 rgba(255, 255, 255, .8);
  transition: border-color .15s ease, box-shadow .15s ease;
}
body.admin textarea {
  border-radius: 14px;                           /* multi-line → softer rect */
  padding: 10px 14px;
}
body.admin select {
  padding-right: 32px;                           /* room for native arrow */
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%230e1ea0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M1 1 L6 7 L11 1'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
}
body.admin input:focus,
body.admin select:focus,
body.admin textarea:focus {
  outline: none;
  border-color: var(--adm-blue);
  box-shadow: 0 0 0 3px rgba(14, 30, 160, .15),
              0 1px 2px rgba(15, 23, 42, .06);
}
body.admin input[type="checkbox"],
body.admin input[type="radio"] {
  /* Don't pill-ify checkboxes/radios — they're auto-styled below. */
  padding: 0; border-radius: initial; box-shadow: none;
}
/* Tiny date/time inputs in tight table cells (trading-hours grid etc.)
 * shouldn't blow out vertically — trim padding slightly when narrow. */
body.admin .adm-table input[type="date"],
body.admin .adm-table input[type="time"] {
  padding: 7px 12px;
}

/* Time pills need enough width that the value + spinner controls don't
 * collide and squish "09:30" into something half-rendered. The native
 * spinner controls take ~20px on Chrome, so we give the field 90px min. */
body.admin input[type="time"]    { min-width: 96px; }
body.admin input[type="date"]    { min-width: 130px; }
body.admin input[type="datetime-local"] { min-width: 200px; }

/* Trading-hours override list: limit to ~8 visible rows + scroll. The
 * surrounding card wraps a <table>; we constrain its parent .card-grid
 * styling via a dedicated class so other tables aren't affected. */
.adm-scroll-table-8 {
  max-height: calc(8 * 48px + 56px);   /* rough row height × 8 + thead */
  overflow-y: auto;
  border-radius: var(--adm-radius);
  border: 1px solid var(--adm-border);
  background: var(--adm-surface);
}
.adm-scroll-table-8 table.adm-table { margin: 0; }
.adm-scroll-table-8 thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--adm-bg);
}

/* The page-level search boxes on /admin/customers/ and /admin/vehicles/
 * (and anywhere else we add it) want to be roomy and obviously a search
 * field — wide pill, magnifying-glass icon, slightly bigger text. */
body.admin .adm-search-input {
  flex: 1;
  width: 100%;
  max-width: 720px;
  min-width: 280px;
  padding: 11px 18px 11px 42px;
  font-size: 15px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230e1ea0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><path d='m21 21-4.3-4.3'/></svg>");
  background-repeat: no-repeat;
  background-position: 16px center;
  background-size: 16px 16px;
}
body.admin .adm-search-input::-webkit-search-cancel-button { cursor: pointer; }

/* =========================================================================
 * Top nav buttons — pill-shaped with soft shadow, current page = filled
 * brand-blue (matches the "Add override" CTA look Annie called out).
 * Slimmed down from the v1 sizes — the previous 8/16 + 600 weight was too
 * chunky and the 1px border showed a faint rectangular halo behind the
 * pill in Annie's screenshot. Shadow-only now, no border.
 * ========================================================================= */
.adm-nav a {
  padding: 5px 13px;
  border-radius: 999px;
  background: #fff;
  color: var(--adm-blue);
  font-weight: 500;
  font-size: 13px;
  line-height: 1.4;
  border: 0;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .06),
              0 2px 4px rgba(15, 23, 42, .04);
  transition: transform .12s ease, box-shadow .15s ease, background .15s ease;
}
.adm-nav a:hover {
  background: var(--adm-blue-tint);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 2px 5px rgba(15, 23, 42, .08),
              0 5px 10px rgba(14, 30, 160, .12);
}
.adm-nav a.is-current {
  background: linear-gradient(180deg, #152dc7 0%, var(--adm-blue) 60%, var(--adm-blue-dark) 100%);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .08),
              0 3px 8px rgba(14, 30, 160, .22),
              inset 0 1px 0 rgba(255, 255, 255, .22);
}
.adm-nav a.is-current:hover { transform: none; }

/* =========================================================================
 * Postcode lookup dropdown (Ideal Postcodes) — mirror of the customer-side
 * styles in ffg.css, with admin tokens. Inserted by postcode-lookup.js
 * after the postcode input's flex wrapper.
 * ========================================================================= */
.postcode-lookup-dropdown {
  position: relative;
  margin-top: .35rem;
  border: 1px solid var(--adm-edge, #d8dde3);
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 4px 14px rgba(0,0,0,.08);
  max-height: 240px;
  overflow-y: auto;
  z-index: 10;
}
.postcode-lookup-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: .5rem .7rem;
  border: 0;
  border-bottom: 1px solid var(--adm-edge, #eef0f3);
  background: transparent;
  font: inherit;
  color: var(--adm-body, #1f2632);
  cursor: pointer;
}
.postcode-lookup-item:last-child { border-bottom: 0; }
.postcode-lookup-item:hover,
.postcode-lookup-item:focus {
  background: #f5f7fa;
  color: var(--adm-blue, #0e1ea0);
  outline: 0;
}
.postcode-lookup-empty,
.postcode-lookup-error {
  padding: .5rem .7rem;
  color: var(--adm-muted, #6b7280);
  font-size: 13px;
}
.postcode-lookup-error { color: #b00020; }
.postcode-lookup-btn.is-error { border-color: #b00020 !important; color: #b00020 !important; }

/* Diary card pulse — triggered when the operator jumps from the Quotes
   & Requests page via the day-link button. JS adds .diary-pulse for 15s,
   then removes it. Uses box-shadow + outline so it doesn't shift the
   absolute-positioned card layout. */
@keyframes diary-pulse-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(56, 130, 245, 0.0); }
  50%      { box-shadow: 0 0 0 6px rgba(56, 130, 245, 0.55), 0 0 16px 6px rgba(14, 30, 160, 0.45); }
}
.diary-booking.diary-pulse,
.forecourt-card.diary-pulse {
  position: relative;
  z-index: 5;
  animation: diary-pulse-glow 1.2s ease-in-out infinite;
  outline: 2px solid #0E1EA0;
  outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
  .diary-booking.diary-pulse,
  .forecourt-card.diary-pulse {
    animation: none;
    box-shadow: 0 0 0 4px rgba(56, 130, 245, 0.7);
  }
}
