/* ═══════════════════════════════════════════════════════════
   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;
}

/* ── Landscape safe-area gutter (iPhone Dynamic Island / notch) ──
   In landscape the island rotates to a SIDE edge, so page content must clear
   the left/right insets — top-only padding (the common case) doesn't help.
   Pad the body globally; viewport-fit=cover (every page) opts us into drawing
   edge-to-edge, so we own the insets. Driven purely by env(): a no-op on
   desktop / iPad / portrait where side-insets are 0, so no media query needed.
   The full-bleed topbar breaks back out via negative margins (topbar.js).
   NOT covered: position:fixed/absolute edge-anchored elements (FABs, slide-out
   panels, bottom sheets) — they anchor to the viewport, not the padded body,
   so each handles its own max(px, env(safe-area-inset-*)). See CANON §10. */
body {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* ── 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; }
/* Mobile: stack the title above its action buttons so they never collide /
   overlap the (wrapped) heading on narrow screens. Pure stack — no width
   changes — to stay safe across the ~20 pages that share this header. */
@media (max-width: 600px) {
  .wc-page-header, .page-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
}

/* ── 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, 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); }

/* ════════════════════════════════════════════════════════════════════════
   STYLED SELECT — "Elevated" (site-wide dropdown restyle, 2026-05-28)
   Replaces the native browser <select> arrow (boxy/inconsistent across browsers,
   ugly in Firefox) with a custom chevron + soft elevation.

   The chevron longhands carry !important ON PURPOSE: several pages set their
   select bg with a `background:` SHORTHAND at higher specificity (e.g.
   `.wo-toolbar .filter-select { background: var(--fm-input-bg) }`, 0,2,0). Without
   !important that shorthand resets background-repeat to `repeat`, tiling the
   chevron into a zigzag (the bug from the first attempt). !important on just the
   chevron properties lets the design system win that one concern while the page's
   theme background-COLOR (also from its shorthand, non-important) is preserved.

   Theme-aware: fleet-maintenance ships <body class="theme-dark"> (always dark),
   so .theme-dark swaps to a light chevron + dark-adaptive fill. Light admin pages
   (no .theme-dark) get the navy chevron. Dark driver/mechanic apps load
   app-glass.css and keep their own select styling — unaffected.
   Verified on the live authed pages (crm light + fleet dark) before shipping.
   ════════════════════════════════════════════════════════════════════════ */
select,
.wc-select,
.wc-field select,
.modal-field select,
select.form-select,
select.filter-select,
select.cell-select {
  -webkit-appearance: none !important;
  -moz-appearance: none !important;
  appearance: none !important;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%231a2744' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: right 11px center !important;
  background-size: 12px !important;
  padding-right: 32px !important;
}
/* Elevated visual: bare/canonical/field/modal selects (white fill, hairline
   border, soft shadow). Theme-aware classed selects keep their own bg + border. */
select,
.wc-select,
.wc-field select,
.modal-field select {
  border: 1px solid #e4e8ee;
  border-radius: 8px;
  background-color: var(--brand-white);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
  transition: border-color 0.14s ease, box-shadow 0.14s ease;
}
select:hover,
.wc-select:hover,
.wc-field select:hover,
.modal-field select:hover {
  border-color: #cdd4dd;
  box-shadow: 0 2px 5px rgba(15, 23, 42, 0.09);
}
select:focus,
.wc-select:focus,
.wc-field select:focus,
.modal-field select:focus,
select.form-select:focus,
select.filter-select:focus,
select.cell-select:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(26, 39, 68, 0.12);
}
/* Dark theme (body.theme-dark — e.g. fleet-maintenance): light chevron + dark-
   adaptive fill for bare/canonical (classed selects keep their theme bg). */
.theme-dark select,
.theme-dark .wc-select,
.theme-dark .wc-field select,
.theme-dark .modal-field select,
.theme-dark select.form-select,
.theme-dark select.filter-select,
.theme-dark select.cell-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23c9d2de' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
}
.theme-dark select,
.theme-dark .wc-select,
.theme-dark .wc-field select,
.theme-dark .modal-field select {
  background-color: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.16);
  color: inherit;
}
.theme-dark select:focus,
.theme-dark .wc-select:focus,
.theme-dark select.form-select:focus,
.theme-dark select.filter-select:focus,
.theme-dark select.cell-select:focus {
  border-color: #6b7a92;
  box-shadow: 0 0 0 3px rgba(150, 170, 200, 0.22);
}

/* ── 6. MODAL ── */
/* Canonical: .wc-overlay / .wc-modal; Aliases: .modal-overlay / .modal
   Pages that need a custom centering model (e.g. absolute + translate, like
   crm.html) override these locally — opacity-based open/close still works
   either way as long as the .open class is the toggle. */
.wc-overlay,
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: var(--brand-z-modal-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 150ms cubic-bezier(0.215,0.61,0.355,1);
}
.wc-overlay.open,
.modal-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.wc-modal,
.modal {
  background: var(--brand-white);
  border-radius: 10px;
  padding: 28px;
  width: 440px;
  max-width: 95vw;
  max-height: min(90dvh, 860px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  box-shadow: 0 20px 60px rgba(0,0,0,0.2);
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 180ms cubic-bezier(0.215,0.61,0.355,1),
              transform 180ms cubic-bezier(0.215,0.61,0.355,1);
}
.wc-overlay.open .wc-modal,
.wc-overlay.open .modal,
.modal-overlay.open .wc-modal,
.modal-overlay.open .modal {
  opacity: 1;
  transform: scale(1);
}
/* Pin the title — stays visible while the body scrolls */
.wc-modal > h3,
.modal > h3 {
  position: sticky;
  top: -28px;
  margin: -28px -28px 16px;
  padding: 24px 28px 12px;
  background: var(--brand-white);
  z-index: 2;
  font-size: 1.1rem;
}

/* 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 — sticky-pinned to the modal's bottom edge so Save is
   always reachable on tall forms without scrolling. */
.wc-modal > .wc-modal-actions,
.wc-modal > .modal-actions,
.modal > .wc-modal-actions,
.modal > .modal-actions {
  position: sticky;
  bottom: -28px;
  margin: 20px -28px -28px;
  padding: 14px 28px;
  background: var(--brand-white);
  border-top: 1px solid var(--brand-border);
  z-index: 2;
}
.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; }

/* ── List end-cap (wc-list-end) ───────────────────────────────────
   Terminal "you've reached the end" cue for long scrolling lists and
   tables. Solves two problems at once: (1) a clear end-of-list signal
   so the last item isn't ambiguous/forgettable, and (2) generous bottom
   padding so the final row clears the viewport edge and any floating UI
   (help bubble / FAB). Opt-in — append after a list, or as the last
   table row:
     <div class="wc-list-end">End of list · 90 items</div>
     <tr class="wc-list-end-row"><td colspan="N"><div class="wc-list-end">…</div></td></tr>
   Empty text auto-hides. Light-theme tokens; dark (app-glass) pages need
   their own muted/border colors. First shipped: Daily Schedule, 2026-05-28. */
.wc-list-end {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 16px 96px;
  color: var(--brand-muted);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  user-select: none;
}
.wc-list-end::before,
.wc-list-end::after {
  content: "";
  height: 1px;
  width: 32px;
  background: var(--brand-border);
}
.wc-list-end:empty { display: none; }
/* Table variant: strip cell chrome so the cue reads as a footer, not a data row */
.wc-list-end-row td,
.wc-list-end-row:hover td { border: none !important; background: none !important; padding: 0 !important; }

/* 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: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
  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; }

/* Horizontal tab strips scroll on overflow but must never show the native
   grey scrollbar (it reads as a broken UI element under the tabs). Same
   treatment as .wc-tabs above — scroll kept, bar hidden, every browser. */
.tabbar, .vd-tabs {
  scrollbar-width: none;        /* Firefox */
  -ms-overflow-style: none;     /* IE / old Edge */
}
.tabbar::-webkit-scrollbar, .vd-tabs::-webkit-scrollbar { display: none; }  /* WebKit / Chrome / Safari */

.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 {
  /* Solid dark loading surface — the aurora "B" is a glow mark and only reads
     at full brilliance against something dark. Defaults to brand navy (matches
     the topbar, so it echoes the chrome rather than clashing); a tenant whose
     primary isn't dark can override --app-loading-bg. */
  background: var(--app-loading-bg, #1a2744);
  color: #fff;
  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);
}
/* Branded loading mark — aurora "B" with a comet-tail ring sweeping around it.
   Used only in the full-screen appLoading overlay; inline .wc-spinner sites keep
   the rod-and-ball spinner. The B glows against the dark card above. */
/* Branded 3-D "B" loading mark — a solid black extruded B that revolves with a
   blue edge. Built by appSpinner.b3d(size): stacked layers (spinner-b-core.png)
   for the depth + two faces (spinner-b-face.png). The revolve hops across the
   exact edge-on frame (88°→92°) so there is no blink. This is the ONE loading
   indicator site-wide — appLoading overlay, inline loading signs, page/button. */
.b3d {
  position: relative;
  display: inline-flex;
  flex: none;
  vertical-align: middle;
  perspective: 900px;
}
.b3d-rot {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: b3d-spin 1.62s linear infinite;
}
.b3d-face {
  position: absolute;
  inset: 0;
  background: url(spinner-b-face.png) center / contain no-repeat;
  backface-visibility: hidden;
}
.b3d-core {
  position: absolute;
  inset: 0;
  background: url(spinner-b-core.png) center / contain no-repeat;
}
/* Small-size wrapper: appSpinner.b3d(<28) builds the mark at 2× inside this
   same-size box and scales it down, doubling the raster backing store so the
   B stays crisp at 18px on 2× screens. */
.b3d-x2 {
  position: relative;
  display: inline-flex;
  flex: none;
  vertical-align: middle;
}
.b3d-x2 > .b3d {
  position: absolute;
  top: 0;
  left: 0;
  transform: scale(0.5);
  transform-origin: 0 0;
}
@keyframes b3d-spin {
  0%     { transform: rotateY(0deg); }
  25%    { transform: rotateY(88deg); }
  25.02% { transform: rotateY(92deg); }
  75%    { transform: rotateY(268deg); }
  75.02% { transform: rotateY(272deg); }
  100%   { transform: rotateY(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .b3d-rot { animation: none; }
}
.app-loading-msg {
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
  line-height: 1.4;
}
.app-loading-sub {
  font-size: 0.85rem;
  color: rgba(255,255,255,0.72);
  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; }
}

/* ── 12d. SAVE FLASH ──
   Pulse-back acknowledgement for inline saves. Add .saved on success,
   remove ~600ms later (or use appUtils.flashSaved(el) which handles
   the timing). Works on any inline/block element. */
.save-flash {
  border-radius: 4px;
  transition: background-color 220ms cubic-bezier(0.215,0.61,0.355,1);
}
.save-flash.saved {
  background-color: rgba(45,155,90,0.16);
}

/* ── 12e. REDUCED MOTION (site-wide) ──
   Flatten every animation/transition when the OS-level Reduce Motion
   preference is on. Individual sections may still scope their own
   rules; this is the universal safety net. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 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 200ms cubic-bezier(0.215,0.61,0.355,1) both;
  max-width: 350px;
}
.toast.success { background: #166534; }
.toast.error   { background: #991b1b; }
.toast.warning { background: #854d0e; }
.toast.leaving { animation: wc-slide-out 160ms cubic-bezier(0.215,0.61,0.355,1) forwards; }

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

@media (prefers-reduced-motion: reduce) {
  .toast, .toast.leaving { animation: none; }
}

/* ── 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; }

/* Grid-cell variant. This is the ALTERNATIVE to digits-N, not a companion,
   and it must follow them here to win the equal-specificity tie. A stepper is
   normally inline-flex at its intrinsic digits-N width, so a row of them
   inside a form-row / form-row-3 renders at three different widths with
   ragged right edges, and any stepper wider than its 1fr column forces that
   column to grow and squeezes its siblings. .fill makes the stepper own its
   column and lets the input absorb the slack, so selects, inputs and steppers
   in one row line up flush. Use digits-N free-standing, .fill in a grid row. */
.num-stepper.fill { display: flex; width: 100%; }
.num-stepper.fill input[type="number"] { width: auto; flex: 1 1 auto; min-width: 0; }

/* 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;
}

/* ── Surcharge badges ──
   Shared chip for the three pricing_surcharges types. Used by
   trip-calculator.html (per-trip evaluation) and calendar.html (per-day
   active rules). Active = solid pastel + checkmark; inactive = white +
   dashed border + plus sign. */
.surcharge-badges {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.surcharge-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 20px; font-size: 12px;
  font-weight: 700; font-family: 'JetBrains Mono', monospace;
	  border: 1.5px solid transparent; transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.surcharge-badge.calendar    { background: #FEF3C7; color: #92400E; border-color: #B45309; }
.surcharge-badge.day_of_week { background: #DBEAFE; color: #1E40AF; border-color: #1E40AF; }
.surcharge-badge.utilization { background: #FCE7F3; color: #9D174D; border-color: #9D174D; }
.surcharge-badge::before {
  content: '\2713'; font-weight: 800; font-size: 11px; opacity: 0.85;
}
.surcharge-badge.is-inactive {
  background: #fff; border-style: dashed; font-weight: 600; cursor: pointer;
}
.surcharge-badge.is-inactive::before { content: '+'; opacity: 1; }
.surcharge-badge.is-inactive.calendar    { color: #B45309; border-color: #FCD34D; }
.surcharge-badge.is-inactive.day_of_week { color: #1E40AF; border-color: #93C5FD; }
.surcharge-badge.is-inactive.utilization { color: #9D174D; border-color: #F9A8D4; }
.surcharge-badge.is-inactive:hover {
  border-style: solid; transform: translateY(-1px);
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
.surcharge-badge.is-inactive.calendar:hover    { background: #FEF3C7; }
.surcharge-badge.is-inactive.day_of_week:hover { background: #DBEAFE; }
.surcharge-badge.is-inactive.utilization:hover { background: #FCE7F3; }
.surcharge-badge .badge-x {
  cursor: pointer; opacity: 0.55; margin-left: 1px; font-size: 14px; line-height: 1;
}
.surcharge-badge .badge-x:hover { opacity: 1; }
/* Compact pct-vs-flat suffix used inside the badge text */
.surcharge-badge .badge-kind { font-size: 10px; opacity: 0.7; font-weight: 600; }
