/* =====================================================================
   Design tokens — THIN MOTION premium automotive design system.
   Two complete themes (light default, dark opt-in) share identical layout,
   spacing, and typography; only these token VALUES change per theme. Every
   other rule in this file reads the legacy --main-bg/--card-bg/... names
   below, which just alias the canonical --tm-* tokens — so retheming only
   ever requires editing this one block, never the ~140 rules that use it.
   ===================================================================== */
:root {
  /* Tells the browser to render native controls (checkboxes, radios, number-input
     spinners, date pickers, scrollbars) in a light-appropriate palette instead of
     always defaulting to a plain white/grey native look — the dark blocks below
     flip this to "dark" so the same controls stay in-theme automatically. */
  color-scheme: light;
  /* ---- Light theme (default) ---- */
  --tm-bg: #f5f5f3;
  --tm-sidebar: #fafaf9;
  --tm-surface: #ffffff;
  --tm-surface-raised: #ffffff;
  --tm-surface-hover: #f0f0ee;
  --tm-border: #e3e4e2;
  --tm-border-strong: #d3d5d2;
  --tm-text-primary: #17191a;
  --tm-text-secondary: #687076;
  --tm-text-tertiary: #969b9f;
  --tm-accent: #ff6400;
  --tm-accent-hover: #e95a00;
  --tm-accent-soft: rgba(255, 100, 0, 0.08);
  --tm-success: #198b4b;
  --tm-success-bg: #e5f4ec;
  --tm-warning: #b87514;
  --tm-warning-bg: #faf0e2;
  --tm-error: #d73c3c;
  --tm-error-bg: #fbe9e9;
  /* Strong neutral emphasis (filter tabs, active zoom/thumbnail state, ...) — near-
     black on light backgrounds, near-white on dark ones, always with readable
     contrasting content on top of it. Deliberately monochrome per the "most of the
     UI stays monochrome, orange only for primary/active-nav/progress" rule. */
  --tm-ink: #17191a;
  --tm-ink-contrast: #ffffff;
  --tm-shadow-sm: 0 1px 2px rgba(17, 17, 17, 0.04), 0 1px 1px rgba(17, 17, 17, 0.03);
  --tm-shadow-md: 0 6px 16px rgba(17, 17, 17, 0.07), 0 2px 4px rgba(17, 17, 17, 0.04);

  /* ---- Spacing (8px system) ---- */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 40px; --sp-8: 48px; --sp-9: 64px;

  /* ---- Radius ---- */
  --radius-xs: 6px;   /* small controls */
  --radius-sm: 7px;   /* buttons, inputs */
  --radius: 8px;      /* cards, panels */
  --radius-lg: 10px;  /* large special surfaces */

  /* ---- Motion ---- */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --dur: 150ms;

  /* ---- Legacy aliases (read by existing rules throughout this file) ---- */
  --main-bg: var(--tm-bg);
  --card-bg: var(--tm-surface);
  --text-primary: var(--tm-text-primary);
  --text-secondary: var(--tm-text-secondary);
  --border: var(--tm-border);
  --sidebar-bg: var(--tm-sidebar);
  --sidebar-text: var(--tm-text-primary);
  --sidebar-text-dim: var(--tm-text-secondary);
  --sidebar-active-bg: var(--tm-surface-hover);
  --success: var(--tm-success);
  --success-bg: var(--tm-success-bg);
  --processing: var(--tm-accent);
  --processing-bg: var(--tm-accent-soft);
  --attention: var(--tm-warning);
  --attention-bg: var(--tm-warning-bg);
  --accent: var(--tm-accent);
  --accent-bg: var(--tm-accent-soft);
  --shadow-sm: var(--tm-shadow-sm);
  --shadow-md: var(--tm-shadow-md);
}

/* ---- Dark theme: layered near-black surfaces, not pure black. Respects
   prefers-color-scheme for first-time visitors (no saved choice yet); an
   explicit [data-theme] (set by the switcher, see app.js) always wins. ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --tm-bg: #0b0d0e;
    --tm-sidebar: #0f1112;
    --tm-surface: #141719;
    --tm-surface-raised: #191c1f;
    --tm-surface-hover: #1e2225;
    --tm-border: #262b2e;
    --tm-border-strong: #343a3e;
    --tm-text-primary: #f5f6f6;
    --tm-text-secondary: #9aa0a6;
    --tm-text-tertiary: #686f75;
    --tm-accent: #ff6400;
    --tm-accent-hover: #ff7624;
    --tm-accent-soft: rgba(255, 100, 0, 0.12);
    --tm-success: #2cc56e;
    --tm-success-bg: rgba(44, 197, 110, 0.14);
    --tm-warning: #e59e2b;
    --tm-warning-bg: rgba(229, 158, 43, 0.14);
    --tm-error: #ef4a4a;
    --tm-error-bg: rgba(239, 74, 74, 0.14);
    --tm-ink: #f5f6f6;
    --tm-ink-contrast: #0b0d0e;
    /* Dark theme relies on borders/surface layering, not shadows. */
    --tm-shadow-sm: none;
    --tm-shadow-md: none;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --tm-bg: #0b0d0e;
  --tm-sidebar: #0f1112;
  --tm-surface: #141719;
  --tm-surface-raised: #191c1f;
  --tm-surface-hover: #1e2225;
  --tm-border: #262b2e;
  --tm-border-strong: #343a3e;
  --tm-text-primary: #f5f6f6;
  --tm-text-secondary: #9aa0a6;
  --tm-text-tertiary: #686f75;
  --tm-accent: #ff6400;
  --tm-accent-hover: #ff7624;
  --tm-accent-soft: rgba(255, 100, 0, 0.12);
  --tm-success: #2cc56e;
  --tm-success-bg: rgba(44, 197, 110, 0.14);
  --tm-warning: #e59e2b;
  --tm-warning-bg: rgba(229, 158, 43, 0.14);
  --tm-error: #ef4a4a;
  --tm-error-bg: rgba(239, 74, 74, 0.14);
  --tm-ink: #f5f6f6;
  --tm-ink-contrast: #0b0d0e;
  --tm-shadow-sm: none;
  --tm-shadow-md: none;
}

*:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--main-bg);
  color: var(--text-primary);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

a { color: inherit; text-decoration: none; }
/* Deliberately a real hyperlink blue, not the orange --accent brand color, so an inline
   text link reads as "click me" the way a link conventionally does — readable on both
   light and dark backgrounds without needing separate theme variants. */
.link-hyperlink { color: #4C8DFF; text-decoration: underline; }
.link-hyperlink:hover { opacity: 0.85; }
button { font-family: inherit; }
img { max-width: 100%; }

/* ---------- App shell ---------- */
/* A class selector setting its own `display` (.app-shell, .sidebar-nav a,
   .toolbar, ...) has higher specificity than the UA's own [hidden]{display:
   none}, so toggling the hidden attribute from JS would silently do nothing
   without this. Kept as one universal rule instead of a per-element
   exception, since [hidden] must always mean invisible regardless of what
   else targets that element. */
[hidden] { display: none !important; }

/* ---------- Modal ---------- */
/* position:absolute (not fixed) so the overlay scrolls away with the page
   like any other content, instead of staying pinned to the viewport while
   the user scrolls the vehicle grid behind it. openModal() sets `top` to
   the scroll position at the moment it's opened, so it still starts right
   where the user is currently looking; min-height keeps the backdrop
   covering at least one full viewport so "click outside to close" has
   something to click on immediately below the box too. */
.modal-overlay {
  position: absolute;
  left: 0;
  right: 0;
  min-height: 100vh;
  background: rgba(17, 17, 17, 0.55);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 24px;
  z-index: 1000;
}
.modal-box {
  background: var(--card-bg);
  border-radius: var(--radius);
  max-width: 960px;
  width: 100%;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  padding: 24px;
  position: relative;
}
.modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
}
.modal-box-lightbox {
  max-width: min(1200px, 90vw);
  text-align: center;
  padding: 20px;
}
.modal-box-lightbox img {
  max-width: 100%;
  max-height: calc(100vh - 160px);
  border-radius: calc(var(--radius) - 4px);
}
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 232px;
  flex: 0 0 232px;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  border-right: 1px solid var(--tm-border);
}

.sidebar-logo {
  display: flex;
  align-items: center;
  padding: 14px 10px 18px;
  flex: 0 0 auto;
}
.sidebar-logo img {
  width: 90%;
  height: auto;
}

.sidebar-scroll { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

.sidebar-group-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--sidebar-text-dim);
  padding: 14px 13px 6px;
}
.sidebar-group-label:first-child { padding-top: 2px; }

.sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px 8px 13px;
  border-radius: var(--radius-sm);
  border-left: 3px solid transparent;
  font-size: 13.5px;
  color: var(--sidebar-text);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.sidebar-nav a:hover { background: var(--sidebar-active-bg); }
.sidebar-nav a.active { background: var(--sidebar-active-bg); border-left-color: var(--accent); color: var(--tm-text-primary); font-weight: 600; }
.sidebar-nav a .nav-icon { width: 18px; height: 18px; flex: 0 0 auto; opacity: 0.8; }
.sidebar-nav a.active .nav-icon { opacity: 1; color: var(--accent); }
.sidebar-nav a:hover .nav-icon { opacity: 1; color: var(--accent); }

.sidebar-nav-secondary a { color: var(--sidebar-text-dim); font-size: 13px; }

/* Unresolved-feedback indicator (see GET /admin/feedback/unresolved-count) — on the
   sidebar's Admin nav item, and again on the admin page's own "Meldingen" section
   option, so a superadmin notices new feedback/low ratings without opening Admin
   first. Plain orange dot per Rob's own "al is het een oranje bolletje" ask, not a
   full popup/toast system. */
.nav-badge-dot {
  /* Explicit inline-block, not left to the parent's own display — this span's width/
     height were silently ignored (and the dot invisible despite hidden={false}) inside
     .custom-select-option, whose display:block does NOT blockify an inline child the
     way a flex/grid parent (e.g. the sidebar nav item, .custom-select-trigger) does.
     Real bug this session: the "Meldingen" option's own dot never showed, even though
     the exact same JS toggle logic and the sidebar's own dot worked fine — root cause
     was CSS, not the badge-refresh logic. inline-block renders identically in every
     parent context, flex or not. */
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--attention);
  flex: 0 0 auto;
  margin-left: auto;
  /* A visible ring at all times, not just when active — .custom-select-option.active's
     own background (--accent-bg) is a light orange tint close enough to --attention
     that the dot otherwise disappears into it on exactly the option a superadmin is
     most likely to have selected (an orange-on-orange bug caught via live browser
     verification, not a screenshot guess). */
  box-shadow: 0 0 0 1.5px var(--card-bg);
}
.custom-select-option .nav-badge-dot { margin-left: 8px; }
/* Inside the trigger button itself (admin section switcher's collapsed state, e.g.
   showing "Meldingen" once selected) — sits right after the label, not pushed to the
   far edge past the chevron like the default margin-left:auto would do; the flex gap
   on .custom-select-trigger already provides spacing on both sides. */
.custom-select-trigger .nav-badge-dot { margin-left: 0; }
.sidebar-nav-secondary a.active { color: var(--tm-text-primary); }

.sidebar-account {
  margin-top: 14px;
  padding: 12px 10px 4px;
  border-top: 1px solid var(--tm-border);
}
.sidebar-account-name { font-size: 13px; font-weight: 600; color: var(--tm-text-primary); }
.sidebar-account-plan { font-size: 11.5px; color: var(--sidebar-text-dim); margin-top: 2px; }
.sidebar-api-docs-link {
  display: block;
  font-size: 11.5px;
  color: var(--sidebar-text-dim);
  margin-bottom: 10px;
  text-decoration: none;
}
.sidebar-api-docs-link:hover { color: var(--tm-text-primary); text-decoration: underline; }
button.sidebar-api-docs-link { background: none; border: none; padding: 0; font: inherit; text-align: left; cursor: pointer; width: 100%; }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  height: 56px;
  flex: 0 0 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  border-bottom: 1px solid var(--border);
  background: var(--main-bg);
}
.topbar-title { font-size: 14px; font-weight: 600; color: var(--text-secondary); }
.topbar-actions { display: flex; align-items: center; gap: 14px; font-size: 13px; color: var(--text-secondary); }

/* ---------- Switch (Apple-style compact toggle) — reused for the topbar's
   dark-mode control and any boolean setting (auto-refill, ...). ---------- */
.switch { display: inline-flex; align-items: center; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.switch-track {
  display: inline-block;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--tm-border-strong);
  position: relative;
  flex: 0 0 auto;
  transition: background var(--dur) var(--ease);
}
.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform var(--dur) var(--ease);
}
.switch input:checked + .switch-track { background: var(--accent); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(14px); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-label { font-size: 13px; color: var(--text-primary); }

.content {
  flex: 1;
  padding: 28px 32px 60px;
  max-width: 1320px;
  width: 100%;
  margin: 0 auto;
  opacity: 0;
  transition: opacity 0.28s ease;
}
.content.visible { opacity: 1; }

.page { display: none; }
.page.active { display: block; }

/* ---------- Typography / structure ---------- */
h1, h2, h3 { margin: 0; font-weight: 600; }
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.page-header h1 { font-size: 32px; line-height: 40px; letter-spacing: -0.01em; }
.page-subtitle { color: var(--text-secondary); font-size: 13px; margin-top: 4px; }

.btn-lg { padding: 12px 22px; font-size: 14px; border-radius: var(--radius); }
.section-label {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 28px 0 12px;
}
.section-label:first-child { margin-top: 0; }

.protocol-subsection-heading {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-secondary);
  margin: 20px 0 6px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.protocol-subsection-heading:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.protocol-item-row.excluded-from-presentation { opacity: 0.55; }

/* ---------- Buttons (one consistent family) ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--text-primary);
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.btn:hover:not(:disabled) { border-color: var(--tm-border-strong); background: var(--tm-surface-hover); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: var(--shadow-sm); }
.btn-primary:hover:not(:disabled) { background: var(--tm-accent-hover); border-color: var(--tm-accent-hover); box-shadow: var(--shadow-md); }
.btn-quiet { background: transparent; border-color: transparent; color: var(--text-secondary); padding: 6px 8px; }
.btn-quiet:hover:not(:disabled) { background: var(--tm-surface-hover); color: var(--text-primary); }
.btn-danger { color: var(--tm-error); }
.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn-icon-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--tm-error);
  cursor: pointer;
  flex: 0 0 auto;
}
.btn-icon-danger:hover:not(:disabled) { background: var(--tm-error-bg); border-color: var(--tm-error); }
.btn-icon-danger:disabled { opacity: 0.35; cursor: not-allowed; }
/* Always rendered (never hidden) so selecting/deselecting a vehicle never
   shifts the grid below it — only the button/count inside it change. */
.vehicle-bulk-bar { margin-top: -6px; }

/* ---------- Cards / panels ---------- */
.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow-sm);
}
.card + .card { margin-top: 14px; }

/* ---------- Result rating ---------- */
.rating-dots { display: flex; gap: 8px; }
.rating-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: transparent;
  cursor: pointer;
  padding: 0;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.rating-dot:hover { border-color: var(--accent); }
.rating-dot.selected { background: var(--accent); border-color: var(--accent); }
.rating-dot.selected.low { background: var(--attention); border-color: var(--attention); }

/* ---------- Status badges ---------- */
.status-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; }
.status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.status-ready .status-dot { background: var(--success); }
.status-ready { color: var(--success); }
.status-processing .status-dot { background: var(--processing); }
.status-processing { color: var(--processing); }
.status-attention .status-dot { background: var(--attention); }
.status-attention { color: var(--attention); }

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.status-pill.status-ready { background: var(--success-bg); }
.status-pill.status-processing { background: var(--processing-bg); }
.status-pill.status-attention { background: var(--attention-bg); }

.package-tier-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-bg);
}
.package-tier-badge:empty { display: none; }

/* ---------- Toasts (transient, self-dismissing, e.g. the package-tier-upgrade
   celebration) ---------- */
#toastStack {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md, var(--shadow-sm));
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.toast.toast-visible { opacity: 1; transform: translateY(0); }

/* ---------- Filter tabs ---------- */
.filter-tabs { display: flex; gap: 4px; }
.filter-tab {
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  border: 1px solid transparent;
}
.filter-tab:hover { background: var(--tm-surface-hover); }
.filter-tab.active { background: var(--tm-ink); color: var(--tm-ink-contrast); }
.filter-tab .count { opacity: 0.65; margin-left: 4px; }

/* ---------- Search / toolbar ---------- */
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 18px; flex-wrap: wrap; }
.search-input {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  min-width: 240px;
}
.search-input input {
  border: none;
  outline: none;
  background: transparent;
  font-size: 13px;
  width: 100%;
  color: var(--text-primary);
}
.search-input svg { flex: 0 0 auto; color: var(--text-secondary); }

/* ---------- Vehicle grid / cards ---------- */
.vehicle-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
.vehicle-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.15s ease;
  position: relative;
}
.vehicle-card-select {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  width: 22px;
  height: 22px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.vehicle-card-select input { width: 16px; height: 16px; cursor: pointer; margin: 0; }
.vehicle-card:hover { border-color: var(--tm-border-strong); transform: translateY(-1px); }
.vehicle-card-image {
  aspect-ratio: 4 / 3;
  background: var(--tm-surface-hover) repeating-linear-gradient(135deg, var(--tm-surface-hover), var(--tm-surface-hover) 10px, var(--tm-border) 10px, var(--tm-border) 20px);
  overflow: hidden;
  position: relative;
}
.vehicle-card-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
a.vehicle-card-image { display: block; }
.vehicle-card-photocount {
  position: absolute;
  right: 8px;
  bottom: 8px;
  background: rgba(17, 17, 17, 0.72);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
}
.vehicle-card-body { padding: 12px 14px 14px; }
.vehicle-card-status { margin-bottom: 6px; }
.vehicle-card-title { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vehicle-card-meta { font-size: 12px; color: var(--text-secondary); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-secondary);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: var(--card-bg);
}
.empty-state h3 { font-size: 14px; color: var(--text-primary); margin-bottom: 6px; }
.empty-state p { font-size: 13px; margin: 0 0 14px; }

/* ---------- Vehicle detail ---------- */
.detail-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.detail-back { font-size: 12.5px; color: var(--text-secondary); margin-bottom: 8px; display: inline-block; }
.detail-back:hover { color: var(--text-primary); }
.detail-title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.detail-title-row h1 { font-size: 19px; }
.detail-meta-row { font-size: 12.5px; color: var(--text-secondary); margin-top: 4px; }
.detail-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.detail-layout { display: grid; grid-template-columns: 1fr 320px; gap: 20px; align-items: start; }
@media (max-width: 980px) { .detail-layout { grid-template-columns: 1fr; } }
/* Grid items default to min-width:auto, so a wide zoomed image inside would
   otherwise blow out this 1fr track instead of scrolling within it. */
.viewer-column { min-width: 0; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.tab-btn {
  padding: 9px 4px;
  margin-right: 18px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  border-bottom: 2px solid transparent;
}
.tab-btn.active { color: var(--text-primary); border-bottom-color: var(--tm-ink); font-weight: 600; }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* Live preview of the embeddable spin-viewer widget on the Publishing tab (see
   app.js's renderSpinEmbedCard) — a border/radius so it reads as a distinct preview
   frame, not part of the page background; the widget itself (spin-viewer.js) supplies
   its own background color/sizing inline once it initializes. */
.spin-embed-preview { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }

.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 18px; font-size: 13px; }
.info-grid dt { color: var(--text-secondary); margin: 0; }
.info-grid dd { margin: 2px 0 0; font-weight: 500; }

.processing-step { display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; font-size: 13px; }
.processing-step .step-icon { flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; margin-top: 1px; }
.processing-step.done .step-icon { background: var(--success-bg); color: var(--success); }
.processing-step.pending .step-icon { background: var(--processing-bg); color: var(--processing); }
.processing-step.error .step-icon { background: var(--attention-bg); color: var(--attention); }
.processing-step .step-title { font-weight: 500; }
.processing-step .step-desc { color: var(--text-secondary); font-size: 12px; margin-top: 1px; }

.progress-bar { height: 6px; border-radius: 999px; background: var(--tm-surface-hover); overflow: hidden; margin-top: 10px; }
.progress-bar-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.3s ease; }

/* ---------- Image viewer (reuses the original slider/zoom mechanics) ---------- */
.viewer-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.viewControls { display: flex; align-items: center; gap: 14px; font-size: 12.5px; flex-wrap: wrap; }
.viewControls label { display: inline-flex; align-items: center; gap: 4px; color: var(--text-secondary); cursor: pointer; }
.zoomGroup { display: flex; align-items: center; gap: 4px; }
.zoomBtn {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px 9px;
  font-size: 12px;
  cursor: pointer;
  color: var(--text-secondary);
}
.zoomBtn.active { background: var(--tm-ink); border-color: var(--tm-ink); color: var(--tm-ink-contrast); }

.compareView { width: 100%; }
.slider-container {
  position: relative;
  width: 100%;
  height: 62vh;
  min-height: 360px;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  user-select: none;
  background: #000;
  /* Centres the photo in the box. At "fit" the whole image is visible at once — it
     used to be scaled to 100% WIDTH, so anything taller than the box ran off the
     bottom and had to be scrolled to. */
  display: flex;
  align-items: center;
  justify-content: center;
}
.slider-stage { position: relative; flex: 0 0 auto; line-height: 0; }
.slider-container.zoomed { cursor: grab; }
.slider-container.zoomed.panning { cursor: grabbing; }
.slider-img { display: block; max-width: none; height: auto; }
.slider-after { position: absolute; top: 0; left: 0; clip-path: inset(0 50% 0 0); }
.slider-line { position: absolute; top: 0; left: 50%; width: 2px; height: 100%; background: #fff; opacity: 0.9; pointer-events: none; }
.slider-handle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 30px;
  height: 30px;
  margin-left: -15px;
  margin-top: -15px;
  border-radius: 50%;
  background: #fff;
  cursor: ew-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #111;
  font-size: 0.85rem;
  z-index: 2;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}
.slider-container.no-result .slider-after,
.slider-container.no-result .slider-line,
.slider-container.no-result .slider-handle { display: none; }
.slider-processing-note {
  position: absolute;
  left: 12px;
  bottom: 12px;
  background: rgba(17, 17, 17, 0.72);
  color: #fff;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 999px;
}

.sbsPane { margin-bottom: 12px; }
.sbsLabel { color: var(--text-secondary); font-size: 12px; margin-bottom: 6px; }
.sbsScroll { height: 50vh; min-height: 300px; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: #000; }
.sbsScroll img { display: block; max-width: none; height: auto; }
.sbsScroll.zoomed { cursor: grab; }
.sbsScroll.zoomed.panning { cursor: grabbing; }

.thumbnail-strip { display: flex; gap: 8px; margin-top: 12px; overflow-x: auto; padding-bottom: 4px; }
.thumbnail-item {
  flex: 0 0 auto;
  width: 76px;
  height: 58px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 2px solid transparent;
  cursor: pointer;
  background: var(--tm-surface-hover);
}
.thumbnail-item.active { border-color: var(--tm-ink); }
.thumbnail-item img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- Forms ---------- */
.form-row { margin-bottom: 14px; }
.form-row label.field-label { display: block; font-size: 12.5px; font-weight: 500; color: var(--text-secondary); margin-bottom: 5px; }
.form-row input[type="text"],
.form-row input[type="email"],
.form-row input[type="password"],
.form-row input[type="number"],
.form-row input[type="search"],
.form-row input[type="tel"],
.form-row input[type="url"],
.form-row input[type="date"],
.form-row select,
.form-row textarea {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 9px 10px;
  font-size: 13px;
  font-family: inherit;
  background: var(--card-bg);
  color: var(--text-primary);
  transition: border-color var(--dur) var(--ease);
}
.form-row input:focus-visible,
.form-row select:focus-visible,
.form-row textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}
.form-row input[type="color"] {
  width: 48px;
  height: 38px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card-bg);
  cursor: pointer;
}
.form-hint { font-size: 12px; color: var(--text-secondary); margin-top: 5px; }
.radio-row { display: flex; gap: 16px; margin-bottom: 6px; }
.radio-row label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }

/* Custom file dropzone — replaces the raw "choose file" browser control. */
.dropzone {
  border: 1.5px dashed var(--border);
  border-radius: var(--radius);
  padding: 22px;
  text-align: center;
  cursor: pointer;
  background: var(--card-bg);
  transition: border-color 0.15s ease, background 0.15s ease;
  position: relative;
}
.dropzone:hover, .dropzone.dragover { border-color: var(--tm-ink); background: var(--tm-surface-hover); }
.dropzone-lg { padding: 48px 22px; }
.dropzone-lg .dropzone-title { font-size: 15px; }

/* Premium 360 spin (Capture page) — one small dropzone per required compass angle,
   since each photo must be individually tagged to its own photo-protocol angle_key
   (see app.js's createVehicleSession premium-spin branch) rather than uploaded as an
   untagged batch like the normal AI/Natural flow. */
.spin-angle-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.spin-angle-slot { padding: 14px 10px; }
.spin-angle-slot .dropzone-title { font-size: 12px; }
.spin-angle-slot.filled { border-color: var(--success); background: var(--accent-bg); }
.spin-angle-slot.filled .dropzone-sub::before { content: "✓ "; color: var(--success); }

/* ---------- Operator panel (Capture) — a bit more breathing room than the
   standard .card, since this is meant to be worked quickly, often at arm's
   length from a vehicle rather than a desk. ---------- */
.operator-panel { padding: 28px; max-width: 640px; }
.operator-panel .field-label { font-size: 13px; }
.dropzone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.dropzone-title { font-size: 13px; font-weight: 600; }
.dropzone-sub { font-size: 12px; color: var(--text-secondary); margin-top: 3px; }
.dropzone-filename { font-size: 12.5px; color: var(--text-primary); margin-top: 8px; font-weight: 500; }

table { width: 100%; border-collapse: collapse; font-size: 13px; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: 13px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
th { color: var(--text-secondary); font-weight: 500; font-size: 12px; }
tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--dur) var(--ease); }
tbody tr:hover { background: var(--tm-surface-hover); }

.thumb-sm { width: 44px; height: 44px; object-fit: cover; border-radius: var(--radius-sm); background: var(--tm-surface-hover); border: 1px solid var(--border); }

.hint { color: var(--text-secondary); font-size: 12.5px; }
code { background: var(--tm-surface-hover); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; font-size: 0.9em; }

/* Collapsible help block (native <details>/<summary> — no JS needed, keyboard-
   accessible by default). The <summary> is styled to look like an ordinary .btn;
   only its own default marker triangle is swapped for a chevron that flips on
   [open], matching the custom-select-chevron pattern used elsewhere on this page. */
details > summary.btn { list-style: none; user-select: none; }
details > summary.btn::-webkit-details-marker { display: none; }
details > summary.btn::after {
  content: "";
  width: 8px; height: 8px;
  margin-left: 2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.15s ease;
}
details[open] > summary.btn::after { transform: rotate(-135deg); }
.flash-help-body { padding: 16px 4px 4px; max-width: 68ch; }
.flash-help-body h4 { font-size: 14px; font-weight: 600; margin: 20px 0 6px; }
.flash-help-body h4:first-child { margin-top: 8px; }
.flash-help-body ol, .flash-help-body ul { margin: 0 0 10px; padding-left: 20px; font-size: 13.5px; line-height: 1.6; }
.flash-help-body li { margin-bottom: 4px; }
.flash-help-body p { font-size: 13.5px; line-height: 1.6; margin: 0 0 10px; }
.flash-help-body p.hint { margin-bottom: 8px; }

/* ---------- Studio picker ---------- */
.studio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.studio-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.studio-card.is-default { border-color: var(--accent); }
.studio-card-image { aspect-ratio: 4/3; background: var(--tm-surface-hover); }
.studio-card-image img { width: 100%; height: 100%; object-fit: cover; display: block; cursor: zoom-in; }
.studio-card-body { padding: 10px 12px; }
.studio-card-name { font-size: 13px; font-weight: 600; }
.studio-card-actions { display: flex; gap: 6px; margin-top: 8px; }

.protocol-item-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.protocol-item-row:last-child { border-bottom: none; }
.badge-required {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-bg);
  cursor: help;
}
.protocol-item-actions { display: flex; gap: 6px; flex: 0 0 auto; align-items: center; }
.protocol-item-main { display: flex; align-items: center; gap: 10px; min-width: 0; }
.protocol-item-thumb { width: 32px; height: 32px; border-radius: 6px; object-fit: cover; flex: 0 0 auto; border: 1px solid var(--border); }

.badge-subaccount {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--tm-surface-hover);
  white-space: nowrap;
}

/* ---------- Auth (login/signup) ----------
   A restrained "studio spotlight" treatment — a soft radial glow in the brand
   accent plus a faint precision grid — rather than a flat single-color screen.
   Kept subtle deliberately: this is the one screen where a plain wash reads as
   unfinished rather than minimal, but it still must not look decorated. */
/* Always dark, independent of the site's own light/dark theme toggle — a fixed brand
   moment (same treatment a lot of products use for a login hero), not a themed working
   surface. Values below are literal, not --tm-* tokens, on purpose. Full-bleed studio
   photo (login-background.png — a real car headlight/silhouette on the right, matching
   the reference design) instead of the earlier CSS-drawn placeholder. */
.auth-screen {
  position: relative;
  min-height: 100vh;
  display: flex;
  padding: 0;
  background-color: #0b0d0e;
  background-image: url('assets/login-background.png');
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
  overflow: hidden;
}
.auth-topbar {
  position: absolute;
  top: 24px;
  right: 28px;
  display: flex;
  align-items: center;
  gap: 14px;
  z-index: 2;
}

.auth-split {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 100vh;
  padding: 40px 64px;
}

.auth-hero {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 28px;
  color: #f5f6f6;
  padding-right: 40px;
}

.auth-hero-brand { display: flex; align-items: center; gap: 18px; }
.auth-hero-logo { height: 52px; width: auto; }
.auth-hero-brand-divider { width: 1px; height: 44px; background: #343a3e; flex: 0 0 auto; }
/* Bumped from 30px — the lockup's own baked-in tagline text was illegible at that size
   (it's part of the source SVG's artwork, not separately styleable). */
.auth-hero-logo-secondary { height: 56px; width: auto; }

.auth-hero-headline { font-size: 44px; line-height: 1.15; font-weight: 700; margin: 0; letter-spacing: -0.01em; text-shadow: 0 2px 24px rgba(0, 0, 0, 0.5); }
.auth-hero-headline-accent { display: block; color: #ff7624; }
.auth-hero-subtext { font-size: 15px; line-height: 1.5; color: #c7cbce; margin: 0; max-width: 440px; }

/* Three equal-size containers (image band + text), not two big ones and a small one —
   the arrows below are positioned against this shared band, so every dimension here is
   deliberate: change AUTH_HERO_STEP_VISUAL_HEIGHT and re-derive the arrow's margin-top
   (see .auth-hero-step-arrow) if this ever changes. align-items: flex-start (not
   flex-end, the old setting) so every step's image band starts at the same Y regardless
   of how many lines its caption wraps to below it — that's what makes the text block
   line up "op gelijke hoogte" across all three. */
.auth-hero-steps { display: flex; align-items: flex-start; gap: 18px; }
.auth-hero-step { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; width: 220px; min-width: 0; }
/* Fixed, shared height for every step's image — the actual "container" Rob asked for.
   Center/center on purpose: the AI badge (step 2) is intentionally much smaller than
   the two real photos (steps 1/3) and just floats in the middle of this same-size box
   rather than being enlarged to match, or stuck to the bottom. overflow: hidden is a
   backstop, not the actual fix — the real fix is the img's own max-width: 100% below
   (was a stale fixed 420px, wider than this 220px column itself: a landscape image,
   e.g. the laptop mockup, rendered past its own container's edges since nothing but
   its height was actually bounded, breaking the "equal space on both sides of the
   arrow" arrows depend on). */
.auth-hero-step-visual { height: 240px; width: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.auth-hero-step-visual img { max-height: 100%; max-width: 100%; width: auto; object-fit: contain; display: block; }
/* Step 2's AI badge is a small mark, not a photo — without its own cap it scales up to
   fill the full 240px band like the two real photos either side of it, reading as
   oversized. Height band stays the shared 240px (so the arrows' centering math and the
   text row's alignment are untouched) — only the image inside is kept small and
   floats centered within that taller box. */
.auth-hero-step-visual-icon img { max-height: 110px; max-width: 130px; }
/* Step 3 ("studio resultaat") is a landscape laptop mockup — at the shared 220px column
   width its rendered size is width-bound (not height-bound), so it can't grow past
   ~220px regardless of the band's height. Widening just this one column lets it render
   meaningfully bigger without touching the shared 240px height (so text/arrow
   alignment against steps 1/2 is unaffected) — the "iets grotere container" Rob okayed. */
.auth-hero-step-wide { width: 300px; }
.auth-hero-step-text { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.auth-hero-step-label { font-size: 12.5px; font-weight: 600; }
.auth-hero-step-num { color: #ff7624; }
.auth-hero-step-caption { font-size: 11px; color: #9aa0a6; line-height: 1.3; }
/* Vertically centered on the image band's own midpoint (240px / 2), not the whole
   step (image + text) — margin-top = half the image band minus half the arrow's own
   size, so its center lands exactly on the band's center regardless of caption length
   below it. Flex's own `gap` on .auth-hero-steps already gives it identical left/right
   spacing to the images on both sides, so no horizontal margin is needed here. */
.auth-hero-step-arrow { width: 20px; height: 20px; flex: 0 0 auto; color: #4a5157; margin-top: 110px; }

.auth-hero-features { display: flex; flex-wrap: wrap; gap: 20px 28px; }
.auth-hero-feature { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: #c7cbce; }
.auth-hero-feature svg { width: 16px; height: 16px; flex: 0 0 auto; color: #ff7624; }

.auth-hero-quote {
  margin: 0;
  max-width: 460px;
  padding-left: 16px;
  border-left: 2px solid #ff7624;
}
.auth-hero-quote p { margin: 0 0 8px; font-size: 14.5px; line-height: 1.5; font-style: italic; color: #e4e6e7; }
.auth-hero-quote cite { font-size: 12px; font-style: normal; color: #9aa0a6; }

.auth-hero-footer { display: flex; align-items: center; gap: 10px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #9aa0a6; }
.auth-hero-footer-brand { font-weight: 700; color: #c7cbce; }
.auth-hero-footer-sep { color: #4a5157; }

/* A genuinely floating card — rounded on every side, drop shadow, clear margin from the
   viewport edge (not a flush sidebar panel) — sitting on top of the background photo.
   margin-right nudges it left of where the flex layout would otherwise put it (flush
   against the padding edge), so it clears the headlight in the background photo and
   sits closer to the car's side mirror instead. */
.auth-card {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 100%;
  max-width: 400px;
  margin-right: 9vw;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45), 0 4px 18px rgba(0, 0, 0, 0.3);
  padding: 40px 36px;
}
.auth-logo-img { display: block; height: 34px; width: auto; margin-bottom: 26px; }
.auth-title { font-size: 22px; margin: 0 0 18px; }

/* Below this, the hero panel is more clutter than value — collapse back to just the
   floating card, centered, so small/narrow windows (and the desktop app's own webview,
   if it's ever reused there) stay usable. */
@media (max-width: 860px) {
  .auth-hero { display: none; }
  .auth-split { justify-content: center; padding: 20px; }
  .auth-card { margin-right: 0; }
}
.auth-form .form-row:last-of-type { margin-bottom: 10px; }
.auth-error { color: var(--tm-error); font-size: 12.5px; min-height: 16px; margin-bottom: 8px; }
.auth-notice { color: var(--tm-success); font-size: 12.5px; min-height: 16px; margin-bottom: 8px; }
.auth-submit { width: 100%; justify-content: center; margin-top: 4px; }
.auth-switch { text-align: center; font-size: 12.5px; color: var(--text-secondary); margin-top: 16px; }
.auth-switch a { color: var(--text-primary); font-weight: 600; }
.auth-switch a:hover { text-decoration: underline; }
.auth-field-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.auth-forgot-link { font-size: 12px; color: var(--text-secondary); }
.auth-forgot-link:hover { color: var(--accent); }

/* ---------- Overview page ---------- */
.low-balance-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--attention-bg);
  border: 1px solid var(--attention);
  color: var(--attention);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 18px;
  font-size: 13px;
}
.low-balance-banner a { color: inherit; font-weight: 600; text-decoration: underline; white-space: nowrap; }
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 22px; }
.stat-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.stat-card-clickable { cursor: pointer; }
.stat-value { font-size: 22px; font-weight: 700; }
.stat-label { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.stat-card-note { font-size: 11.5px; color: var(--warning, #b45309); margin-top: 6px; }

/* ---------- Checklist (evaluation) ---------- */
.verdict-group label { margin-right: 14px; cursor: pointer; font-size: 12.5px; }
.verdict-group input[value="PASS"] + span { color: var(--success); }
.verdict-group input[value="FAIL"] + span { color: var(--tm-error); }
td input[type="text"] {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  font-size: 12.5px;
  background: var(--card-bg);
}

.badge-chip { font-size: 11px; color: var(--text-secondary); }

/* ---------- Integrations page: desktop-app download rows ---------- */
.download-row { display: flex; align-items: center; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--border); }
.download-row:last-child { border-bottom: none; }
.download-row-icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--tm-surface-hover);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
}
.download-row-icon svg { width: 20px; height: 20px; }
.download-row-body { flex: 1 1 auto; min-width: 0; }
.download-row-title { font-weight: 600; font-size: 13.5px; }

/* ---------- Admin page: section switcher ---------- */
.admin-section-switcher {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 22px;
}
.admin-section-crumb { font-size: 13px; font-weight: 600; color: var(--text-secondary); }
.admin-section-crumb-sep { font-size: 13px; color: var(--text-secondary); opacity: 0.5; }

/* A plain <select>'s open dropdown is rendered by the OS/browser chrome, not by our
   CSS — no amount of styling the closed control makes the popup match the rest of the
   dashboard. This is a fully custom-built dropdown instead, styled end to end. */
.custom-select { position: relative; display: inline-block; }
.custom-select-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card-bg);
  color: var(--text-primary);
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  padding: 7px 10px 7px 12px;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease);
}
.custom-select-trigger:hover { border-color: var(--tm-ink); }
.custom-select-trigger:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}
.custom-select-chevron { width: 16px; height: 16px; color: var(--text-secondary); transition: transform var(--dur) var(--ease); flex: 0 0 auto; }
.custom-select.open .custom-select-chevron { transform: rotate(180deg); }
.custom-select-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 200px;
  max-height: min(560px, 80vh);
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 6px;
  z-index: 50;
}
.custom-select-option {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 13.5px;
  font-family: inherit;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.custom-select-option:hover { background: var(--tm-surface-hover); }
.custom-select-option.active { background: var(--accent-bg); color: var(--accent); font-weight: 600; }

/* Compact variant used for the topbar/auth-screen language switcher — smaller footprint
   than the admin section switcher, and opens right-aligned so its menu never overflows
   past the right edge of the viewport near the topbar's own right-hand edge. */
.locale-custom-select .custom-select-trigger { font-size: 12.5px; font-weight: 400; padding: 5px 8px; }
.locale-custom-select .custom-select-menu { left: auto; right: 0; min-width: 160px; }

/* Custom month-grid date picker — see initDatePicker in app.js for why this exists
   instead of a plain <input type="date">'s own (unstyleable) popup calendar. */
.custom-datepicker .custom-select-menu { min-width: 250px; padding: 10px; }
.datepicker-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.datepicker-month-label { font-size: 13px; font-weight: 600; color: var(--text-primary); text-transform: capitalize; }
.datepicker-nav {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: 16px;
  line-height: 1;
  padding: 4px 9px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.datepicker-nav:hover { background: var(--tm-surface-hover); color: var(--text-primary); }
.datepicker-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 11px; color: var(--text-secondary); margin-bottom: 4px; }
.datepicker-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.datepicker-day {
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 13px;
  font-family: inherit;
  padding: 7px 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.datepicker-day:hover { background: var(--tm-surface-hover); }
.datepicker-day.today { font-weight: 700; color: var(--accent); }
.datepicker-day.active { background: var(--accent); color: #fff; font-weight: 600; }
.datepicker-day-empty { cursor: default; }

/* ---------- Admin page: grouped panels ---------- */
.admin-panel {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px 24px 26px;
  margin-bottom: 22px;
  box-shadow: var(--shadow-sm);
}
.admin-panel-title { font-size: 15px; font-weight: 700; margin: 0; }
.admin-panel-title::before { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); margin-right: 8px; }
.admin-panel-subtitle { color: var(--text-secondary); font-size: 12.5px; margin: 4px 0 0; }
.admin-panel .section-label:first-of-type { margin-top: 24px; }
.admin-panel .card { background: var(--main-bg); }
.two-col { display: grid; grid-template-columns: 1fr; gap: 24px; }
@media (min-width: 900px) {
  .two-col { grid-template-columns: 1fr 1fr; }
  .two-col > .section-label:first-of-type,
  .two-col > .section-label:nth-of-type(2) { margin-top: 24px; }
}

.period-filter { display: inline-flex; gap: 4px; margin-bottom: 16px; }
.period-filter button.active { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ---------- Account page: balance hero ---------- */
.balance-hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding: 24px 0 28px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 24px;
}
.balance-hero-label { font-size: 13px; color: var(--text-secondary); margin-bottom: 4px; }
.balance-hero-value { font-size: 40px; font-weight: 600; letter-spacing: -0.02em; line-height: 1; }
.balance-hero-estimate { font-size: 13px; color: var(--text-secondary); margin-top: 8px; }
.balance-hero-estimate span { display: block; }

/* ---------- Account page: two-column layout (main + settings sidebar) ---------- */
.account-layout { display: grid; grid-template-columns: 1fr; gap: 32px; align-items: start; }
@media (min-width: 1100px) {
  .account-layout { grid-template-columns: minmax(0, 1fr) 320px; }
}
.account-main .section-label:first-child { margin-top: 0; }
.account-side .section-label:first-child { margin-top: 0; }

/* ---------- Account page: selectable credit-package options ---------- */
.package-select-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.package-option {
  display: block;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  text-align: center;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.package-option input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.package-option:hover { border-color: var(--tm-border-strong); }
.package-option.selected { border-color: var(--accent); background: var(--accent-bg); }
.package-option-name { font-size: 12.5px; color: var(--text-secondary); }
.package-option-price { font-size: 19px; font-weight: 600; margin-top: 2px; }
.package-option-bonus { color: var(--success); font-size: 11.5px; margin-top: 3px; min-height: 14px; }
.package-option-hint { color: var(--text-secondary); font-size: 11px; margin-top: 4px; line-height: 1.35; }

/* Read-only variant used for the Account page's "what does a vehicle cost" tiles and
   the Capture page's current-package badge — same look, no selection state/cursor. */
.package-option-static { cursor: default; }
.package-option-static:hover { border-color: var(--border); }
.package-tier-spin-badge {
  display: inline-block;
  margin-top: 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-bg);
  border-radius: 999px;
  padding: 2px 8px;
}

/* ---------- Switch row (label + Apple-style toggle, e.g. auto-refill) ---------- */
.switch-row { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }

/* Email settings connection check (see admin.py's /settings/email/diagnose) — a
   per-layer pass/fail list, so a broken mail config names its own cause instead of
   surfacing as one opaque timeout. */
.email-diagnostics {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  font-size: 13px;
  line-height: 1.5;
}
.email-diagnostics-step { display: flex; gap: 8px; align-items: flex-start; }
.email-diagnostics-step + .email-diagnostics-step { margin-top: 4px; }
.email-diagnostics-mark { flex: 0 0 auto; font-weight: 700; }
.email-diagnostics-step.ok .email-diagnostics-mark { color: var(--success, #16a34a); }
.email-diagnostics-step.fail .email-diagnostics-mark { color: var(--danger, #dc2626); }
.email-diagnostics-suggestion {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
}

/* Campaign mail editor (frontend/mail-editor.js) */
.mail-editor { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.mail-editor-toolbar {
  display: flex; flex-wrap: wrap; gap: 4px;
  padding: 6px; background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.mail-editor-btn {
  min-width: 30px; padding: 4px 8px; font-size: 12px; cursor: pointer;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 5px;
}
.mail-editor-btn:hover { background: var(--surface-3, var(--surface-2)); }
.mail-editor-btn.active { background: var(--accent); color: #fff; }
.mail-editor-token { font-family: ui-monospace, monospace; font-size: 11px; opacity: .85; }
.mail-editor-surface {
  min-height: 240px; max-height: 480px; overflow-y: auto;
  padding: 12px; background: #fff; color: #111;
  font-family: Arial, Helvetica, sans-serif; font-size: 14px; line-height: 1.5;
}
/* The surface previews an email, which renders on a white background in every mail
   client — so it stays light even in dark mode rather than lying about the result. */
.mail-editor-surface:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.mail-editor-surface img { max-width: 100%; height: auto; }
.mail-editor-surface table { border-collapse: collapse; }
.mail-editor-source {
  width: 100%; min-height: 240px; padding: 12px; border: 0;
  font-family: ui-monospace, monospace; font-size: 12px; resize: vertical;
}
.modal-panel-wide { max-width: 860px; width: 92vw; }

/* Grouped options in the admin section dropdown (Marketing, Financieel). The group
   label is a div, not a button, so initAdminSectionSwitcher's .custom-select-option
   query skips it and it can never be selected. */
.custom-select-group {
  padding: 8px 12px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
  pointer-events: none;
}
.custom-select-option-sub { padding-left: 24px; }

/* Anti-spam notice on the two invite tabs (see app/services/invite_gate.py) — shown
   instead of silently disabling the buttons, so the restriction is explained rather
   than just encountered. */
.invite-locked-note {
  margin-bottom: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--tm-ink);
  border-radius: 6px;
  background: var(--surface-2);
}

/* Pipeline development bench (superadmin) — see renderPipelineDevPage in app.js. */
.pipeline-dev-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.pipeline-dev-strip img {
  display: block;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
}
/* The generated sheet is the thing you actually study when a run disappoints, so it gets
   real size rather than sitting in the strip at thumbnail scale. */
.pipeline-dev-sheet { width: 100%; max-width: 720px; height: auto; }
.pipeline-dev-frame { width: 96px; height: 96px; object-fit: cover; }
.prompt-dump {
  max-height: 420px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 12px;
  line-height: 1.5;
  padding: 12px;
  margin-top: 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
}

.pipeline-dev-files { list-style: none; margin: 8px 0 0; padding: 0; }
.pipeline-dev-files li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 10px;
  margin-bottom: 4px;
  border-radius: 6px;
  font-size: 12.5px;
  background: var(--surface-2);
}
/* Anything past the limit stays visible and flagged rather than silently dropped, so it
   is obvious which ones to remove. */
.pipeline-dev-file-over { color: var(--danger, #d9534f); text-decoration: line-through; }

/* The rotation verdict on a bench run (see spin_coverage.py). Loud on purpose: it is the
   one question a spin has to answer, and it should not read as another statistic. */
.pipeline-dev-verdict-ok,
.pipeline-dev-verdict-bad {
  margin: 10px 0;
  padding: 10px 12px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  border-left: 3px solid;
}
.pipeline-dev-verdict-ok { background: var(--surface-2); border-color: #3c9a5f; }
.pipeline-dev-verdict-bad { background: var(--surface-2); border-color: #d9534f; }

/* The bench's prompt field. Monospace and full width because what goes in here is a
   multi-thousand-word instruction, not a caption. */
.prompt-field {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  padding: 10px;
  margin-top: 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: inherit;
  resize: vertical;
}
