/* ═══════════════════════════════════════════════════════════
   App Components — Component Library
   Light admin theme shared across all ops pages.
   New pages: <link rel="stylesheet" href="app-components.css"> before <style>
   ═══════════════════════════════════════════════════════════ */

/* ── 1. DESIGN TOKENS ── */
:root {
  --brand-primary:      #1a2744;
  --brand-accent:      #c8a951;
  --brand-white:     #ffffff;
  --brand-light:     #f4f5f7;
  --brand-border:    #dde1e6;
  --brand-text:      #1a2744;
  --brand-muted:     #6b7280;
  --brand-hover:     #f0f2f5;
  --brand-green:     #22c55e;
  --brand-red:       #ef4444;
  --brand-blue:      #3b82f6;
  --brand-yellow:    #eab308;
  --brand-orange:    #f97316;
  --brand-red-bg:    #fef2f2;
  --brand-green-bg:  #f0fdf4;
  --brand-blue-bg:   #eff6ff;
  --brand-yellow-bg: #fefce8;
  --topbar-h:     52px;

  /* Stacking ladder — use these tokens everywhere z-index is needed.
     Order (bottom → top): page content → sticky header → page banners
     → slideouts → modals → toasts. See CANON.md "Z-Index" for the rule. */
  --brand-z-sticky-header:    50;    /* topbar, sticky table thead */
  --brand-z-page-overlay:     100;   /* claim banners, test-mode banner */
  --brand-z-slideout-overlay: 500;   /* slideout / drawer backdrops */
  --brand-z-slideout:         501;   /* slideout / drawer panel */
  --brand-z-modal-overlay:    1000;  /* modal dialogs — always above slideouts */
  --brand-z-modal:            1001;  /* modal inner box */
  --brand-z-toast:            10000; /* toast notifications — always on top */

  /* Legacy aliases — light admin pages that reference un-prefixed vars will pick up
     the light admin values. Dark pages load app-glass.css (not this file) and
     define their own --navy / --gold with different values — unaffected. */
  --navy:  var(--brand-primary);
  --gold:  var(--brand-accent);
}

/* ── 2. BASE RESET ── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--brand-light);
  color: var(--brand-text);
  min-height: 100vh;
}

/* ── 3. PAGE LAYOUT ── */
/* canonical: wc-page / wc-page-header; aliases: page-wrap / page-header */
.wc-page, .page-wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 24px 60px;
}
.wc-page-header, .page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}
.wc-page-header h1, .page-header h1 { font-size: 1.4rem; }

/* ── 4. BUTTONS ── */

/* Site-wide tactile press feedback (Emil Kowalski "Animations on the Web").
   Uses :where() to give zero specificity so any class-based :active rule
   (e.g. .btn-gold-3d's translateY, driver-app's custom scales) wins. New
   buttons get the press feel for free; old buttons with bespoke press
   effects keep theirs untouched. */
button:where(:active:not(:disabled)) {
  transform: scale(0.97);
  transition: transform 0.05s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  button:where(:active:not(:disabled)) { transform: none; }
}

/* Generic in-button spinner — drop <span class="btn-spinner"></span> inside
   any button to show a loading state. Uses currentColor so it adapts to
   the button's text color (white on navy, navy on gold, etc.). */
.btn-spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
  vertical-align: -2px;
  margin-right: 6px;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn-spinner { animation: none; border-top-color: currentColor; opacity: 0.5; }
}

/* Primary — navy solid
   Canonical: .btn-primary
   Aliases:   .btn-user-add  .btn-save  .btn-add  .btn-modal-submit  .btn-send-memo */
.btn-primary,
.btn-user-add,
.btn-save,
.btn-add,
.btn-modal-submit,
.btn-send-memo {
  background: var(--brand-primary);
  color: var(--brand-text-on-primary, #fff);
  border: none;
  padding: 8px 18px;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s, transform 0.05s ease-out;
  display: inline-block;
  line-height: 1.4;
  text-decoration: none;
}
.btn-primary:hover:not(:disabled),
.btn-user-add:hover:not(:disabled),
.btn-save:hover:not(:disabled),
.btn-add:hover:not(:disabled),
.btn-modal-submit:hover:not(:disabled),
.btn-send-memo:hover:not(:disabled) { opacity: 0.85; }

/* Secondary — light bordered
   Canonical: .btn-secondary
   Aliases:   .btn-modal-cancel */
.btn-secondary,
.btn-modal-cancel {
  background: var(--brand-light);
  color: var(--brand-text);
  border: 1px solid var(--brand-border);
  padding: 8px 16px;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, transform 0.05s ease-out;
  display: inline-block;
  line-height: 1.4;
  text-decoration: none;
}
.btn-secondary:hover, .btn-modal-cancel:hover { background: var(--brand-border); }

/* Ghost — no fill, bordered, gold hover
   Canonical: .btn-ghost
   Aliases:   .btn-user-action  .btn-user-edit */
.btn-ghost,
.btn-user-action,
.btn-user-edit {
  background: none;
  color: var(--brand-text);
  border: 1px solid var(--brand-border);
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.05s ease-out;
  display: inline-block;
  line-height: 1.6;
  text-decoration: none;
}
.btn-ghost:hover,
.btn-user-action:hover,
.btn-user-edit:hover {
  background: var(--brand-light);
  border-color: var(--brand-accent);
  color: var(--brand-text);
}

/* Danger — red text/border
   Canonical: .btn-danger
   Aliases:   .btn-user-delete */
.btn-danger,
.btn-user-delete {
  background: none;
  color: var(--brand-red);
  border: 1px solid var(--brand-border);
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s, transform 0.05s ease-out;
  display: inline-block;
  line-height: 1.6;
  text-decoration: none;
}
.btn-danger:hover,
.btn-user-delete:hover { background: var(--brand-red-bg); border-color: var(--brand-red); }

/* Danger solid — red fill (modifier or .btn-user-action.danger) */
.btn-danger.solid,
.btn-user-action.danger,
.btn-danger.solid:hover,
.btn-user-action.danger:hover {
  background: var(--brand-red);
  color: #fff;
  border-color: var(--brand-red);
}
.btn-user-action.danger { color: var(--brand-red); background: none; border-color: var(--brand-border); }
.btn-user-action.danger:hover { background: var(--brand-red-bg); border-color: var(--brand-red); }

/* Gold CTA */
.btn-gold {
  background: var(--brand-accent);
  color: var(--brand-text-on-accent, var(--brand-primary));
  border: none;
  padding: 8px 18px;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s, transform 0.05s ease-out;
  display: inline-block;
  text-decoration: none;
}
.btn-gold:hover { opacity: 0.88; }

/* Size modifiers */
.btn-sm { padding: 3px 10px; font-size: 0.75rem; }
.btn-lg { padding: 11px 24px; font-size: 0.95rem; }

/* Mobile tap targets — iOS minimum is 44x44px. Desktop keeps compact look. */
@media (max-width: 600px) {
  /* Universal catch-all: any <button> is a tap target. Covers page-specific
     custom classes (.btn-nav, .filter-pill, .btn-distinctive-sync, etc.)
     that don't use the canonical .btn-* names. */
  button, input[type="button"], input[type="submit"], input[type="reset"] {
    min-height: 44px;
  }
  /* Canonical classes — explicit padding bump for breathing room */
  [class*="btn-"],
  .btn-primary, .btn-secondary, .btn-ghost, .btn-danger, .btn-gold,
  .btn-user-add, .btn-save, .btn-add, .btn-modal-submit, .btn-send-memo,
  .btn-modal-cancel, .btn-user-action, .btn-user-edit, .btn-user-delete {
    min-height: 44px;
    padding-top: 10px;
    padding-bottom: 10px;
  }
  /* .btn-sm used to keep 36px compact on mobile — Heath asked for full 44 everywhere */
  .btn-sm { min-height: 44px; padding-top: 8px; padding-bottom: 8px; }
  .btn-lg { min-height: 48px; }
  .wc-input, .wc-select, input[type="text"], input[type="email"],
  input[type="tel"], input[type="number"], input[type="password"],
  input[type="search"], input[type="date"], input[type="time"],
  textarea, select { min-height: 44px; }
  .wc-tab { min-height: 44px; }
  .wc-pill, .filter-pill { min-height: 44px; padding-top: 10px; padding-bottom: 10px; }
  .filter-tab, .picker-tab, .lp-chip { min-height: 44px; padding-top: 10px; padding-bottom: 10px; }
  .num-stepper .stepper-btn { min-width: 44px; min-height: 44px; }
  /* Pagination buttons — currently 32x44, bump width to meet iOS minimum */
  .wp-btn { min-width: 44px; padding-left: 10px; padding-right: 10px; }
  /* Close/× and small nav/icon buttons (cover the common patterns across pages) */
  button[class*="-close"],
  button.pn-x, button.btn-close-panel, button.iw-panel-close,
  button.blast-panel-close, button.init-panel-close, button.dqf-panel-close,
  button.manual-app-close, button.slideout-close, button.panel-close,
  button.dp-close, button.drawer-close-btn,
  button.btn-nav, button.date-nav-btn,
  button.itin-add-btn, button.itin-delete-btn {
    min-width: 44px; min-height: 44px;
  }
  /* Form checkboxes/radios — iOS minimum visual size */
  input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; }
  /* Clickable list alert cards (management) + collapsible group headers
     (trip-calculator) — nudge up 2-3px to clear 44 */
  .alert-item, .cost-group-header { min-height: 44px; }
  /* Collapsible section headers (trip-calculator street view, etc.) */
  .sv-header { min-height: 44px; padding-top: 12px; padding-bottom: 12px; }
  /* Back-arrow page links */
  .back-btn { min-height: 44px; display: inline-flex; align-items: center; }
  /* Wrapping labels that contain a radio/checkbox — the label IS the tap target */
  label.blast-cat, label.role-card, label.consent-label,
  label[class*="-option"], label[class*="-choice"] { min-height: 44px; display: inline-flex; align-items: center; }
  /* .lp-chip is already in the filter-tab rule above, but extra selector for icon-only active state */
  .lp-chip { min-width: 44px; }

  /* ── iOS zoom-on-focus fix ──
     iOS Safari auto-zooms the viewport whenever an input is focused at
     font-size < 16px, and frequently doesn't zoom back out on blur.
     Force 16px on every typed input on mobile. !important is intentional —
     this is enforcing a platform requirement, not a design preference, and
     it needs to beat any page-level inline font-size:13px/0.82rem. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="range"]):not([type="file"]),
  select, textarea { font-size: 16px !important; }

  /* ── Grid/flex overflow fix ──
     <input> has an implicit min-width that forces grid columns wider than
     their container. This is what made Customer Info (trip-calculator) and
     other 2-col forms overflow on 390px. Clamp it. */
  input, select, textarea { min-width: 0; }
}

/* Universal disabled state */
[class*="btn-"]:disabled,
[class*="btn-"][aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── 5. FORM ELEMENTS ── */
.wc-field { margin-bottom: 14px; }

.wc-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  margin-bottom: 5px;
  color: var(--brand-text);
}

.wc-input,
.wc-field input[type="text"],
.wc-field input[type="email"],
.wc-field input[type="tel"],
.wc-field input[type="number"],
.wc-field input[type="url"],
.wc-field input[type="date"],
.wc-field input[type="time"],
.wc-field select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-size: 0.88rem;
  font-family: inherit;
  background: var(--brand-white);
  color: var(--brand-text);
  transition: border-color 0.15s;
}
.wc-input:focus,
.wc-field input:focus,
.wc-field select:focus {
  outline: none;
  border-color: var(--brand-accent);
}

.wc-textarea,
.wc-field textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-size: 0.88rem;
  font-family: inherit;
  background: var(--brand-white);
  color: var(--brand-text);
  resize: vertical;
  min-height: 80px;
  line-height: 1.5;
}
.wc-textarea:focus, .wc-field textarea:focus {
  outline: none;
  border-color: var(--brand-accent);
}

.wc-select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-size: 0.88rem;
  font-family: inherit;
  background: var(--brand-white);
  color: var(--brand-text);
  cursor: pointer;
}
.wc-select:focus { outline: none; border-color: var(--brand-accent); }

/* ── 6. MODAL ── */
/* Canonical: .wc-overlay / .wc-modal; Aliases: .modal-overlay / .modal */
.wc-overlay,
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: var(--brand-z-modal-overlay);
  align-items: center;
  justify-content: center;
}
.wc-overlay.open,
.modal-overlay.open { display: flex; }

.wc-modal,
.modal {
  background: var(--brand-white);
  border-radius: 10px;
  padding: 28px;
  width: 440px;
  max-width: 95vw;
  box-shadow: 0 20px 60px rgba(0,0,0,0.2);
}
.wc-modal h3,
.modal h3 {
  font-size: 1.1rem;
  margin-bottom: 20px;
}

/* Modal field — label + input row */
.modal-field {
  margin-bottom: 14px;
}
.modal-field label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  margin-bottom: 5px;
  color: var(--brand-text);
}
.modal-field input,
.modal-field select,
.modal-field textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-size: 0.88rem;
  font-family: inherit;
  background: var(--brand-white);
  color: var(--brand-text);
  box-sizing: border-box;
}
.modal-field textarea {
  resize: vertical;
  line-height: 1.45;
  min-height: 64px;
}
/* Inline checkbox + label — when a .modal-field label wraps a checkbox,
   treat it as an inline-flex row so the box and its caption read as one
   unit instead of a block label sitting above a 100%-width input. */
.modal-field label:has(> input[type="checkbox"]) {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
  cursor: pointer;
  font-weight: 500;
}
.modal-field label:has(> input[type="checkbox"]) > input[type="checkbox"] {
  width: auto;
  padding: 0;
  margin: 0;
  flex: 0 0 auto;
}

.modal-field input:focus,
.modal-field select:focus,
.modal-field textarea:focus {
  outline: none;
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-accent) 18%, transparent);
}
.modal-field-hint {
  display: block;
  font-size: 0.74rem;
  color: var(--brand-muted);
  margin-top: 4px;
  line-height: 1.4;
}

/* Modal actions row */
.wc-modal-actions,
.modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 20px;
}

/* ── 7. TABLE ── */
/* Canonical: .wc-table; Alias: .user-table (base styles only) */
.wc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.wc-table th {
  text-align: left;
  padding: 10px 16px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-muted);
  background: var(--brand-light);
  border-bottom: 1px solid var(--brand-border);
  white-space: nowrap;
}
.wc-table td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--brand-border);
  vertical-align: middle;
}
.wc-table tr:last-child td { border-bottom: none; }
/* Mobile wrapper — every data table should be inside <div class="wc-table-scroll">
   so columns that exceed viewport width scroll horizontally instead of clipping. */
.wc-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.wc-table-scroll > .wc-table { min-width: max-content; }

/* Wrap-friendly modifier — opt-in for tables where multi-line cells are
   acceptable and horizontal scroll is undesirable (e.g. user-assignment
   matrices with comma-separated tag lists). Lifts the min-width:max-content
   override and lets cells wrap naturally on word boundaries. */
.wc-table-scroll > .wc-table.wc-table-wrap { min-width: 0; }
.wc-table.wc-table-wrap td {
  white-space: normal;
  word-break: break-word;
  vertical-align: top;
}
/* Small inline tag chip — used inside .wc-table-wrap cells to render
   comma-separated lists (operating companies, depots, etc.) as a
   wrap-friendly cluster instead of a long unbroken string. */
.wc-tag-cluster {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.wc-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 0.78rem;
  font-weight: 500;
  background: var(--brand-light, #f4f5f7);
  color: var(--brand-text);
  border: 1px solid var(--brand-border);
  border-radius: 999px;
  line-height: 1.4;
  white-space: nowrap;
}
.wc-tag.wc-tag-primary {
  background: color-mix(in srgb, var(--brand-accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--brand-accent) 32%, transparent);
}
.wc-tag-empty {
  font-size: 0.78rem;
  color: var(--brand-muted);
  font-style: italic;
}

/* Half-window safety net: at narrow widths (≤1100px), any non-canonical
   container that wraps a <table> gets horizontal scroll so wide tables
   don't blow past the viewport. Scoped to narrow widths to avoid disturbing
   full-width layouts that intentionally use overflow:hidden for rounded
   corners or sticky positioning. !important is intentional — many per-page
   wrappers set overflow:hidden for border-radius corner clipping; we need
   to win at narrow widths regardless. */
@media (max-width: 1100px) {
  :where(div, section, article, main):has(> table):not(.wc-table-scroll) {
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
  }
}
.wc-table tbody tr:hover td { background: var(--brand-hover); }

/* ── 8. CARD ── */
.wc-card {
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 10px;
  padding: 20px 24px;
}

/* ── 9. BADGES ── */
.wc-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 4px;
  line-height: 1;
  vertical-align: middle;
}
.wc-badge-green  { background: #dcfce7; color: #166534; }
.wc-badge-red    { background: var(--brand-red-bg); color: #991b1b; }
.wc-badge-yellow { background: var(--brand-yellow-bg); color: #854d0e; }
.wc-badge-blue   { background: var(--brand-blue-bg); color: #1e40af; }
.wc-badge-navy   { background: var(--brand-primary); color: var(--brand-text-on-primary, #fff); }
.wc-badge-muted  { background: var(--brand-light); color: var(--brand-muted); }
.wc-badge-orange { background: #fff7ed; color: #9a3412; }
.wc-badge-gold   { background: #fef3c7; color: #78350f; }
.wc-badge-purple { background: #ede9fe; color: #5b21b6; }

/* ── 10. PILLS ── */
.wc-pill-group { display: flex; flex-wrap: wrap; gap: 8px; }

.wc-pill {
  display: inline-block;
  padding: 5px 14px;
  border-radius: 20px;
  border: 1px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-muted);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s;
  user-select: none;
}
.wc-pill:hover { border-color: var(--brand-accent); color: var(--brand-text); }
.wc-pill.active {
  background: var(--brand-primary);
  color: var(--brand-text-on-primary, #fff);
  border-color: var(--brand-primary);
}

/* ── 11. TABS ── */
.wc-tabs {
  display: flex;
  gap: 0;
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 8px 8px 0 0;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.wc-tabs::-webkit-scrollbar { display: none; }

.wc-tab {
  background: none;
  border: none;
  color: var(--brand-muted);
  font-size: 13px;
  font-weight: 600;
  padding: 12px 16px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color 0.15s, border-color 0.15s;
  font-family: inherit;
  flex-shrink: 0;
}
.wc-tab:hover { color: var(--brand-text); }
.wc-tab.active {
  color: var(--brand-primary);
  border-bottom-color: var(--brand-accent);
}

/* ── 12. EMPTY STATE ── */
.wc-empty,
.empty-section {
  padding: 40px 20px;
  text-align: center;
  color: var(--brand-muted);
  font-size: 0.9rem;
}

/* ── 12b. SKELETON LOADERS ── */
/* Drop-in placeholder shown while a section's data is still loading.
   Usage: <div class="wc-skel wc-skel-line"></div>
          <div class="wc-skel wc-skel-card"></div>
   Each element animates its own shimmer; grouping isn't required. */
.wc-skel {
  position: relative;
  overflow: hidden;
  background: #eef1f4;
  border-radius: 6px;
}
.wc-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255,255,255,0.55) 50%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: wc-skel-shimmer 1.2s ease-in-out infinite;
}
.wc-skel-line { height: 12px; margin: 6px 0; }
.wc-skel-line.sm { height: 10px; width: 60%; }
.wc-skel-line.lg { height: 18px; width: 40%; }
.wc-skel-card {
  height: 72px;
  margin: 8px 0;
  border: 1px solid var(--brand-border);
}
.wc-skel-stat {
  height: 84px;
  border: 1px solid var(--brand-border);
}
.wc-skel-row {
  height: 44px;
  border-bottom: 1px solid var(--brand-border);
  background: transparent;
}
.wc-skel-row::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0,0,0,0.04) 50%,
    transparent 100%
  );
}
@keyframes wc-skel-shimmer {
  to { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .wc-skel::after { animation: none; opacity: 0.4; transform: none; }
}

/* ── 12c. SPINNER (rod-and-ball star) ── */
/*
 * Inline busy indicator. Eight glossy rod-and-ball spokes from a white
 * center, alternating two colors. Whole arrangement rotates.
 *
 * COLORS — driven by CSS custom properties so the spinner auto-themes
 * to the active tenant's brand:
 *
 *   --spin-rod-a → cardinals (N, E, S, W)   defaults to var(--brand-primary)
 *   --spin-rod-b → diagonals (NE, SE, SW, NW) defaults to var(--brand-accent)
 *
 * For Werner (brand-primary=navy, brand-accent=gold) this naturally renders
 * as the official "W1 Werner Classic" scheme. For other tenants, it auto-
 * themes to their primary+accent. To force a specific palette regardless of
 * tenant brand, add one of the .scheme-* override classes (see below).
 *
 * MARKUP:
 *   <svg class="wc-spinner" viewBox="-50 -50 100 100" aria-hidden="true">
 *     <line class="rod-arm rod-a" x1="0" y1="0" x2="0"   y2="-32"/> ...8 lines
 *     <circle class="rod-ball rod-a" cx="0" cy="-32" r="6"/>       ...8 circles
 *     <circle class="rod-center" cx="0" cy="0" r="9"/>
 *   </svg>
 *
 * SIZES — default 18px (inline). Add .wc-spinner-lg for 44px badge,
 * or set inline width/height for any custom size. SVG viewBox handles
 * scaling — internal proportions stay correct at every size.
 */
.wc-spinner {
  /* Default colors — override via .scheme-* class or per-tenant CSS */
  --spin-rod-a: var(--brand-primary, #0B1D3A);
  --spin-rod-b: var(--brand-accent, #C6973F);

  display: inline-block;
  width: 18px;
  height: 18px;
  flex: none;
  animation: wc-spinner-rotate 1.5s linear infinite;
  transform-origin: center;
}
.wc-spinner-lg { width: 44px; height: 44px; }

.wc-spinner .rod-arm    { stroke-linecap: round; stroke-width: 6; fill: none; }
.wc-spinner .rod-ball   { stroke: rgba(0,0,0,.15); stroke-width: 0.5; }
.wc-spinner .rod-center { fill: #fff; stroke: rgba(0,0,0,.2); stroke-width: 0.5; }
.wc-spinner .rod-a      { stroke: var(--spin-rod-a); fill: var(--spin-rod-a); }
.wc-spinner .rod-b      { stroke: var(--spin-rod-b); fill: var(--spin-rod-b); }

/* ── Scheme overrides — saved palettes for tenants whose brand
 *    doesn't naturally fit the rod-and-ball ──
 *
 *   .scheme-werner  Werner Classic (navy + gold)        explicit/locked
 *   .scheme-tech    Cool Tech (cyan + magenta)          vibrant SaaS
 *   .scheme-earth   Earth Tones (sage + terracotta)     warm/organic
 *   .scheme-mono    Monochrome Premium (charcoal+silver) sophisticated
 *   .scheme-multi   Vibrant Multi (teal + orange)       playful original
 *
 * Werner does NOT need .scheme-werner — the default already produces it
 * because Werner's brand-primary/accent are navy/gold.
 */
.wc-spinner.scheme-werner { --spin-rod-a: #0B1D3A; --spin-rod-b: #C6973F; }
.wc-spinner.scheme-tech   { --spin-rod-a: #00bcd4; --spin-rod-b: #e91e63; }
.wc-spinner.scheme-earth  { --spin-rod-a: #6b8e6b; --spin-rod-b: #c66a3d; }
.wc-spinner.scheme-mono   { --spin-rod-a: #36404a; --spin-rod-b: #b0b8c0; }
.wc-spinner.scheme-multi  { --spin-rod-a: #1d6c8a; --spin-rod-b: #e8742a; }

/* ── Dark glass surfaces (driver/mechanic pages) ──
 * Brand-primary is typically dark (navy/black) which would disappear
 * against the dark glass backdrop. Lift the rod-a color so geometry
 * stays visible. Defaults swap to accent + white; named schemes that
 * are already light-on-dark (tech, earth, multi) don't need
 * adjustment. Werner-classic and mono get explicit lifts. */
.glass .wc-spinner,
.app-glass .wc-spinner {
  --spin-rod-a: var(--brand-accent, #d4a953);
  --spin-rod-b: #ffffff;
}
.glass .wc-spinner.scheme-werner,
.app-glass .wc-spinner.scheme-werner {
  --spin-rod-a: #6694d8;
  --spin-rod-b: #d4a953;
}
.glass .wc-spinner.scheme-mono,
.app-glass .wc-spinner.scheme-mono {
  --spin-rod-a: #b0b8c0;
  --spin-rod-b: #ffffff;
}

@keyframes wc-spinner-rotate { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .wc-spinner { animation: none; }
}

/* ── LOADING OVERLAY (appLoading.show / hide) ── */
.app-loading-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.app-loading-overlay.app-loading-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.18s ease, visibility 0s linear 0s;
}
.app-loading-card {
  background: var(--brand-surface, #fff);
  color: var(--brand-text, #1a2744);
  border-radius: 14px;
  padding: 32px 40px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.35), 0 4px 12px rgba(0,0,0,0.2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  min-width: 280px;
  max-width: 420px;
  text-align: center;
  transform: scale(0.96);
  transition: transform 0.18s ease;
}
.app-loading-overlay.app-loading-visible .app-loading-card {
  transform: scale(1);
}
.app-loading-card .wc-spinner-lg { width: 56px; height: 56px; }
.app-loading-msg {
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-text, #1a2744);
  line-height: 1.4;
}
.app-loading-sub {
  font-size: 0.85rem;
  color: var(--brand-muted, #6b7280);
  line-height: 1.4;
  margin-top: -6px;
}
@media (max-width: 600px) {
  .app-loading-card { padding: 24px 28px; min-width: 0; width: 100%; max-width: 360px; }
  .app-loading-msg { font-size: 0.95rem; }
}

/* ── 13. TOAST ── */
.toast-container {
  position: fixed;
  bottom: max(20px, env(safe-area-inset-bottom));
  right: max(20px, env(safe-area-inset-right));
  left: max(0px, env(safe-area-inset-left));
  z-index: var(--brand-z-toast);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  pointer-events: none;
}
.toast-container > .toast { pointer-events: auto; }
.toast {
  background: var(--brand-primary);
  color: var(--brand-text-on-primary, #fff);
  padding: 12px 20px;
  border-radius: 8px;
  font-size: 0.85rem;
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  animation: wc-slide-in 0.3s ease;
  max-width: 350px;
}
.toast.success { background: #166534; }
.toast.error   { background: #991b1b; }
.toast.warning { background: #854d0e; }

@keyframes wc-slide-in {
  from { transform: translateX(100px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
/* Keep old keyframe name for pages that reference it directly */
@keyframes slideIn {
  from { transform: translateX(100px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* ── 13. NUMBER STEPPER ── */
/* Hide native spinners site-wide */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; }

/* Custom +/− stepper wrapper */
.num-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  overflow: hidden;
  background: var(--brand-white);
  height: 38px;
}
.num-stepper .stepper-btn {
  width: 38px;
  background: var(--brand-light);
  border: none;
  color: var(--brand-text);
  font-size: 1.2rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s, color 0.15s;
  user-select: none;
  -webkit-user-select: none;
  flex-shrink: 0;
}
.num-stepper .stepper-btn:hover { background: var(--brand-primary); color: var(--brand-text-on-primary, var(--brand-white)); }
.num-stepper .stepper-btn:active { background: #0f1a30; color: var(--brand-white); }
.num-stepper input[type="number"] {
  border: none;
  border-left: 1px solid var(--brand-border);
  border-right: 1px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-text);
  text-align: center;
  font-size: 0.92rem;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  padding: 0 4px;
  outline: none;
}
.num-stepper input[type="number"]:focus { background: var(--brand-blue-bg); }
.num-stepper.wide input[type="number"] { width: 80px; }
.num-stepper.narrow input[type="number"] { width: 54px; }

/* Digit-count input widths. Pick the smallest one that fits the max
   realistic value — gallons (3), quarts (3 incl. ".5"), odometer (6).
   These are independent of .wide / .narrow (which control button size
   and overall stepper height): combine .wide.digits-6 for tablet-sized
   tap targets with a 6-digit input, or .narrow.digits-3 for a compact
   inline qty field. flex:0 0 width pins the input width so a parent
   .wide override that uses flex:1 doesn't stretch it back to 100%. */
.num-stepper.digits-1 input[type="number"] { width: 40px;  flex: 0 0 40px;  }
.num-stepper.digits-2 input[type="number"] { width: 52px;  flex: 0 0 52px;  }
.num-stepper.digits-3 input[type="number"] { width: 64px;  flex: 0 0 64px;  }
.num-stepper.digits-4 input[type="number"] { width: 80px;  flex: 0 0 80px;  }
.num-stepper.digits-5 input[type="number"] { width: 96px;  flex: 0 0 96px;  }
.num-stepper.digits-6 input[type="number"] { width: 112px; flex: 0 0 112px; }
.num-stepper.digits-7 input[type="number"] { width: 128px; flex: 0 0 128px; }

/* Dark-theme baseline for steppers. Pages with class="theme-dark" on
   <body> get sensible dark colors automatically; they can still override
   with their own --fm-* / --ck-* tokens for tighter brand alignment. */
.theme-dark .num-stepper {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.14);
}
.theme-dark .num-stepper input[type="number"] {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.14);
  color: rgba(255,255,255,0.92);
}
.theme-dark .num-stepper input[type="number"]:focus {
  background: rgba(255,255,255,0.06);
}
.theme-dark .num-stepper .stepper-btn {
  background: rgba(255,255,255,0.06);
  color: rgba(255,255,255,0.92);
}
.theme-dark .num-stepper .stepper-btn:hover {
  background: var(--brand-accent);
  color: var(--brand-primary);
}
.theme-dark .num-stepper .stepper-btn:active {
  background: var(--brand-accent);
  color: var(--brand-primary);
  filter: brightness(0.9);
}

/* ── 14. NATIVE DATE / TIME PICKERS ──
   Tenant- and theme-aware styling for every native date/time/month/week
   input site-wide. No opt-in needed — applies wherever a native picker
   is used. Two CSS variables control color so light and dark surfaces
   adapt without per-page CSS:
     --wc-picker-glyph  : color of the calendar/clock indicator icon
     --wc-picker-scheme : color-scheme for the native popup (light/dark)
   The glyph SVG is masked, so background-color paints through it — that
   means each tenant's --brand-* tokens automatically theme the icon
   without us editing the SVG. */
:root {
  --wc-picker-glyph: var(--brand-primary);
  --wc-picker-scheme: light;
}

input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
  color-scheme: var(--wc-picker-scheme);
}

input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator {
  background-image: none;
  background-color: var(--wc-picker-glyph);
  -webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
  filter: none;
  cursor: pointer;
  width: 22px;
  height: 22px;
  padding: 0;
  opacity: 1;
  transition: opacity 0.15s;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover,
input[type="week"]::-webkit-calendar-picker-indicator:hover {
  opacity: 0.75;
}

/* Dark surfaces opt in by setting these two variables on a wrapper or
   <body>. Pages that should render with the dark popup + accent-color
   glyph add class="theme-dark" to <body>. */
.theme-dark {
  --wc-picker-glyph: var(--brand-accent);
  --wc-picker-scheme: dark;
}

/* ── Text — no clipping ──
   Project rule: never truncate text vertically or horizontally. Size
   containers (columns, cards, modals) to fit the longest real content
   and let text wrap naturally. Do NOT add -webkit-line-clamp, and do
   NOT use text-overflow:ellipsis in admin pages.
   The .truncate utility below is retained only for internal topbar/menu
   labels where horizontal scroll would break layout — do not apply it
   to business data (company names, trip details, user-entered text). */
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
