/* =============================================================================
 * SMS WEB Designer — admin GUI styles.
 * Visual identity inspired by yarotech.net:
 *   - Dark-first palette (true black #0a0a0a) with subtle white surfaces
 *   - Yarotech brand triad accent (red / green / blue) used sparingly
 *   - Geist font (loaded from Google Fonts in _layout.ejs)
 *   - Theme variables drive everything; light mode swaps them
 * ============================================================================= */

/* ---- Yarotech brand triad (constant across themes) ---- */
:root {
  --brand-red:   #E53935;
  --brand-green: #2E9E2E;
  --brand-blue:  #5B8AC5;
}

/* ---- Light theme (default for daytime use) ---- */
:root {
  --fg: #18191c;
  --bg: #faf9f7;
  --muted: #565e6e;
  --accent: var(--brand-blue);
  --accent-hover: #4a78b5;
  --danger: var(--brand-red);
  --ok: var(--brand-green);
  --border: #d6d9de;
  --surface: #fff;
  --surface-alt: #f9fafb;
  --flash-bg: #fff3cd;
  --flash-border: #ffe69c;
  --badge-ok-bg: #dcfce7;
  --badge-err-bg: #fee2e2;
  --badge-muted-bg: #e5e7eb;
  --shadow-card: 0 1px 2px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.03);
}

/* ---- Dark theme (the yarotech.net look) ---- */
:root[data-theme="dark"] {
  --fg: #f4f4f5;
  --bg: #0a0a0a;
  --muted: #a1a1aa;
  --accent: #7BAEEF;            /* lighter brand-blue for AA contrast on near-black */
  --accent-hover: #94c2ff;
  --danger: #ff6b66;
  --ok: #4ade80;
  --border: rgba(255, 255, 255, 0.12);
  --surface: #131313;           /* subtle elevated surface — "rgba(255,255,255,0.02)" baked into a solid */
  --surface-alt: #1a1a1a;       /* "rgba(255,255,255,0.04)" baked in */
  --flash-bg: rgba(229, 57, 53, 0.12);
  --flash-border: rgba(229, 57, 53, 0.35);
  --badge-ok-bg: rgba(46, 158, 46, 0.15);
  --badge-err-bg: rgba(229, 57, 53, 0.15);
  --badge-muted-bg: rgba(255, 255, 255, 0.07);
  --shadow-card: 0 0 0 1px rgba(255,255,255,0.04);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --fg: #f4f4f5;
    --bg: #0a0a0a;
    --muted: #a1a1aa;
    --accent: #7BAEEF;
    --accent-hover: #94c2ff;
    --danger: #ff6b66;
    --ok: #4ade80;
    --border: rgba(255, 255, 255, 0.12);
    --surface: #131313;
    --surface-alt: #1a1a1a;
    --flash-bg: rgba(229, 57, 53, 0.12);
    --flash-border: rgba(229, 57, 53, 0.35);
    --badge-ok-bg: rgba(46, 158, 46, 0.15);
    --badge-err-bg: rgba(229, 57, 53, 0.15);
    --badge-muted-bg: rgba(255, 255, 255, 0.07);
    --shadow-card: 0 0 0 1px rgba(255,255,255,0.04);
  }
}

/* ---- Reset + base ---- */
* { box-sizing: border-box; }
body {
  margin: 0;
  font: 15px/1.62 "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* =============================================================================
 * Left sidebar navigation (SaaS-style) — replaces the former top nav bar.
 *   - Vertical rail: brand at top, scrollable link list, utility footer holding
 *     the theme toggle, guided-tour "?" trigger, collapse control, and Logout.
 *   - Collapsible to a slim icon-only rail. State persists in localStorage
 *     ('admin-sidebar-collapsed') and is applied to <html data-sidebar> before
 *     paint (inline script in _layout.ejs) so there's no flash.
 *   - On mobile it becomes an off-canvas left drawer toggled by #nav-toggle
 *     (see the responsive layer below).
 * ============================================================================= */
:root {
  --sidebar-w: 236px;             /* expanded rail width */
  --sidebar-w-collapsed: 68px;    /* icon-only rail width */
}
.layout {
  display: flex;
  align-items: flex-start;
  min-height: 100vh;
}
.sidebar {
  position: sticky;
  top: 0;
  align-self: flex-start;
  flex: 0 0 var(--sidebar-w);
  width: var(--sidebar-w);
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  overflow: hidden;               /* the nav list scrolls internally, not the rail */
  transition: flex-basis 0.18s ease, width 0.18s ease, transform 0.22s ease;
  z-index: 40;
}
/* Vertical triad accent along the right edge — the yarotech signature line,
   rotated from the old topnav's bottom border. */
.sidebar::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0; right: -1px;
  width: 1px;
  background: linear-gradient(180deg,
    transparent 0%,
    var(--brand-red) 22%,
    var(--brand-green) 50%,
    var(--brand-blue) 78%,
    transparent 100%);
  opacity: 0.5;
  pointer-events: none;
}

/* ---- Brand (top of the rail) ---- */
.sidebar-top {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 18px;
  min-height: 62px;
}
.brand {
  font-weight: 600;
  text-decoration: none;
  color: var(--fg);
  font-size: 15px;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;          /* long business name -> "Web Agency" drops to the next line instead of being clipped */
  gap: 2px 10px;            /* row-gap 2px when wrapped, column-gap 10px inline */
  min-width: 0;
}
.brand-logo { height: 30px; width: auto; display: block; flex-shrink: 0; }
.brand-logo-dark { display: none; }
:root[data-theme="dark"] .brand-logo-light { display: none; }
:root[data-theme="dark"] .brand-logo-dark  { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo-light { display: none; }
  :root:not([data-theme="light"]) .brand-logo-dark  { display: block; }
}
.brand-text { line-height: 1; white-space: nowrap; }
/* Logo-less fallback: the tenant's business name as an accent-colored wordmark
   beside the constant "Web Agent" product name. Correct in light + dark via the
   theme var --accent (picks up the per-tenant accent injected by _layout.ejs). */
.brand-name {
  font-size: 16.5px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--accent);
  white-space: normal;      /* a long name wraps across lines within the sidebar */
  word-break: break-word;
  min-width: 0;
}

/* ---- Nav links (vertical list). #topnav-menu is preserved as the container. */
.sidebar-nav {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
}
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  transition: background 0.14s ease, color 0.14s ease;
}
.sidebar-nav a:hover { color: var(--fg); background: var(--surface-alt); }
.sidebar-nav a.active { color: var(--accent); background: rgba(91, 138, 197, 0.12); }
/* Unread badge on the "What's New" + "Flags" nav items — a small red count pill,
   top-right of the item so it shows in both expanded and collapsed (icon-only)
   sidebar modes. BOTH host items MUST be position:relative, or the absolutely-
   positioned badge escapes to the nearest positioned ancestor and shows up as a
   stray dot near the top (this was the bug for the Flags badge). */
#nav-updates, #nav-flags { position: relative; }
.nav-badge {
  position: absolute; top: 5px; right: 8px; box-sizing: border-box;
  min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 700; line-height: 1;
  background: #e5393e; color: #fff; border-radius: 8px; pointer-events: none;
}
/* The author `display:inline-flex` above beats the [hidden] attribute's UA
   `display:none`, so a count-0 badge would linger as an EMPTY red dot (the JS
   only sets `hidden`, expecting that to hide it). This makes `hidden` actually
   hide the badge — for both Flags and What's New. */
.nav-badge[hidden] { display: none; }
/* One-time dashboard coachmark — an arrow tooltip pointing at the "+ New Client &
   Site" button (mirrors the chat "View Site" coachmark). Fixed + viewport-clamped
   by JS, so it's safe on any width. */
.dash-coach {
  position: fixed; z-index: 200; display: none;
  max-width: min(270px, calc(100vw - 16px));
  padding: 10px 13px; background: #2563eb; color: #fff; border-radius: 10px;
  font-size: 13.5px; font-weight: 600; line-height: 1.35;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35); cursor: pointer;
}
.dash-coach.show { display: block; animation: dashCoachIn 0.25s ease-out; }
@keyframes dashCoachIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.dash-coach .dash-coach-arrow {
  position: absolute; top: -7px; left: 20px; width: 0; height: 0;
  border-left: 8px solid transparent; border-right: 8px solid transparent;
  border-bottom: 8px solid #2563eb;
}
:root[data-theme="dark"] .sidebar-nav a.active { background: rgba(123, 174, 239, 0.14); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sidebar-nav a.active { background: rgba(123, 174, 239, 0.14); }
}
.nav-ico { width: 20px; height: 20px; flex-shrink: 0; }
.nav-label { overflow: hidden; text-overflow: ellipsis; }

/* ---- Utility footer (theme toggle, tour "?", collapse control, Logout) ---- */
.sidebar-foot {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--border);
}
.sidebar-tools { display: flex; align-items: center; gap: 8px; }
/* #11 — iOS-style sliding light/dark switch (replaces the plain emoji button). Same
   #theme-toggle id + click logic; the JS flips .is-dark to match the effective theme
   and the knob (carrying the current mode's icon) slides. `.rdy` gates the transition
   so a dark-mode load doesn't animate on first paint. */
#theme-toggle.theme-switch {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 4px 6px; border: 0; background: none; cursor: pointer; color: var(--fg);
  font: inherit; -webkit-tap-highlight-color: transparent;
}
#theme-toggle.theme-switch .theme-switch-track {
  position: relative; box-sizing: border-box; flex: 0 0 auto;
  width: 46px; height: 25px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-alt);
}
#theme-toggle.theme-switch.rdy .theme-switch-track { transition: background .28s ease, border-color .28s ease; }
#theme-toggle.theme-switch .theme-switch-knob {
  position: absolute; top: 2px; left: 3px; width: 19px; height: 19px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.30);
  display: flex; align-items: center; justify-content: center; font-size: 11px; line-height: 1;
}
#theme-toggle.theme-switch.rdy .theme-switch-knob { transition: transform .28s cubic-bezier(.5, .1, .3, 1.35); }
#theme-toggle.theme-switch .theme-switch-knob::after { content: "☀️"; }
#theme-toggle.theme-switch .theme-switch-text { font-size: 13px; font-weight: 500; letter-spacing: .01em; }
#theme-toggle.theme-switch.is-dark .theme-switch-track { background: color-mix(in srgb, var(--accent) 52%, #12151b); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
#theme-toggle.theme-switch.is-dark .theme-switch-knob { transform: translateX(21px); }
#theme-toggle.theme-switch.is-dark .theme-switch-knob::after { content: "🌙"; }
#theme-toggle.theme-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
/* Collapsed rail: hide the word, keep just the switch. */
:root[data-sidebar="collapsed"] #theme-toggle.theme-switch .theme-switch-text { display: none; }
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  padding: 0;
  min-height: 0;                  /* override the global button min-height */
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  transition: color 0.14s ease, border-color 0.14s ease, background 0.14s ease;
}
.icon-btn:hover { color: var(--accent); border-color: var(--accent); background: var(--surface-alt); }
.tour-trigger { font-weight: 700; }
/* Labelled "? Tour" pill — the top-right guided-tour launcher beside New Client & Site. */
.tour-pill {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  width: auto; height: 36px; padding: 0 13px; min-height: 0;
  border: 1px solid var(--border); border-radius: 8px; background: transparent;
  color: var(--muted); font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer;
  transition: color 0.14s ease, border-color 0.14s ease, background 0.14s ease;
}
.tour-pill:hover { color: var(--accent); border-color: var(--accent); background: var(--surface-alt); }
.tour-pill .tour-pill-q { font-weight: 800; font-size: 15px; line-height: 1; }
.sidebar-collapse { margin-left: auto; } /* push the collapse toggle to the far edge */
.sidebar-collapse .chev { width: 16px; height: 16px; transition: transform 0.18s ease; }
.sidebar-logout {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  transition: background 0.14s ease, color 0.14s ease;
}
.sidebar-logout:hover { color: var(--danger); background: var(--surface-alt); }
.sidebar-logout .nav-ico { width: 20px; height: 20px; flex-shrink: 0; }

/* ---- Content column — sits beside the rail and flexes to fill the rest. */
.content { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

/* ---- "+ New Site" quick-action -----------------------------------------------
 * A persistent primary CTA to the new-build form (/admin/builds/new).
 * Desktop: a slim top bar (.content-topbar) pins it to the top-right of the
 * content column, lined up with <main>'s right edge. Mobile: the same button is
 * relocated into .mobile-topbar (see the responsive layer) beside the hamburger.
 * Background uses --accent / --accent-hover, so it tracks the injected per-tenant
 * brand accent AND dark mode automatically, matching the app's other primary
 * buttons (which are <button>s — this is an <a>, hence the parallel rules). */
.content-topbar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;                  /* space between the tour "?" and the New Client & Site CTA */
  width: 100%;
  max-width: 1320px;          /* match <main> so the button aligns with its right edge */
  margin: 0;
  padding: 20px 28px 0;       /* 28px sides == <main>'s horizontal padding */
}
.new-site-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  padding: 9px 16px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: background 0.15s ease, transform 0.05s ease;
}
.new-site-btn:hover { background: var(--accent-hover); color: #fff; }
.new-site-btn:active { transform: translateY(1px); }
.new-site-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(91, 138, 197, 0.35); }
.new-site-ico { width: 17px; height: 17px; flex-shrink: 0; }

/* Mobile-only chrome — hidden on desktop, enabled in the responsive layer. */
.mobile-topbar { display: none; }
.sidebar-backdrop { display: none; }

/* ---- Collapsed icon-rail — desktop only. Mobile keeps full labels in its
   drawer, so these rules are gated ≥769px to avoid clashing with it. ---- */
@media (min-width: 769px) {
  :root[data-sidebar="collapsed"] { --sidebar-w: var(--sidebar-w-collapsed); }
  :root[data-sidebar="collapsed"] .brand-text,
  :root[data-sidebar="collapsed"] .brand-name,
  :root[data-sidebar="collapsed"] .nav-label { display: none; }
  :root[data-sidebar="collapsed"] .sidebar-top { justify-content: center; padding: 16px 8px; }
  :root[data-sidebar="collapsed"] .brand { gap: 0; }
  :root[data-sidebar="collapsed"] .sidebar-nav { padding: 8px 10px; }
  :root[data-sidebar="collapsed"] .sidebar-nav a,
  :root[data-sidebar="collapsed"] .sidebar-logout { justify-content: center; gap: 0; padding-left: 0; padding-right: 0; }
  :root[data-sidebar="collapsed"] .sidebar-foot { padding: 10px 8px; }
  :root[data-sidebar="collapsed"] .sidebar-tools { flex-direction: column; }
  :root[data-sidebar="collapsed"] .sidebar-collapse { margin-left: 0; }
  :root[data-sidebar="collapsed"] .sidebar-collapse .chev { transform: rotate(180deg); }
}

/* ---- Guided tour: stationary bubble + spotlight ------------------------------
 * Driven by the engine in _layout.ejs. Two fixed-position layers plus the bubble:
 *   .tour-dim       — a plain full-screen dim for target-less steps (Welcome,
 *                     the wrap recap).
 *   .tour-spotlight — a transparent box sized (in JS) to the current target's
 *                     bounding rect. Its huge box-shadow dims the whole rest of
 *                     the page, and a 3px accent ring makes the target pop.
 *                     pointer-events:none, so it never blocks the target or the
 *                     tour's own demo clicks. Repositioned on scroll/resize and
 *                     briefly tracked after each step (smooth-scroll + reflow).
 *   .tour-tip       — the instruction bubble. Fixed at the bottom-centre of the
 *                     content column (never over the rail); only its inner
 *                     content changes between steps, so it stays put.
 * -------------------------------------------------------------------------- */
.tour-dim {
  position: fixed; inset: 0; z-index: 9998;
  /* Dim + blur the page behind target-less steps (the first-login Welcome popup and
     the wrap-up recap) so the bubble reads as a focused modal. It's cleared the
     moment a targeted step takes over (render() swaps the dim for the spotlight) or
     the tour is skipped/finished — so it only shows while the centred bubble is up. */
  background: rgba(0, 0, 0, 0.42);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: tourFade 0.18s ease;
}
@keyframes tourFade { from { opacity: 0; } to { opacity: 1; } }
.tour-spotlight {
  position: fixed; z-index: 9998; top: 0; left: 0; width: 0; height: 0;
  border-radius: 10px;
  box-shadow: 0 0 0 3px var(--accent), 0 0 0 7px color-mix(in srgb, var(--accent) 35%, transparent), 0 8px 26px rgba(0, 0, 0, 0.28);
  pointer-events: none;                 /* never trap clicks — incl. the demo act() clicks */
}
.tour-tip {
  position: fixed; z-index: 10000;
  left: 50%; bottom: 28px; transform: translateX(-50%);
  width: 440px; max-width: calc(100vw - 32px);
  max-height: calc(100vh - 56px); overflow: auto;
  background: var(--surface); color: var(--fg);
  border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4); padding: 19px 22px;
  font-size: 15.5px; animation: tourPop 0.18s ease;
}
@keyframes tourPop { from { opacity: 0; transform: translateX(-50%) translateY(8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
/* Recentre in the content column so the bubble never sits over the rail.
   --sidebar-w tracks the collapsed width automatically, so this stays correct
   whether the menu is expanded or collapsed. Desktop only — on mobile the rail
   is an off-canvas drawer and the content is full width. */
@media (min-width: 769px) {
  .tour-tip { left: calc(50% + var(--sidebar-w) / 2); }
}
/* Target-less steps (Welcome, wrap recap): centre the bubble on screen. */
.tour-tip.tour-tip-center {
  top: 50%; bottom: auto; transform: translate(-50%, -50%); animation: none;
}
@media (min-width: 769px) {
  .tour-tip.tour-tip-center { left: calc(50% + var(--sidebar-w) / 2); }
}
.tour-title { font-weight: 600; font-size: 18px; margin-bottom: 8px; }
.tour-body { color: var(--muted); line-height: 1.58; }
.tour-body b { color: var(--fg); font-weight: 600; }
.tour-body i { font-style: italic; }
.tour-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 16px; gap: 8px; }
.tour-count { font-size: 12.5px; color: var(--muted); }
.tour-actions { display: flex; gap: 6px; }
.tour-btn { font: inherit; font-size: 13.5px; padding: 7px 14px; border-radius: 6px; cursor: pointer; border: 1px solid var(--border); background: transparent; color: var(--fg); min-height: 0; }
.tour-btn.tour-next { background: var(--accent); color: #fff; border-color: var(--accent); }
.tour-btn.tour-skip { color: var(--muted); border-color: transparent; }
.tour-btn.tour-skip:hover { color: var(--fg); }

/* Go-live two-factor nudge (modal) — see _layout.ejs #twofaWarn. */
.twofa-warn-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 11000; padding: 16px; animation: tourFade 0.15s ease; }
.twofa-warn-backdrop[hidden] { display: none; }
.twofa-warn-box { background: var(--surface); color: var(--fg); border: 1px solid var(--border); border-radius: 14px; max-width: 440px; width: 100%; padding: 26px 26px 22px; box-shadow: 0 20px 60px rgba(0,0,0,0.42); text-align: center; }
.twofa-warn-box p { text-align: left; }

/* ---- Page container ---- */
main { max-width: 1320px; margin: 28px 0; padding: 0 28px; }

/* ---- Flash / banner ---- */
.flash {
  padding: 11px 15px;
  background: var(--flash-bg);
  border: 1px solid var(--flash-border);
  border-radius: 6px;
  margin-bottom: 18px;
}

/* ---- Headings ---- */
h1, h2, h3 { color: var(--fg); letter-spacing: -0.015em; }
h1 { font-size: 24px; margin: 0 0 18px; font-weight: 600; }
h2 { font-size: 18px; margin: 28px 0 12px; font-weight: 600; }
h3 { font-size: 15px; margin: 18px 0 8px; font-weight: 600; }
/* #8 — clearer separation between the stacked <h2> + card sections on the config
   pages (Settings, Branding/DNS) so they stop reading as one run-on block. Targets
   only a section header that directly precedes a card; the first one on a page
   (right after the <h1>) keeps its normal spacing with no divider. */
h2:has(+ .card), h2:has(+ form.card) { margin-top: 46px; padding-top: 24px; border-top: 1px solid var(--border); }
h1 + h2:has(+ .card), h1 + h2:has(+ form.card) { margin-top: 22px; padding-top: 0; border-top: 0; }

/* ---- Tables ----
 * Tables are block-level with horizontal scroll built in. Each cell stays on
 * a single line (phone numbers, slugs, IDs, paths all read the long way) and
 * the table scrolls horizontally inside its own container when content is
 * wider than the available width. Vertical overflow stays hidden so the
 * rounded corners still clip cleanly. The exception is `.kvs` (key-value)
 * tables — those are used for label/value layout, not tabular data, so we
 * let their values wrap naturally below. */
table {
  display: block;
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  box-shadow: var(--shadow-card);
}
th, td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
  vertical-align: top;
}
tr:last-child td { border-bottom: 0; }
th {
  background: var(--surface-alt);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
/* Key-value tables (customer detail's Phone / Email / Status panel) hold
 * descriptive text per row — let values wrap naturally rather than scroll. */
.kvs td { white-space: normal; }

/* ---- Data tables fill the widened content column on desktop ----
   The base `table` rule is display:block so tables horizontally scroll on
   phones; on a wide screen that shrink-wraps a table to its content and leaves
   dead space to the right of the 1320px column. On desktop, promote real data
   tables to true full-width table layout so they use the whole container.
   Key-value tables (.kvs) stay compact; mobile keeps the block+scroll base. */
@media (min-width: 769px) {
  main table:not(.kvs) { display: table; width: 100%; }
}

/* Staging clients table: faint "not live yet" tint on desktop (on phones the
   .rtable cards carry it — see the responsive layer). Replaces the old inline
   style on the <table>. */
.staging-cards { background: rgba(234, 179, 8, 0.04); border-color: rgba(234, 179, 8, 0.25); }

/* ---- Cards / forms ---- */
form.card, .card {
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 18px;
  border-radius: 8px;
  box-shadow: var(--shadow-card);
}
label { display: block; margin: 12px 0 5px; font-weight: 500; font-size: 13px; color: var(--fg); }

/* ---- Inputs ---- */
input[type=text], input[type=password], input[type=email], input[type=number],
select, textarea {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 14px;
  background: var(--surface);
  color: var(--fg);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(91, 138, 197, 0.18);
}
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 0.6; }

/* ---- Buttons ---- */
button {
  background: var(--accent);
  color: #fff;
  border: 0;
  padding: 9px 18px;
  border-radius: 6px;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}
button:hover { background: var(--accent-hover); }
button:active { transform: translateY(1px); }
button.danger { background: var(--danger); }
button.danger:hover { filter: brightness(1.08); }
button.secondary {
  background: var(--surface);
  color: var(--accent);
  border: 1px solid var(--accent);
}
button.secondary:hover { background: rgba(91, 138, 197, 0.08); }

/* ---- Badges ---- */
.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}
.badge.ok    { background: var(--badge-ok-bg);    color: var(--ok);     border: 1px solid rgba(46, 158, 46, 0.45); }
.badge.err   { background: var(--badge-err-bg);   color: var(--danger); border: 1px solid rgba(229, 57, 53, 0.45); }
.badge.muted { background: var(--badge-muted-bg); color: var(--muted);  border: 1px solid var(--border); }
.badge.warn {
  background: rgba(245, 158, 11, 0.16);
  color: #b45309;
  border: 1px solid rgba(245, 158, 11, 0.45);
}
.badge.info {
  background: rgba(91, 138, 197, 0.16);
  color: #3730a3;
  border: 1px solid rgba(91, 138, 197, 0.45);
}
:root[data-theme="dark"] .badge.warn { color: #fbbf24; }
:root[data-theme="dark"] .badge.info { color: #93c5fd; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .badge.warn { color: #fbbf24; }
  :root:not([data-theme="light"]) .badge.info { color: #93c5fd; }
}
button.badge { border: 0; cursor: pointer; font-family: inherit; }

/* ---- Layout helpers ---- */
.row { display: flex; gap: 18px; }
.col { flex: 1; }
.muted { color: var(--muted); }
.kvs td:first-child { color: var(--muted); width: 200px; font-weight: 500; }

/* ---- Code blocks / inline code ---- */
code {
  background: var(--surface-alt);
  padding: 2px 6px;
  border-radius: 4px;
  font-family: "Geist Mono", "JetBrains Mono", Consolas, monospace;
  font-size: 12.5px;
  color: var(--fg);
  border: 1px solid var(--border);
}
pre code { background: transparent; border: 0; padding: 0; }

/* ---- Links inside body content ---- */
a { color: var(--accent); transition: color 0.15s ease; }
a:hover { color: var(--accent-hover); }

/* =============================================================================
 * Hamburger button — lives in .mobile-topbar (hidden on desktop, shown ≤768px).
 * Three stacked bars that morph into an X when the drawer is open.
 * ============================================================================= */
.nav-toggle {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 40px; height: 38px;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  min-height: 0;            /* override the global button min-height */
}
.nav-toggle span {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--fg);
  border-radius: 1px;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.layout[data-menu-open="true"] .nav-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.layout[data-menu-open="true"] .nav-toggle span:nth-child(2) { opacity: 0; }
.layout[data-menu-open="true"] .nav-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* =============================================================================
 * Universal overflow safety. Long unbroken strings (file paths in <code>,
 * URLs) shouldn't push the page wider than the viewport — let them wrap.
 * ============================================================================= */
code { overflow-wrap: anywhere; word-break: break-word; }
pre  { white-space: pre-wrap; overflow-wrap: anywhere; }

/* Wrap any table in a horizontal-scroll container at any screen size when its
   natural width exceeds the parent. We do this via the table itself becoming
   a block-level scroll wrapper on small screens (see media query below). */

/* The one-line mobile "Chats" cell is hidden on desktop (the three 24h/3d/7d
 * number columns show instead); the responsive layer swaps them on phones. */
td.chat-combined { display: none; }
/* "Chats" group label sits to the LEFT of the 24h column header (absolutely placed
 * so it doesn't widen the column) — this keeps 24h/3d/7d centered directly above
 * their number columns, with "Chats" to the side. */
th.chats-head { position: relative; }
th.chats-head::before { content: "Chats"; position: absolute; right: 100%; margin-right: 14px; white-space: nowrap; }

/* #10 — active-build rows shown inside the dashboard's Open-sessions card. */
#active-builds { display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; }
#active-builds:empty { display: none; }
.ab-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 9px 12px; border: 1px solid var(--border); border-radius: 8px; background: rgba(245, 158, 11, 0.08); font-size: 13px; }
.ab-row .ab-main { font-weight: 500; }
.ab-row .ab-meta { color: var(--muted); font-size: 12.5px; }
.ab-row .ab-bar { flex: 0 1 150px; height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
.ab-row .ab-bar > span { display: block; height: 100%; background: #f59e0b; transition: width .4s ease; }
.ab-row .ab-cancel { margin-left: auto; }

/* =============================================================================
 * Responsive layer.
 * ============================================================================= */
@media (max-width: 768px) {
  /* Sidebar collapses to an off-canvas left drawer; a sticky top bar with the
     hamburger + brand replaces it in the content column. #nav-toggle toggles
     `data-menu-open` on .layout. */
  .sidebar {
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: 268px;
    flex-basis: 268px;
    height: 100%;
    transform: translateX(-100%);
    z-index: 50;
  }
  .layout[data-menu-open="true"] .sidebar {
    transform: translateX(0);
    box-shadow: 0 0 42px rgba(0, 0, 0, 0.30);
  }
  .sidebar-collapse { display: none; }   /* collapse control is desktop-only */
  .content { width: 100%; }

  .mobile-topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    position: sticky;
    top: 0;
    z-index: 30;
    padding: 10px 14px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
  }
  .mobile-topbar .brand { font-size: 14px; flex-wrap: nowrap; }
  .mobile-topbar .brand-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mobile-topbar .brand-name { font-size: 15.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mobile-topbar .brand-logo { height: 26px; flex-shrink: 0; }

  /* New Site shortcut: the desktop top bar folds away and the button reappears
     here, pushed to the right edge beside the brand and sized level with the
     hamburger. The brand between them shrinks/ellipsises to make room. */
  .content-topbar { display: none; }
  .mobile-topbar .new-site-btn {
    margin-left: auto;
    padding: 8px 13px;
    font-size: 13.5px;
    height: 38px;              /* level with the 38px hamburger */
  }

  .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 45;
    background: rgba(0, 0, 0, 0.42);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, visibility 0.2s ease;
  }
  .layout[data-menu-open="true"] .sidebar-backdrop { opacity: 1; visibility: visible; }

  /* Page container. NO overflow:hidden — we don't want to clip content,
     we want children to handle their own overflow. */
  main { padding: 0 14px; margin: 18px auto; max-width: 100%; }

  /* Typography scales down a touch */
  h1 { font-size: 21px; margin-bottom: 14px; word-wrap: break-word; }
  h2 { font-size: 16px; margin: 22px 0 10px; }
  h3 { font-size: 14px; }

  /* Cell density on phones (applies to every table). */
  main table th, main table td { padding: 9px 11px; font-size: 13px; }

  /* ---- Mobile data tables: stack into cards, never scroll sideways ----
     List/data tables carry `.rtable`. On phones each ROW becomes a card and
     each CELL a "LABEL / value" block (label from the cell's data-label), so a
     table only ever scrolls DOWN — never left/right. Long values (URLs, IDs,
     summaries) wrap instead of widening the row. `.kvs` + specialized tables
     (.dns-table, .domains-dns-table) keep their own layout. */
  main table.rtable {
    display: block;
    overflow: visible;                 /* drop the horizontal scroll box */
    border: 0;
    background: transparent;
    box-shadow: none;
    border-radius: 0;
  }
  main table.rtable thead { display: none; }   /* labels move into each cell */
  main table.rtable tbody { display: block; }
  main table.rtable tr {
    display: block;
    margin: 0 0 12px;
    padding: 4px 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: var(--shadow-card);
  }
  main table.rtable.staging-cards tr { background: rgba(234, 179, 8, 0.06); border-color: rgba(234, 179, 8, 0.30); }
  main table.rtable td {
    display: block;
    padding: 9px 0;
    border: 0;
    border-bottom: 1px solid var(--border);
    text-align: left;
    white-space: normal !important;    /* beat inline white-space:nowrap */
    overflow-wrap: anywhere;           /* wrap long URLs/IDs, don't overflow */
  }
  main table.rtable tr td:last-child { border-bottom: 0; }
  main table.rtable td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 3px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
  }
  /* Action-only cells (buttons / "view") set data-label="" — show value only. */
  main table.rtable td[data-label=""]::before { content: none; }
  main table.rtable td[data-label=""] { padding-top: 12px; }

  /* ---- Client-list cards on phones: bigger name (card title) + one-line Chats.
     The three desktop Chats columns (24h/3d/7d) collapse into a single "Chats"
     line, the client name reads as the card's title, and the base value size is
     bumped up so the card is comfortable to read on a phone. */
  main table.rtable td { font-size: 14.5px; }
  main table.rtable td.cust-name-cell::before { display: none; }   /* the name IS the title */
  main table.rtable td.cust-name-cell { padding-top: 13px; padding-bottom: 11px; }
  main table.rtable .cust-name { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
  main table.rtable td.chat-cell { display: none; }                /* hide the 3 separate columns */
  main table.rtable td.chat-combined { display: block; }
  main table.rtable td.chat-combined .cc-p { font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); margin-right: 3px; }
  main table.rtable td.chat-combined .cc-sep { color: var(--border); margin: 0 9px; }

  /* Condense the rest of the card: each short field (Nickname, URL, Chat, Status)
     becomes a "label … value" row — value pushed to the right to use the wasted
     space, and one line instead of two so there's much less to scroll. Name stays
     the full-width title; Chats keeps its inline one-liner. */
  main table.rtable.cust-cards tr { padding: 4px 14px; }
  main table.rtable.cust-cards td {
    display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
    padding: 8px 0; min-width: 0;
  }
  main table.rtable.cust-cards td::before { margin-bottom: 0; flex: 0 0 auto; }
  main table.rtable.cust-cards td > * { text-align: right; overflow-wrap: anywhere; min-width: 0; }
  main table.rtable.cust-cards td.cust-name-cell { display: block; padding: 12px 0 9px; }
  main table.rtable.cust-cards td.cust-name-cell > * { text-align: left; }
  main table.rtable.cust-cards td.chat-cell { display: none; }   /* keep the 3 columns hidden (compact rule above must not un-hide them) */
  main table.rtable.cust-cards td.chat-combined { display: block; padding: 8px 0; }
  main table.rtable.cust-cards td.chat-combined::before { display: inline; margin: 0 8px 0 0; }
  main table.rtable.cust-cards td.chat-combined > * { text-align: left; }

  /* Touch targets ≥44px — Apple HIG and Google Material both want this. */
  button { min-height: 44px; padding: 11px 18px; font-size: 14px; }
  .icon-btn { width: 38px; height: 38px; font-size: 16px; }

  /* ---- Client-page action buttons: a tidy 2-column grid on phones. They wrap
     into a ragged, uneven mess otherwise. Equal-width, full-tap-target buttons;
     the two dropdown actions (Announcement, Clear chat) span the full width so
     their menus have room and read as distinct. */
  main .customer-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; align-items: stretch; margin: 12px 0 18px; }
  main .customer-actions > * { margin: 0 !important; }
  main .customer-actions .customer-action { display: block; }
  main .customer-actions .customer-action button,
  main .customer-actions > form button,
  main .customer-actions > details > summary {
    width: 100%; box-sizing: border-box; height: auto; min-height: 44px;
    display: flex; align-items: center; justify-content: center; gap: 6px;
    text-align: center; font-size: 14px;
  }
  main .customer-actions > details.announce,
  main .customer-actions > details.clear-client { grid-column: 1 / -1; position: relative; }
  /* Move the two full-width dropdowns below the paired buttons so the grid packs
     tightly (no half-empty rows). Mobile-only via `order`; desktop order untouched. */
  main .customer-actions > details.announce { order: 90; }
  main .customer-actions > details.clear-client { order: 91; }
  main .customer-actions > details.clear-client > summary { font-size: 14px; height: auto; padding: 11px 16px; background: rgba(139, 92, 246, 0.14); color: #8b5cf6; border: 1px solid rgba(139, 92, 246, 0.40); border-radius: 6px; }
  main .customer-actions .announce-menu, main .customer-actions .clear-client-menu { left: 0; right: 0; width: auto; }

  /* Stack horizontal flex rows on mobile */
  .row { flex-direction: column; gap: 12px; }

  /* Key-value tables let the label column auto-size */
  .kvs td:first-child { width: auto; padding-right: 12px; }
  .kvs td { white-space: normal; }

  /* iOS Safari auto-zooms on any input with font-size < 16px. */
  input[type=text], input[type=password], input[type=email], input[type=number],
  input[type=tel], input[type=url], select, textarea {
    padding: 11px 12px;
    font-size: 16px;
  }

  /* Inline-stacked buttons in <p> get breathing room when they wrap rows. */
  p > form[style*="inline"], p > a > button, p > button { margin: 4px 4px 4px 0; }

  /* Inline forms (like the toggle button in customers_list) keep horizontal */
  form[style*="inline"] { display: inline-block; }

  /* Cards and forms tighten side padding */
  form.card, .card { padding: 16px; }

  /* Long inputs/textareas already use width:100% — make sure they don't blow
     past the form's padding box. */
  input, select, textarea { max-width: 100%; }
}

@media (max-width: 420px) {
  /* On real phones (≤iPhone SE width) hide the wordmark, keep just the logo. */
  .mobile-brand .brand-text { display: none; }
  .mobile-topbar { padding: 9px 12px; gap: 8px; }
  /* Tightest phones: the shortcut goes icon-only (label hidden, like the wordmark
     above) so hamburger + logo + shortcut all fit. aria-label keeps its name. */
  .mobile-topbar .new-site-btn { padding: 8px 10px; gap: 0; }
  .mobile-topbar .new-site-btn .new-site-label { display: none; }
  main { padding: 0 11px; }
  h1 { font-size: 20px; }
  h2 { font-size: 15px; }
  th, td { padding: 8px 9px; font-size: 12.5px; }
}

/* ---- Generic collapsible card (used for the maintenance auto-reply panel,
   dev-chat panel, and any other <details>-based settings group). Surface +
   border use the theme vars so it adapts without per-instance overrides. */
.card-collapsible {
  margin-bottom: 16px;
  padding: 12px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.card-collapsible > summary {
  cursor: pointer;
  font-weight: 500;
  color: var(--fg);
  list-style: none;
}
.card-collapsible > summary::marker { display: none; }
.card-collapsible > summary::-webkit-details-marker { display: none; }

/* ---- Activity tab: each SESSION (one client's chat conversation on one site)
   is a native <details>; its <summary> is a single click-to-toggle row and the
   expanded body holds that conversation's TASKS. Custom ▸/▾ caret (matching the
   audit list) since a flex <summary> drops the browser's default marker. */
.activity-session {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-card);
  margin-bottom: 10px;
  padding: 11px 14px;
}
.activity-session > summary {
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  list-style: none;
}
.activity-session > summary::marker { content: ''; }
.activity-session > summary::-webkit-details-marker { display: none; }
.activity-session > summary::before { content: '▸'; color: var(--muted); font-size: 11px; }
.activity-session[open] > summary::before { content: '▾'; }
.activity-session[open] > summary { margin-bottom: 6px; }
.activity-site { font-size: 14px; }
.activity-count { font-size: 12.5px; font-weight: 500; }
.activity-meta { font-size: 12.5px; }
.activity-from { margin-left: auto; font-size: 12.5px; }
.activity-body { padding-top: 2px; }
.activity-controls { margin: 4px 0 2px; }

/* ---- Flash variants — the base .flash uses --flash-bg/--flash-border (from
   theme vars). Warn/err/info variants use rgba tints that stay legible on
   both light and dark backgrounds. */
.flash.warn {
  background: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.45);
  color: var(--fg);
}
.flash.warn strong { color: #d97706; }
.flash.err {
  background: rgba(229, 57, 53, 0.10);
  border-color: rgba(229, 57, 53, 0.45);
  color: var(--fg);
}
.flash.err strong { color: var(--danger); }
.flash.info {
  background: rgba(91, 138, 197, 0.10);
  border-color: rgba(91, 138, 197, 0.45);
  color: var(--fg);
}
.flash.info strong { color: var(--accent); }
.flash.ok {
  background: rgba(46, 158, 46, 0.10);
  border-color: rgba(46, 158, 46, 0.45);
  color: var(--fg);
}
.flash.ok strong { color: var(--ok); }

/* Customers list: Production / Staging tabs. Underline-style accent for the
   active tab, matches the daily-report current-day pill in spirit but
   simpler. Persists selection in localStorage so a refresh keeps you put. */
.customers-tabs {
  display: flex;
  gap: 4px;
  margin: 18px 0 16px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.customers-tab {
  background: transparent;
  border: 0;
  padding: 9px 16px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  border-radius: 0;
  min-height: 0;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.customers-tab:hover { color: var(--fg); }
.customers-tab.active {
  color: var(--fg);
  border-bottom-color: var(--accent);
}
.customers-tab .count {
  color: var(--muted);
  font-weight: 400;
  font-size: 12px;
  margin-left: 4px;
}
.customers-tab .muted-hint {
  color: var(--muted);
  font-weight: 400;
  font-size: 11.5px;
  margin-left: 4px;
}

/* Per-page intro blurb shown directly under an <h1>. Stays muted so it
   doesn't compete with the page title, but full-width and slightly spaced
   above the first interactive element. */
.page-blurb {
  font-size: 13px;
  max-width: 760px;
  margin: -6px 0 18px;
  line-height: 1.5;
}

/* Customer-detail top action bar. All buttons share the same height +
   padding so they read as one row; semantic colors signal what the
   button does. Wraps cleanly on narrow screens. */
.customer-actions {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
  align-items: stretch;
  margin: 12px 0 18px;
  /* Full content width — the buttons stretch to line up with the cards below. */
}
.customer-actions > * { margin: 0; }
.customer-actions .customer-action {
  margin: 0;
  display: block;
}
.customer-actions .customer-action,
.customer-actions form button,
.customer-actions a button {
  text-decoration: none;
}
.customer-actions button {
  height: 36px;
  padding: 0 16px;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  margin: 0;
  min-height: 0;
  border-radius: 6px;
}
/* #2 — a tidy 5-column x 2-row grid (equal cells). `order` places each button
   into its grid cell regardless of source order; Announcement sits at the end of
   row 1 and Maintenance at the end of row 2. Missing buttons (by role or settings)
   simply compact — the grid stays five columns.
   row 1  View Site · Suspend Site · AI image generation · Edit client info · 📣 Announcement
   row 2  Client chat · Dev chat · Clear chat · Pause Chat · 🛠 Maintenance mode  */
.customer-actions .customer-action > button { width: 100%; box-sizing: border-box; }
.customer-actions > details > summary { width: 100%; box-sizing: border-box; display: flex; justify-content: center; }
.customer-actions a.customer-action:has(.view-site-cta) { order: 1; }
.customer-actions form:has(.suspend-cta), .customer-actions form:has(.unsuspend-cta) { order: 2; }
.customer-actions form#imagegen { order: 3; }
.customer-actions a.customer-action[href$="/edit"] { order: 4; }
.customer-actions details.announce { order: 5; }
.customer-actions a.customer-action:has(.cust-chat-cta) { order: 6; }
.customer-actions a.customer-action:has(.dev-chat-cta) { order: 7; }
.customer-actions details.clear-client { order: 8; }
.customer-actions form[action$="/toggle"] { order: 9; }
.customer-actions form:has(.maint-start-cta), .customer-actions form:has(.maint-end-cta) { order: 10; }
/* Maintenance dropdown keeps the same slot the old maintenance button had. */
.customer-actions details.announce.maint-dd { order: 10; }
/* Announcement now sits in the rightmost column, so open its dropdown leftward to
   keep it on-screen (its default is left-anchored). */
.customer-actions details.announce .announce-menu { left: auto; right: 0; }
/* Give the plain outline buttons (Edit client info, Pause Chat, AI image generation)
   a soft tinted fill so they read as buttons alongside the coloured ones, not empty
   boxes. Scoped to the action bar so .secondary elsewhere is untouched. */
.customer-actions button.secondary { background: color-mix(in srgb, var(--accent) 10%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 24%, var(--border)); }
.customer-actions button.secondary:hover { background: color-mix(in srgb, var(--accent) 17%, var(--surface)); }

/* "Open chat" CTA — accent blue (matches the primary brand) so the
   operator's most common daily action is the visually dominant button. */
button.cust-chat-cta { background: var(--accent); color: #fff; border: 0; }
button.cust-chat-cta:hover { background: var(--accent-hover); }

/* View Site CTA — green (same family as resume / un-suspend "positive" actions).
   Opens the client's live website; sits to the left of Open chat. */
button.view-site-cta { background: #16a34a; color: #fff; border: 0; }
button.view-site-cta:hover { background: #15803d; }

/* Dev chat CTA — purple, matches the inline .dev-panel accent so the
   operator knows both surfaces lead to the same operator-only channel. */
button.dev-chat-cta { background: #8b5cf6; color: #fff; border: 0; }
button.dev-chat-cta:hover { background: #7c3aed; }
:root[data-theme="dark"] button.dev-chat-cta { background: #a78bfa; color: #1a1d23; }
:root[data-theme="dark"] button.dev-chat-cta:hover { background: #c4b5fd; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) button.dev-chat-cta { background: #a78bfa; color: #1a1d23; }
  :root:not([data-theme="light"]) button.dev-chat-cta:hover { background: #c4b5fd; }
}

/* Maintenance-start: amber (warning), maintenance-end: green (restoring),
   resume: green (restoring). Resume + end-maintenance share a color
   because they're conceptually "bring it back to normal". */
button.maint-start-cta { background: #f59e0b; color: #fff; border: 0; }
button.maint-start-cta:hover { background: #d97706; }
button.maint-end-cta,
button.resume-cta { background: #16a34a; color: #fff; border: 0; }
button.maint-end-cta:hover,
button.resume-cta:hover { background: #15803d; }

/* Suspend CTA reuses .danger (red). Un-suspend mirrors the green resume button
   since it restores the live site AND un-pauses the account. */
button.unsuspend-cta { background: #16a34a; color: #fff; border: 0; }
button.unsuspend-cta:hover { background: #15803d; }

/* Collapsible section cards on the client detail page — essentials stay open,
   heavier/situational blocks (Activity, Move to Live Sites, Usage, Delete) tuck
   behind a tidy expandable summary so the page reads cleanly top-to-bottom. */
.cust-collapse { border: 1px solid var(--border); border-radius: 10px; margin: 16px 0; background: color-mix(in srgb, var(--accent) 3%, transparent); overflow: hidden; }
.cust-collapse > summary { cursor: pointer; list-style: none; padding: 13px 16px; font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 10px; user-select: none; }
.cust-collapse > summary::-webkit-details-marker { display: none; }
.cust-collapse > summary::before { content: "\25B8"; color: var(--accent); font-size: 13px; transition: transform 0.15s ease; flex: 0 0 auto; }
.cust-collapse[open] > summary::before { transform: rotate(90deg); }
.cust-collapse > summary:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.cust-collapse[open] > summary { border-bottom: 1px solid var(--border); }
.cust-collapse .cust-collapse-hint { font-weight: 400; font-size: 12.5px; color: var(--muted); margin-left: auto; text-align: right; min-width: 0; }
.cust-collapse .cust-collapse-body { padding: 6px 16px 16px; overflow-x: auto; }
.cust-collapse .cust-collapse-body > .help-tip:first-child,
.cust-collapse .cust-collapse-body > p:first-child { margin-top: 10px; }
.cust-collapse.danger-zone { border-color: color-mix(in srgb, #dc2626 45%, var(--border)); background: color-mix(in srgb, #dc2626 4%, transparent); }
.cust-collapse.danger-zone > summary,
.cust-collapse.danger-zone > summary::before { color: #dc2626; }
/* Client-page cards as a single-column grid so the Move to Live Sites card can
   lead (order:-1) for a staging client without moving its markup. min-width:0
   lets the wide chat-links table scroll inside its card instead of stretching. */
.cust-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; margin-top: 10px; }
/* order:6 is the default slot (the un-id'd SMS usage card lands here); the
   id-specific rules below override it, and the Danger zone (later, same
   specificity) wins order:7 so it stays last. */
.cust-cards > .cust-collapse { margin: 0; min-width: 0; order: 6; }
/* Card order, top -> bottom: Move to Live Sites leads for staging clients (its
   graduation CTA), then Activity, Chat links, Alias, Forwarding, Advanced sites,
   SMS usage; Danger zone always last. CSS order keeps the markup in place. */
.cust-cards > #go-live { order: -1; }
.cust-cards > #cust-activity { order: 1; }
.cust-cards > #sec-chat { order: 2; }
.cust-cards > #mirrors { order: 3; }
.cust-cards > #domains { order: 4; }
.cust-cards > #cust-sites { order: 5; }
.cust-cards > .danger-zone { order: 7; }

/* ---- "Move to production" box + DNS records table (customer detail) ----
   A clean card that groups: what it does -> the records -> how to add them ->
   the actions. The record table is scannable (Type / Name-Host / monospace
   Value) with a per-value Copy button, mirroring the DNS-tab explainer style. */
.go-live-card { max-width: 680px; margin: 4px 0 8px; }
.go-live-card .go-live-intro { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--fg); }
.go-live-liveat { margin: 0 0 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.go-live-err { color: var(--danger); margin: 6px 0; font-size: 13px; }
.go-live-block-label {
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--muted); margin: 18px 0 7px;
}
.dns-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.dns-table thead th {
  text-align: left; font-size: 11px; font-weight: 600; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--muted); padding: 2px 10px 7px;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.dns-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.dns-table tbody tr:last-child td { border-bottom: 0; }
.dns-table .dns-type, .dns-table .dns-name { white-space: nowrap; }
.dns-table .dns-type code { font-weight: 600; }
.dns-value { width: 100%; }
.dns-val {
  display: inline-block; user-select: all; word-break: break-all;
  background: var(--bg); border: 1px solid var(--border); border-radius: 5px;
  padding: 2px 7px; font-size: 12.5px; font-family: 'Geist Mono', Consolas, monospace;
  color: var(--fg); max-width: 100%; vertical-align: middle;
}
button.copy-val-btn {
  margin-left: 8px; padding: 3px 9px; height: auto; min-height: 0;
  font-size: 11px; font-weight: 500; vertical-align: middle;
  background: var(--surface); color: var(--accent);
  border: 1px solid var(--accent); border-radius: 5px;
}
button.copy-val-btn:hover { background: rgba(91, 138, 197, 0.08); }
.go-live-steps { margin: 0; padding-left: 20px; font-size: 13px; line-height: 1.6; color: var(--fg); }
.go-live-steps li { margin: 3px 0; }
.go-live-actions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border);
}

/* Dev-chat page header bar — holds the View-live-site pill (left) and the
   back-to-customer link (right). flex-row with a gap so they read as one
   compact strip above the H1. */
.dev-chat-header-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

/* ---- Dev chat full-page view (operator-only chat history per token).
   Distinct from the inline .dev-panel collapsible on customer_detail —
   this is a dedicated page that polls + sends messages live. */
.dev-chat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  max-height: 70vh;
  min-height: 360px;
}
.dev-chat-stream {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.dev-msg-row {
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 13px;
  max-width: 78%;
}
.dev-msg-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.dev-msg-time {
  color: var(--muted);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  font-size: 10.5px;
}
.dev-msg-text {
  white-space: pre-wrap;
  word-wrap: break-word;
  color: var(--fg);
}
.dev-msg-inbound {
  background: rgba(91, 138, 197, 0.10);
  border: 1px solid rgba(91, 138, 197, 0.30);
  align-self: flex-end;
}
.dev-msg-inbound .dev-msg-label { color: var(--accent); }
.dev-msg-outbound {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  align-self: flex-start;
}
.dev-msg-outbound .dev-msg-label { color: var(--muted); }
.dev-msg-system {
  background: rgba(46, 158, 46, 0.10);
  border: 1px solid rgba(46, 158, 46, 0.40);
  align-self: center;
  max-width: 92%;
}
.dev-msg-system .dev-msg-label { color: var(--ok); }
.dev-msg-error {
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.45);
  align-self: center;
  max-width: 92%;
}
.dev-msg-error .dev-msg-label { color: #d97706; }
.dev-msg-dev-in {
  background: rgba(139, 92, 246, 0.14);
  border: 1px solid rgba(139, 92, 246, 0.40);
  border-left: 3px solid #8b5cf6;
  align-self: flex-end;
}
.dev-msg-dev-in .dev-msg-label { color: #8b5cf6; }
.dev-msg-dev-out {
  background: rgba(167, 139, 250, 0.08);
  border: 1px solid rgba(167, 139, 250, 0.40);
  border-left: 3px solid #a78bfa;
  align-self: flex-start;
}
.dev-msg-dev-out .dev-msg-label { color: #a78bfa; }
:root[data-theme="dark"] .dev-msg-dev-in .dev-msg-label,
:root[data-theme="dark"] .dev-msg-dev-out .dev-msg-label { color: #c4b5fd; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .dev-msg-dev-in .dev-msg-label,
  :root:not([data-theme="light"]) .dev-msg-dev-out .dev-msg-label { color: #c4b5fd; }
}
.dev-chat-form {
  flex: 0 0 auto;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  background: var(--surface-alt);
  border-radius: 0 0 10px 10px;
}
.dev-chat-form textarea {
  width: 100%;
  margin: 0;
  resize: vertical;
}
.dev-chat-form-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
  gap: 12px;
}

/* ---- "Hidden from client" marker — a message the operator cleared from the
   CLIENT's chat view (migration 019). Muted here so the operator can tell at a
   glance what the customer no longer sees; still fully readable on this page. */
.dev-msg-hidden { opacity: 0.6; }
.dev-msg-hidden-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  background: var(--badge-muted-bg);
  color: var(--muted);
  border: 1px solid var(--border);
}

/* ---- "Clear from client's view" dropdown (operator-only). Purple accent to
   match the dev-chat theme; hides the native <details> marker and shows a
   popover menu of rolling windows + a restore action. */
.clear-client { position: relative; }
.clear-client > summary {
  list-style: none;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  box-sizing: border-box;
  padding: 0 16px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  background: rgba(139, 92, 246, 0.14);
  color: #8b5cf6;
  border: 1px solid rgba(139, 92, 246, 0.40);
}
.clear-client > summary::-webkit-details-marker { display: none; }
.clear-client[open] > summary { background: rgba(139, 92, 246, 0.24); }
.clear-client-caret { font-size: 10px; }
.clear-client-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  right: 0;
  width: 268px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.20);
}
.clear-client-hint { font-size: 11.5px; line-height: 1.45; margin: 0 0 10px; }
.clear-client-periods { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.clear-client-periods button {
  width: 100%;
  text-align: left;
  padding: 7px 12px;
  font-size: 13px;
  font-weight: 500;
  background: var(--surface-alt);
  color: var(--fg);
  border: 1px solid var(--border);
}
.clear-client-periods button:hover {
  background: rgba(139, 92, 246, 0.12);
  border-color: rgba(139, 92, 246, 0.40);
}
.clear-client-restore { margin: 10px 0 0; padding-top: 10px; border-top: 1px solid var(--border); }
.clear-client-restore button { width: 100%; }

/* Agency "Announcement" — inline dropdown in the client actions row. Posts a
   one-way green SYSTEM bubble into the client's chat that the agent ignores.
   Green to match the announcement bubble it produces. Mirrors .clear-client, but
   the menu opens to the LEFT edge since this sits mid-row next to Dev chat. */
.announce { position: relative; }
.announce > summary {
  list-style: none; user-select: none; display: inline-flex; align-items: center; gap: 6px;
  height: 36px; padding: 0 16px; border-radius: 6px; font-size: 13px; font-weight: 500;
  cursor: pointer; white-space: nowrap; box-sizing: border-box;
  background: #16a34a; color: #fff; border: 0;
}
.announce > summary::-webkit-details-marker { display: none; }
.announce > summary:hover,
.announce[open] > summary { background: #15803d; }
.announce-caret { font-size: 10px; }
.announce-menu {
  position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; width: 320px; max-width: 86vw;
  padding: 12px; background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.20);
}
.announce-hint { font-size: 11.5px; line-height: 1.45; margin: 0 0 10px; }
.announce-menu textarea {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 74px;
  padding: 8px 10px; font-size: 13px; font-family: inherit; line-height: 1.45;
  border: 1px solid var(--border); border-radius: 6px; background: var(--surface-alt); color: var(--fg);
}
.announce-menu .announce-send {
  margin: 8px 0 0; width: 100%; height: 34px; padding: 0 14px; font-size: 13px; font-weight: 600;
  background: #16a34a; color: #fff; border: 0; border-radius: 6px; cursor: pointer; white-space: nowrap;
}
.announce-menu .announce-send:hover { background: #15803d; }
/* Maintenance dropdown — same dropdown pattern as .announce, but amber-accented
   (matching the old maintenance button) so it reads as maintenance, not the
   green announcement. */
.announce.maint-dd > summary { background: #f59e0b; }
.announce.maint-dd > summary:hover,
.announce.maint-dd[open] > summary { background: #d97706; }
.announce.maint-dd .announce-menu .announce-send { background: #f59e0b; }
.announce.maint-dd .announce-menu .announce-send:hover { background: #d97706; }

/* ---- Audit log list — readable rows with severity color, expandable raw
   payload, and inline customer/job links. Replaces the older dense table
   layout. */
.audit-filters {
  display: flex;
  gap: 16px;
  align-items: end;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.audit-filters label { margin: 0; display: flex; flex-direction: column; font-size: 12px; }
.audit-filters select { width: auto; min-width: 180px; }
.audit-filters button { align-self: end; }
.audit-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.audit-row {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: 6px;
  padding: 10px 14px;
}
.audit-row.audit-err  { border-left-color: var(--danger); }
.audit-row.audit-warn { border-left-color: #d97706; }
.audit-row.audit-ok   { border-left-color: var(--ok); }
.audit-row.audit-info { border-left-color: var(--accent); }
.audit-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
  font-size: 12px;
}
.audit-head .badge { font-size: 10.5px; padding: 1px 8px; text-transform: uppercase; letter-spacing: 0.04em; }
.audit-customer { font-weight: 500; color: var(--fg); text-decoration: none; }
.audit-customer:hover { color: var(--accent); }
.audit-folder { font-size: 11.5px; }
.audit-job {
  font-family: Geist Mono, Consolas, monospace;
  font-size: 11.5px;
  color: var(--muted);
  text-decoration: none;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--surface-alt);
}
.audit-job:hover { color: var(--accent); }
.audit-time { margin-left: auto; white-space: nowrap; }
.audit-summary {
  font-size: 13.5px;
  color: var(--fg);
  word-break: break-word;
  margin-bottom: 4px;
}
.audit-details {
  font-size: 11px;
  margin-top: 4px;
}
.audit-details > summary {
  cursor: pointer;
  display: inline-block;
  font-size: 11px;
  list-style: none;
}
.audit-details > summary::marker { content: ''; }
.audit-details > summary::-webkit-details-marker { display: none; }
.audit-details > summary::before { content: '▸ '; opacity: 0.5; }
.audit-details[open] > summary::before { content: '▾ '; opacity: 0.5; }
.audit-details > pre {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 8px 10px;
  margin: 6px 0 0;
  font-family: Geist Mono, Consolas, monospace;
  font-size: 11px;
  line-height: 1.45;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--fg);
}

/* ---- Platform support session banner (shown at the very top of every admin
   page when an Yarotech operator is acting on behalf of this tenant). Stays
   amber on both themes for unmistakable distinction. */
.platform-session-banner {
  background: rgba(245, 158, 11, 0.16);
  border-bottom: 1px solid rgba(245, 158, 11, 0.45);
  padding: 8px 16px;
  font-size: 13px;
  color: var(--fg);
  text-align: center;
}
.platform-session-banner strong { color: #d97706; }
.platform-session-banner a { color: #d97706; text-decoration: underline; }
:root[data-theme="dark"] .platform-session-banner strong,
:root[data-theme="dark"] .platform-session-banner a { color: #fbbf24; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .platform-session-banner strong,
  :root:not([data-theme="light"]) .platform-session-banner a { color: #fbbf24; }
}
:root[data-theme="dark"] .flash.warn strong { color: #fbbf24; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .flash.warn strong { color: #fbbf24; }
}

/* ---- Card variants — for solid-color status cards (job_detail, build_detail
   success/error states). Same tint family as .flash variants for visual
   consistency, but as full cards with more padding. */
.card.card-ok    { background: rgba(46, 158, 46, 0.10);  border-color: rgba(46, 158, 46, 0.45); }
.card.card-err   { background: rgba(229, 57, 53, 0.10);  border-color: rgba(229, 57, 53, 0.45); }
.card.card-warn  { background: rgba(245, 158, 11, 0.12); border-color: rgba(245, 158, 11, 0.45); }
.card.card-info  { background: rgba(91, 138, 197, 0.10); border-color: rgba(91, 138, 197, 0.45); }
.card.card-ok strong  { color: var(--ok); }
.card.card-err strong { color: var(--danger); }
.card.card-warn strong { color: #d97706; }
.card.card-info strong { color: var(--accent); }
:root[data-theme="dark"] .card.card-warn strong { color: #fbbf24; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card.card-warn strong { color: #fbbf24; }
}

/* ---- Callout — sidebar-style warning/info block with a thick left border.
   Used in customers_form.ejs and similar advice surfaces. */
.callout {
  margin-top: 16px;
  padding: 14px 18px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-left: 4px solid var(--muted);
  border-radius: 0 6px 6px 0;
  color: var(--fg);
}
.callout.warn {
  background: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.45);
  border-left-color: #d97706;
}
:root[data-theme="dark"] .callout.warn { border-left-color: #fbbf24; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .callout.warn { border-left-color: #fbbf24; }
}

/* ---- Dropzone (file picker on build_new) — dashed-border target area that
   the operator drags files onto. Needs to read as "drop here" on either
   theme so the dashes + background tint adapt. */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: 8px;
  padding: 24px;
  text-align: center;
  background: var(--surface-alt);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
  color: var(--fg);
}
.dropzone:hover, .dropzone.dragover {
  background: var(--surface);
  border-color: var(--accent);
}

/* ---- Day-picker buttons (daily_report) — segmented row of dates where one
   is "current" (filled accent) and the rest are default (surface). */
.day-picker {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 24px;
  padding: 8px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.day-pick {
  flex: 1;
  min-width: 78px;
  padding: 8px 6px;
  text-align: center;
  border-radius: 6px;
  text-decoration: none;
  background: var(--surface);
  color: var(--fg);
  border: 1px solid var(--border);
}
.day-pick.current {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}

/* ---- Inline "open in tab" link pill (dashboard sessions table) ---- */
.link-pill {
  display: inline-block;
  margin-right: 8px;
  padding: 3px 10px;
  border-radius: 4px;
  text-decoration: none;
  font-size: 12px;
  font-family: inherit;
  line-height: normal;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background: rgba(91, 138, 197, 0.16);
  color: var(--accent);
  border: 1px solid rgba(91, 138, 197, 0.45);
}

/* ---- Dev chat panel (operator-only silent channel under each chat token) ----
   Purple accent in both themes; surface + border use the theme vars so the
   panel matches the rest of the page in light and dark mode. */
.dev-panel {
  margin: 0;
  padding: 8px 10px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.dev-panel > summary {
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  color: #8b5cf6;
  list-style: none;
}
.dev-panel > summary::marker { content: ''; }
.dev-panel > summary::-webkit-details-marker { display: none; }
.dev-panel-body { margin-top: 10px; }
.dev-panel-empty {
  color: var(--muted);
  font-size: 12px;
  margin: 0 0 8px;
}
.dev-msg {
  padding: 6px 10px;
  margin: 4px 0;
  border-radius: 4px;
  font-size: 13px;
  background: rgba(139, 92, 246, 0.08);
  border-left: 3px solid #8b5cf6;
  color: var(--fg);
}
.dev-msg.agent {
  background: rgba(167, 139, 250, 0.08);
  border-left-color: #a78bfa;
}
.dev-msg-label {
  font-size: 11px;
  text-transform: uppercase;
  font-weight: 600;
  color: #a78bfa;
}
.dev-msg-body {
  margin-left: 6px;
  white-space: pre-wrap;
}
.dev-textarea {
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 4px;
}
.dev-send-btn {
  padding: 5px 12px;
  font-size: 12px;
  min-height: 0;
}

/* Dark theme — the purple tints stand out more on near-black, so dial them
   down a bit and brighten the label color so it stays readable. */
:root[data-theme="dark"] .dev-panel > summary { color: #a78bfa; }
:root[data-theme="dark"] .dev-msg {
  background: rgba(167, 139, 250, 0.12);
  border-left-color: #a78bfa;
}
:root[data-theme="dark"] .dev-msg.agent {
  background: rgba(167, 139, 250, 0.06);
  border-left-color: #c4b5fd;
}
:root[data-theme="dark"] .dev-msg-label { color: #c4b5fd; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .dev-panel > summary { color: #a78bfa; }
  :root:not([data-theme="light"]) .dev-msg {
    background: rgba(167, 139, 250, 0.12);
    border-left-color: #a78bfa;
  }
  :root:not([data-theme="light"]) .dev-msg.agent {
    background: rgba(167, 139, 250, 0.06);
    border-left-color: #c4b5fd;
  }
  :root:not([data-theme="light"]) .dev-msg-label { color: #c4b5fd; }
}

/* =============================================================================
 * Help affordances — inline "?" tooltips + the in-dashboard knowledge base.
 * Added in the help/onboarding pass so a non-technical tenant understands what
 * each thing is and does. Always-visible blurbs/hints carry the essentials;
 * the "?" tooltips add detail on hover.
 * ============================================================================= */

/* Inline "?" help icon — small circular badge next to a label/heading that
   reveals a hint on hover or keyboard focus. Hint text lives in data-tip. */
.help {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--surface-alt); color: var(--muted);
  border: 1px solid var(--border);
  font-size: 10px; font-weight: 700; line-height: 1;
  cursor: help; margin-left: 5px; vertical-align: middle;
  position: relative; user-select: none; flex-shrink: 0;
}
.help:hover, .help:focus { color: var(--accent); border-color: var(--accent); outline: none; }
.help::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 9px); left: 50%; transform: translateX(-50%);
  width: max-content; max-width: 250px;
  background: var(--fg); color: var(--bg);
  padding: 8px 11px; border-radius: 6px;
  font-size: 12px; font-weight: 400; line-height: 1.45; letter-spacing: 0;
  text-align: left; text-transform: none; white-space: normal;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.12s ease, visibility 0.12s ease;
  z-index: 60; box-shadow: 0 6px 22px rgba(0,0,0,0.28);
}
.help::before {
  content: ''; position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--fg);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.12s ease, visibility 0.12s ease; z-index: 60;
}
.help:hover::after, .help:focus::after,
.help:hover::before, .help:focus::before { opacity: 1; visibility: visible; }

/* Tooltips now render as a body-level, FIXED-position bubble (.global-tip, shown
   by the JS in _layout.ejs) so they can never be clipped by a card/table overflow
   — the old ::after bubble got cut off inside scroll containers all over. We
   neutralise the pseudo-element tooltip here so there's no second, clipped bubble. */
.help::after, .help::before { display: none !important; content: none !important; }
.global-tip { position: fixed; z-index: 9999; display: none; max-width: 270px; background: var(--fg, #1a1d23); color: var(--bg, #ffffff); padding: 7px 11px; border-radius: 7px; font-size: 12.5px; font-weight: 400; line-height: 1.45; box-shadow: 0 8px 24px rgba(0,0,0,0.3); pointer-events: none; opacity: 0; transition: opacity .12s ease; }
.global-tip.visible { opacity: 1; }

/* Always-visible "tip" line under a control — muted, no hover needed. */
.help-tip { color: var(--muted); font-size: 12px; line-height: 1.5; margin: 4px 0 0; }

/* Per-page tour launcher — a small clickable "?" next to a page/section heading
   that starts the guided tour at just that section (window.startTourSection).
   Same subtle circular badge as .help, but a real button with a pointer cursor
   and an accent hover. Explicitly resets the global button padding/background. */
.tour-help {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; min-height: 0; padding: 0;
  border-radius: 50%; border: 1px solid var(--border);
  background: var(--surface-alt); color: var(--muted);
  font-size: 12px; font-weight: 700; line-height: 1;
  cursor: pointer; margin-left: 10px; vertical-align: middle; position: relative;
  flex-shrink: 0; transition: color 0.14s ease, border-color 0.14s ease, background 0.14s ease;
}
/* Small always-visible hint so people know the "?" plays a tour of THIS page. */
.tour-help::after {
  content: "Tour this page"; position: absolute; left: calc(100% + 7px); top: 50%;
  transform: translateY(-50%); font-size: 11px; font-weight: 500; color: var(--accent);
  white-space: nowrap; cursor: pointer; opacity: 0.9;
}
.tour-help:hover::after, .tour-help:focus-visible::after { text-decoration: underline; opacity: 1; }
@media (max-width: 640px) { .tour-help::after { display: none; } }
.tour-help:hover, .tour-help:focus-visible { color: var(--accent); border-color: var(--accent); background: var(--surface); outline: none; }

/* ---- Knowledge base (the Help page): sticky left topic nav + reading pane. */
.kb { display: flex; gap: 30px; align-items: flex-start; }
.kb-nav { flex: 0 0 210px; position: sticky; top: 20px; }
.kb-nav .kb-nav-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 600; margin: 0 0 8px 12px; }
.kb-nav ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.kb-nav a { display: block; padding: 8px 12px; border-radius: 6px; text-decoration: none; color: var(--muted); font-size: 13.5px; font-weight: 500; border-left: 2px solid transparent; }
.kb-nav a:hover { background: var(--surface-alt); color: var(--fg); }
.kb-nav a.active { background: var(--surface-alt); color: var(--accent); border-left-color: var(--accent); }
.kb-content { flex: 1; min-width: 0; max-width: 740px; }
.kb-section { margin-bottom: 38px; scroll-margin-top: 18px; }
.kb-section > h2:first-child { margin-top: 0; }
.kb-section p, .kb-section li { font-size: 14px; line-height: 1.62; color: var(--fg); }
.kb-section .muted { color: var(--muted); }
.kb-q { font-weight: 600; margin: 18px 0 4px; font-size: 14.5px; }
.kb-steps { padding-left: 20px; }
.kb-steps li { margin: 6px 0; }
.kb-lead { font-size: 15px; color: var(--muted); line-height: 1.6; margin: -6px 0 24px; max-width: 700px; }
@media (max-width: 768px) {
  .kb { flex-direction: column; gap: 16px; }
  .kb-nav { position: static; flex: 0 0 auto; width: 100%; }
  .kb-nav ul { flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .kb-nav a { border-left: 0; border: 1px solid var(--border); }
}

/* ── Feedback / support widget ─────────────────────────────────────────────
   A floating button pinned bottom-right on every dashboard page, plus a small
   modal for composing a message. Available to every logged-in user. Colours all
   flow from the shared tokens (--accent is overridden per-tenant in _layout.ejs)
   so it matches the brand and works in light AND dark mode. The FAB sits at
   z-index 40 — above page content, below the mobile nav backdrop (45) and the
   guided-tour overlay (9998) — so it never pokes through either. */
.feedback-fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 40;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 17px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  transition: background 0.15s ease, transform 0.05s ease, box-shadow 0.15s ease;
}
.feedback-fab:hover { background: var(--accent-hover); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.24); }
.feedback-fab:active { transform: translateY(1px); }
.feedback-fab:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(91, 138, 197, 0.45); }
.feedback-fab-ico { width: 18px; height: 18px; flex-shrink: 0; }
/* Hide the FAB while the mobile nav drawer is open (the FAB is a following
   sibling of .layout in the DOM), so it can't sit over the drawer backdrop. */
.layout[data-menu-open="true"] ~ .feedback-fab { display: none; }

.feedback-modal[hidden] { display: none; }
.feedback-modal {
  position: fixed;
  inset: 0;
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.feedback-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  animation: feedback-fade 0.12s ease;
}
.feedback-modal-card {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--surface);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  padding: 22px 22px 20px;
  animation: feedback-pop 0.14s ease;
}
@keyframes feedback-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes feedback-pop { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }
.feedback-modal-x {
  position: absolute;
  top: 10px;
  right: 12px;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 8px;
  border-radius: 6px;
}
.feedback-modal-x:hover { color: var(--fg); background: var(--surface-alt); }
.feedback-modal-title { margin: 0 26px 6px 0; font-size: 18px; font-weight: 600; }
.feedback-modal-sub { margin: 0 0 6px; font-size: 13px; color: var(--muted); line-height: 1.5; }
.feedback-optional { color: var(--muted); font-weight: 400; }
#feedback-form textarea { resize: vertical; min-height: 96px; }
.feedback-status { min-height: 18px; margin: 10px 0 0; font-size: 13px; font-weight: 500; }
.feedback-status-ok { color: var(--ok); }
.feedback-status-err { color: var(--danger); }
.feedback-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.feedback-btn {
  padding: 9px 18px;
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--border);
  transition: background 0.15s ease, transform 0.05s ease;
}
.feedback-btn:active { transform: translateY(1px); }
.feedback-btn-cancel { background: transparent; color: var(--fg); }
.feedback-btn-cancel:hover { background: var(--surface-alt); }
.feedback-btn-send { background: var(--accent); color: #fff; border-color: transparent; }
.feedback-btn-send:hover { background: var(--accent-hover); }
.feedback-btn-send:disabled { opacity: 0.6; cursor: default; }
body.feedback-open { overflow: hidden; }

@media (max-width: 768px) {
  /* Minimize the feedback FAB to a small icon-only circle, tucked into the corner
     and slightly recessed, so it stays reachable but never blocks other buttons. */
  .feedback-fab {
    right: 12px;
    bottom: 12px;
    width: 40px;
    height: 40px;
    padding: 0;
    gap: 0;
    justify-content: center;
    opacity: 0.6;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  }
  .feedback-fab:hover,
  .feedback-fab:active,
  .feedback-fab:focus-visible { opacity: 1; }
  .feedback-fab-label { display: none; }
  .feedback-fab-ico { width: 20px; height: 20px; }
}

/* Wide multi-column tables (inline inputs + several action buttons — e.g. the
   onboarding intake-links table) stay a real table down to 768px, which leaves
   them overflowing sideways on tablet / large-phone-landscape widths (~769–980px).
   Marking a table `rtable-wide` stacks it into cards earlier, so a data table only
   ever scrolls DOWN — never left/right. (It still stacks ≤768px via `.rtable`.) */
@media (max-width: 980px) {
  main table.rtable-wide { display: block; overflow: visible; border: 0; background: transparent; box-shadow: none; border-radius: 0; }
  main table.rtable-wide thead { display: none; }
  main table.rtable-wide tbody { display: block; }
  main table.rtable-wide tr { display: block; margin: 0 0 12px; padding: 4px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-card); }
  main table.rtable-wide td { display: block; padding: 9px 0; border: 0; border-bottom: 1px solid var(--border); text-align: left; white-space: normal !important; overflow-wrap: anywhere; }
  main table.rtable-wide tr td:last-child { border-bottom: 0; }
  main table.rtable-wide td::before { content: attr(data-label); display: block; margin-bottom: 3px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
  main table.rtable-wide td[data-label=""]::before { content: none; }
  main table.rtable-wide td[data-label=""] { padding-top: 12px; }
}
