/* ==========================================================================
   Charlie — components
   ========================================================================== */

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--ink-950);
  --btn-fg: #fff;
  --btn-border: transparent;
  --btn-shadow: var(--shadow-sm);
  /* A hairline of light along the top edge. It is the difference between a
     button that looks printed on and one that looks like an object. */
  --btn-sheen: inset 0 1px 0 rgba(255, 255, 255, 0.14);

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 0.78rem 1.4rem;
  min-height: 48px;
  border: 1px solid var(--btn-border);
  border-radius: var(--r-full);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: var(--tracking-snug);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  overflow: hidden;
  box-shadow: var(--btn-shadow), var(--btn-sheen);
  transition:
    transform var(--dur-2) var(--ease-swift),
    box-shadow var(--dur-2) var(--ease-out),
    background-color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}
/* A light sweep that crosses the face on hover. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg, transparent 20%, rgba(255, 255, 255, 0.22) 50%, transparent 80%
  );
  transform: translateX(-120%);
  transition: transform var(--dur-4) var(--ease-swift);
  pointer-events: none;
}
.btn:hover::after { transform: translateX(120%); }
.btn:hover { text-decoration: none; transform: translateY(-2px); color: var(--btn-fg); }
.btn:active { transform: translateY(0) scale(0.99); }
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
  transform: none;
}

.btn--primary {
  --btn-bg: var(--red-500);
  --btn-shadow: var(--shadow-brand);
  background-image: linear-gradient(180deg, var(--red-400), var(--red-500) 58%, var(--red-600));
}
.btn--primary:hover { box-shadow: var(--shadow-brand-lg), var(--btn-sheen); }

.btn--dark { --btn-bg: var(--ink-950); }
.btn--dark:hover { --btn-bg: var(--ink-800); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink-800);
  --btn-border: var(--border-strong);
  --btn-shadow: none;
  --btn-sheen: none;
}
.btn--ghost:hover { --btn-bg: var(--ink-50); --btn-border: var(--ink-400); }
.btn--ghost::after { display: none; }

.btn--quiet {
  --btn-bg: transparent;
  --btn-fg: var(--text-muted);
  --btn-shadow: none;
  --btn-sheen: none;
  padding-inline: 0.9rem;
}
.btn--quiet:hover { --btn-bg: var(--ink-100); --btn-fg: var(--ink-900); }
.btn--quiet::after { display: none; }

.btn--on-dark {
  --btn-bg: rgba(255, 255, 255, 0.07);
  --btn-fg: #fff;
  --btn-border: rgba(255, 255, 255, 0.16);
  --btn-shadow: none;
  --btn-sheen: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.btn--on-dark:hover {
  --btn-bg: rgba(255, 255, 255, 0.13);
  --btn-border: rgba(255, 255, 255, 0.28);
}

.btn--danger { --btn-bg: var(--danger-500); --btn-shadow: none; }
.btn--danger:hover { --btn-bg: var(--danger-700); }

.btn--success { --btn-bg: var(--success-500); --btn-shadow: none; }
.btn--success:hover { --btn-bg: var(--success-700); }

.btn--sm { min-height: 38px; padding: 0.5rem 1rem; font-size: var(--text-sm); }
.btn--xs { min-height: 32px; padding: 0.35rem 0.75rem; font-size: var(--text-xs); }
.btn--lg { min-height: 56px; padding: 1rem 1.9rem; font-size: var(--text-md); }
.btn--block { width: 100%; }
.btn--icon { padding: 0.6rem; min-height: 42px; aspect-ratio: 1; border-radius: var(--r-full); }

/* The arrow nudges on hover — a small, deliberate reward, not a flourish. */
.btn__arrow { transition: transform var(--dur-2) var(--ease-spring); }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Cards & surfaces
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
.card--glass {
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-color: rgba(255, 255, 255, 0.55);
  box-shadow: var(--shadow-float);
}
.card__body { padding: var(--sp-6); }
.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--border-subtle);
}
.card__header h2,
.card__header h3 { font-size: var(--text-lg); letter-spacing: var(--tracking-snug); }
.card__footer {
  padding: var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--border-subtle);
  background: var(--ink-25);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.card--flush .card__body { padding: 0; }
.card--interactive {
  transition: transform var(--dur-3) var(--ease-swift),
              box-shadow var(--dur-3) var(--ease-swift),
              border-color var(--dur-3) var(--ease-swift);
}
.card--interactive:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--border);
}
.card--inverse {
  background: var(--ink-950);
  border-color: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.82);
}
.card--inverse h1, .card--inverse h2,
.card--inverse h3, .card--inverse h4 { color: #fff; }

.panel {
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
  padding: var(--sp-5);
}

/* --------------------------------------------------------------------------
   Badges & pills
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.3rem 0.7rem;
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: 0.01em;
  line-height: 1.3;
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: var(--r-full);
  background: currentColor;
  flex: none;
}
.badge--neutral  { background: var(--ink-100);      color: var(--ink-600);      border-color: var(--ink-200); }
.badge--info     { background: var(--info-50);      color: var(--info-700);     border-color: #CBDCFF; }
.badge--success  { background: var(--success-50);   color: var(--success-700);  border-color: #BDEBD6; }
.badge--warning  { background: var(--warning-50);   color: var(--warning-700);  border-color: #FAE0AA; }
.badge--danger   { background: var(--danger-50);    color: var(--danger-500);   border-color: #F7CBC6; }
.badge--progress { background: var(--progress-50);  color: var(--progress-700); border-color: #D8CDFA; }
.badge--brand    { background: var(--red-50);       color: var(--red-700);      border-color: var(--red-100); }
.badge--plain::before { display: none; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.4rem 0.85rem;
  border-radius: var(--r-full);
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: var(--text-sm);
  font-weight: 550;
  color: var(--ink-700);
  transition: all var(--dur-1) var(--ease-out);
}
.chip:hover { border-color: var(--ink-400); text-decoration: none; color: var(--ink-900); }
.chip--active {
  background: var(--ink-950);
  border-color: var(--ink-950);
  color: #fff;
}
.chip--active:hover { color: #fff; }
.chip__remove { display: inline-flex; opacity: 0.6; }
.chip__remove:hover { opacity: 1; }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
.field { display: block; margin-bottom: var(--sp-5); }
.field:last-child { margin-bottom: 0; }

.field__label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-800);
  letter-spacing: var(--tracking-snug);
}
.field__label .req { color: var(--red-500); margin-inline-start: 2px; }

.field__hint {
  margin-top: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.5;
}

.field__error {
  display: flex;
  align-items: flex-start;
  gap: 0.4em;
  margin-top: var(--sp-2);
  font-size: var(--text-xs);
  font-weight: 550;
  color: var(--danger-500);
}

.input,
.select,
.textarea {
  width: 100%;
  padding: 0.8rem 1rem;
  min-height: 50px;
  background: var(--ink-25);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--text-base);
  color: var(--text);
  transition:
    border-color var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out),
    background-color var(--dur-2) var(--ease-out);
}
.textarea { min-height: 96px; resize: vertical; line-height: var(--leading-normal); }

.input::placeholder,
.textarea::placeholder { color: var(--ink-400); }

.input:hover,
.select:hover,
.textarea:hover { border-color: var(--ink-300); background: var(--surface); }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--red-500);
  box-shadow: var(--ring);
}

.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  border-color: var(--danger-500);
  background: var(--danger-50);
}
.input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px rgba(180, 35, 24, 0.18); }

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--ink-50);
  color: var(--text-muted);
  cursor: not-allowed;
}

.select {
  appearance: none;
  padding-inline-end: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%236E7889' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  cursor: pointer;
}

/* Searchable select: a native <select> enhanced with a type-to-filter text
   box in front of it (see initSearchableSelect in charlie.js). The native
   select stays in the DOM — still the real form value — just not shown. */
.searchable-select { position: relative; }
.searchable-select__native { display: none; }
.searchable-select__list {
  position: absolute;
  z-index: 20;
  top: calc(100% + var(--sp-2));
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.12));
}
.searchable-select__list[hidden] { display: none; }
.searchable-select__option {
  display: block;
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: var(--text);
}
.searchable-select__option:hover,
.searchable-select__option:focus { background: var(--ink-50); }

/* Native date/time controls: make the picker indicator match the palette. */
input[type="date"],
input[type="time"],
input[type="datetime-local"] { min-height: 48px; }
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.55;
  transition: opacity var(--dur-1) var(--ease-out);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* The control and its icon. `position: relative` belongs here rather than on
   `.field`, which also contains the label and the hint — centring against the
   whole block put every icon 14px above the middle of its input. */
.field__control { position: relative; }

.field--inline-icon .input,
.field--inline-icon .select { padding-inline-start: 2.85rem; }

.field--inline-icon .field__icon {
  position: absolute;
  inset-inline-start: 0.95rem;
  top: 50%;
  transform: translateY(-50%);
  /* A fixed box, and an svg that cannot grow out of it. The size is on the
     <svg> element too, but a stylesheet that fails to load, or a browser that
     scales by font size, should not be able to leave a 40px pin sprawling
     across the field. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 18px;
  block-size: 18px;
  color: var(--ink-400);
  pointer-events: none;
}
.field--inline-icon .field__icon > svg {
  inline-size: 18px;
  block-size: 18px;
  flex: none;
}

/* ---- Checkbox / radio -------------------------------------------------- */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  cursor: pointer;
  font-size: var(--text-base);
  line-height: 1.45;
}
.check input[type="checkbox"],
.check input[type="radio"] {
  appearance: none;
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border: 1.6px solid var(--border-strong);
  background: var(--surface);
  cursor: pointer;
  transition: all var(--dur-1) var(--ease-out);
}
.check input[type="checkbox"] { border-radius: 6px; }
.check input[type="radio"] { border-radius: var(--r-full); }
.check input:hover { border-color: var(--ink-400); }
.check input:checked {
  background: var(--red-500);
  border-color: var(--red-500);
}
.check input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E");
  background-size: 14px;
  background-position: center;
  background-repeat: no-repeat;
}
.check input[type="radio"]:checked {
  box-shadow: inset 0 0 0 4px var(--surface);
}
.check input:focus-visible { box-shadow: var(--ring); }

/* ---- Selectable option cards (payment method, when-to-travel, …) ------- */
.option-grid { display: grid; gap: var(--sp-3); }
@media (min-width: 560px) {
  .option-grid--2 { grid-template-columns: 1fr 1fr; }
}

.option {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1.5px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: all var(--dur-2) var(--ease-out);
}
.option:hover { border-color: var(--ink-400); background: var(--ink-25); }
.option input { position: absolute; opacity: 0; pointer-events: none; }
.option__mark {
  flex: none;
  width: 20px; height: 20px;
  margin-top: 2px;
  border: 1.6px solid var(--border-strong);
  border-radius: var(--r-full);
  transition: all var(--dur-1) var(--ease-out);
}
.option__title { font-weight: 600; color: var(--ink-900); line-height: 1.35; }
.option__desc { font-size: var(--text-sm); color: var(--text-muted); margin-top: 2px; }
.option:has(input:checked) {
  border-color: var(--red-500);
  background: var(--red-50);
  box-shadow: 0 0 0 1px var(--red-500);
}
.option:has(input:checked) .option__mark {
  border-color: var(--red-500);
  background: var(--red-500);
  box-shadow: inset 0 0 0 4px var(--surface);
}
.option:has(input:focus-visible) { box-shadow: var(--ring); }
.option--disabled { opacity: 0.55; cursor: not-allowed; }
.option--disabled:hover { border-color: var(--border); background: var(--surface); }

/* ---- Segmented toggle (Taximeter/Manual, Cash/Account, When, …) -------
   The same radio group, read as two switch positions rather than two forms
   to pick between — no dot, filled when active, sitting edge to edge, and
   sized like a real control rather than a card that happens to hold one. */
.option-grid--toggle {
  gap: 0;
  border: 1.5px solid var(--border);
  border-radius: var(--r-sm, 6px);
  overflow: hidden;
}
.option--toggle {
  justify-content: center;
  align-items: center;
  text-align: center;
  min-height: 36px;
  padding: 6px var(--sp-3);
  border: none;
  border-radius: 0;
  background: var(--surface);
}
.option--toggle:not(:first-child) { border-inline-start: 1.5px solid var(--border); }
.option--toggle:hover { background: var(--ink-25); }
.option--toggle .option__title { font-size: var(--text-sm); font-weight: 600; line-height: 1.2; }
.option--toggle:has(input:checked) {
  background: var(--red-500);
  box-shadow: none;
  border-color: transparent;
}
.option--toggle:has(input:checked) .option__title { color: #fff; }

/* ---- Field groups ------------------------------------------------------ */
.field-row { display: grid; gap: var(--sp-4); }
@media (min-width: 640px) {
  .field-row--2 { grid-template-columns: 1fr 1fr; }
  .field-row--3 { grid-template-columns: repeat(3, 1fr); }
  .field-row--4 { grid-template-columns: repeat(4, 1fr); }
  .field-row--2-1 { grid-template-columns: 2fr 1fr; }
}
.field-row .field { margin-bottom: 0; }

.fieldset {
  border: none;
  padding: 0;
  margin: 0 0 var(--sp-7);
  /* Browsers give <fieldset> `min-inline-size: min-content`, so it refuses to
     shrink and drags its container wide. Setting `min-width` alone does not
     reliably override the UA rule; set the logical property it actually uses. */
  min-inline-size: 0;
  min-width: 0;
}
.fieldset__legend {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
  padding: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: var(--tracking-snug);
  color: var(--ink-950);
}
.fieldset__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  border-radius: var(--r-full);
  background: var(--ink-950);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
  flex: none;
}

/* --------------------------------------------------------------------------
   Alerts & messages
   -------------------------------------------------------------------------- */
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  font-size: var(--text-base);
  line-height: 1.5;
}
.alert__icon { flex: none; margin-top: 1px; }
.alert__body { flex: 1; min-width: 0; }
.alert__title { font-weight: 650; margin-bottom: 2px; }
.alert--info    { background: var(--info-50);    border-color: #CBDCFF; color: var(--info-700); }
.alert--success { background: var(--success-50); border-color: #BDEBD6; color: var(--success-700); }
.alert--warning { background: var(--warning-50); border-color: #FAE0AA; color: var(--warning-700); }
.alert--error,
.alert--danger  { background: var(--danger-50);  border-color: #F7CBC6; color: var(--danger-700); }
.alert--neutral { background: var(--ink-50);     border-color: var(--border); color: var(--ink-700); }

.toast-stack {
  position: fixed;
  top: calc(var(--header-h) + var(--sp-3));
  inset-inline-end: var(--gutter);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(420px, calc(100vw - var(--gutter) * 2));
  pointer-events: none;
}
.toast-stack .alert {
  pointer-events: auto;
  box-shadow: var(--shadow-lg);
  background-color: var(--surface);
  animation: toast-in var(--dur-3) var(--ease-spring) both;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(-10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   Tables — collapse to cards on small screens
   -------------------------------------------------------------------------- */
.table-wrap {
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow-x: auto;
}

.table { width: 100%; font-size: var(--text-sm); }

/* Cells hold their line on desktop — a reference or a service name broken
   across two lines makes a table much harder to scan. Anything genuinely
   long opts out with `.cell--wrap`, and the whole table reflows into cards
   below 860px anyway. */
@media (min-width: 861px) {
  .table td, .table th { white-space: nowrap; }
  .table td.cell--wrap, .table th.cell--wrap { white-space: normal; }
  .table td.cell--wrap { min-width: 18rem; }
}

/* Reference columns: monospaced, so digits align and the column stays narrow. */
.table__ref {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: -0.01em;
}
.table thead th {
  padding: var(--sp-3) var(--sp-4);
  background: var(--ink-25);
  border-bottom: 1px solid var(--border);
  text-align: start;
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}
.table tbody td {
  padding: var(--sp-4);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
.table tbody tr:hover { background: var(--ink-25); }
.table .num { text-align: end; font-variant-numeric: tabular-nums; }
.table__primary { font-weight: 600; color: var(--ink-900); }
.table__meta { font-size: var(--text-xs); color: var(--text-muted); margin-top: 2px; }

/*
  Below 860px each row becomes a stacked card and the column headings are
  re-rendered from `data-label`. Admin tables never overflow horizontally.
*/
@media (max-width: 860px) {
  .table--responsive thead { display: none; }
  .table--responsive,
  .table--responsive tbody,
  .table--responsive tr,
  .table--responsive td { display: block; width: 100%; }
  .table--responsive tr {
    padding: var(--sp-4);
    border-bottom: 1px solid var(--border);
  }
  .table--responsive tr:last-child { border-bottom: none; }
  .table--responsive td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: 0.3rem 0;
    border: none;
    text-align: end;
    /* A long value — a two-line meta line, a full address — has to wrap or
       shrink rather than push the card past the screen. Without these the
       reports page scrolled sideways by the 4px its widest cell overshot. */
    flex-wrap: wrap;
    min-width: 0;
    overflow-wrap: anywhere;
  }
  .table--responsive td::before {
    content: attr(data-label);
    flex: none;
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--text-subtle);
    text-align: start;
  }
  .table--responsive td[data-label=""]::before,
  .table--responsive td:not([data-label])::before { content: none; }
  .table--responsive td.cell--full {
    display: block;
    text-align: start;
    padding-bottom: var(--sp-3);
  }
  .table--responsive .num { text-align: end; }

  /* Row actions are the whole point of the card on a phone, and `btn--xs`
     renders at 32px — under a thumb. Give them a real target here without
     enlarging them on desktop, where the pointer is precise and the tables
     are dense on purpose. */
  .table--responsive .btn--xs {
    min-height: 40px;
    padding-inline: var(--sp-4);
  }
}

/* --------------------------------------------------------------------------
   Empty states
   -------------------------------------------------------------------------- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--sp-12) var(--sp-6);
  color: var(--text-muted);
}
.empty__icon {
  display: grid;
  place-items: center;
  width: 64px; height: 64px;
  margin-bottom: var(--sp-4);
  border-radius: var(--r-full);
  background: var(--ink-50);
  color: var(--ink-400);
}
.empty__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--ink-900);
  margin-bottom: var(--sp-2);
}
.empty p { max-width: 46ch; }

/* --------------------------------------------------------------------------
   Stats
   -------------------------------------------------------------------------- */
.stat {
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
}
.stat__label {
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-subtle);
}
.stat__value {
  margin-top: var(--sp-2);
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--tracking-tight);
  color: var(--ink-950);
  font-variant-numeric: tabular-nums;
}
.stat__value--sm { font-size: var(--text-2xl); }
.stat__meta { margin-top: var(--sp-2); font-size: var(--text-xs); color: var(--text-muted); }
.stat--accent { border-inline-start: 3px solid var(--red-500); }
.stat--success { border-inline-start: 3px solid var(--success-500); }
.stat--warning { border-inline-start: 3px solid var(--warning-500); }

/* --------------------------------------------------------------------------
   Progress / timeline
   -------------------------------------------------------------------------- */
.progress-track {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--ink-100);
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--red-500), var(--red-400));
  transition: width var(--dur-4) var(--ease-out);
}
.progress-bar--success { background: linear-gradient(90deg, var(--success-500), #34C98D); }
.progress-bar--neutral { background: var(--ink-400); }

.timeline { position: relative; padding-inline-start: 28px; }
.timeline::before {
  content: "";
  position: absolute;
  left: 8px; top: 8px; bottom: 8px;
  width: 2px;
  background: var(--border);
  border-radius: 2px;
}
.timeline__item { position: relative; padding-bottom: var(--sp-5); }
.timeline__item:last-child { padding-bottom: 0; }
.timeline__dot {
  position: absolute;
  inset-inline-start: -28px; top: 3px;
  width: 18px; height: 18px;
  border-radius: var(--r-full);
  background: var(--surface);
  border: 2px solid var(--border-strong);
  display: grid;
  place-items: center;
  color: transparent;
}
.timeline__item--done .timeline__dot {
  background: var(--success-500);
  border-color: var(--success-500);
  color: #fff;
}
.timeline__item--current .timeline__dot {
  background: var(--red-500);
  border-color: var(--red-500);
  box-shadow: 0 0 0 4px var(--red-100);
}
.timeline__title { font-weight: 600; color: var(--ink-900); font-size: var(--text-base); }
.timeline__item--pending .timeline__title { color: var(--text-subtle); font-weight: 500; }
.timeline__meta { font-size: var(--text-xs); color: var(--text-muted); margin-top: 1px; }

/* `.pulse-dot` is defined in motion.css alongside the other live states. */

/* --------------------------------------------------------------------------
   Route (pickup → drop-off)
   Shared by the back office, the customer portal and the driver PWA, so it
   belongs here rather than in any one surface's stylesheet.
   -------------------------------------------------------------------------- */
.route { display: grid; gap: var(--sp-3); }
.route__point {
  position: relative;
  display: flex;
  gap: var(--sp-3);
  padding-inline-start: var(--sp-1);
}
.route__marker {
  position: relative;
  flex: none;
  width: 12px;
  height: 12px;
  margin-top: 5px;
  border-radius: var(--r-full);
  border: 2.5px solid var(--ink-400);
  background: var(--surface);
}
.route__point--end .route__marker { border-color: var(--red-500); background: var(--red-500); }
.route__point:not(:last-child) .route__marker::after {
  content: "";
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: calc(100% + var(--sp-3) - 6px);
  min-height: 20px;
  background: repeating-linear-gradient(
    180deg, var(--ink-300) 0 3px, transparent 3px 6px
  );
}
.route__label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-subtle);
}
.route__value { color: var(--ink-900); font-weight: 550; line-height: 1.4; }
.route__extra { font-size: var(--text-sm); color: var(--text-muted); margin-top: 2px; }

/* --------------------------------------------------------------------------
   Avatars
   -------------------------------------------------------------------------- */
/* The avatar is gone, on purpose.
   An initials disc is a placeholder for a photograph in a product that has
   no photographs. It told the account holder nothing they did not know, and
   down the first column of the customers, drivers and staff tables it was
   decoration occupying the position the eye reads first.
   Removed here rather than left as dead rules so that nobody reintroduces
   it by reaching for a class that still styles. The `initials` template
   filter is likewise unused now and kept only because it is three lines.
   Names are what identify people in this product. */

/* --------------------------------------------------------------------------
   Tabs & pagination
   -------------------------------------------------------------------------- */
.tabs {
  display: flex;
  gap: var(--sp-1);
  padding: 4px;
  background: var(--ink-100);
  border-radius: var(--r-full);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  padding: 0.5rem 1rem;
  border-radius: var(--r-full);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  transition: all var(--dur-1) var(--ease-out);
}
.tab:hover { color: var(--ink-900); text-decoration: none; }
.tab--active {
  background: var(--surface);
  color: var(--ink-950);
  box-shadow: var(--shadow-xs);
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
}
.pagination__info { font-size: var(--text-sm); color: var(--text-muted); }

/* --------------------------------------------------------------------------
   Modal / drawer
   -------------------------------------------------------------------------- */
.modal[hidden] { display: none; }
.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: rgba(11, 12, 14, 0.55);
  backdrop-filter: blur(3px);
  animation: fade-in var(--dur-2) var(--ease-out);
}
.modal__panel {
  width: min(560px, 100%);
  max-height: min(84dvh, 720px);
  overflow-y: auto;
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xl);
  animation: modal-in var(--dur-3) var(--ease-spring);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(14px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@media (max-width: 560px) {
  .modal { align-items: flex-end; padding: 0; }
  .modal__panel {
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    max-height: 90dvh;
    animation: sheet-in var(--dur-3) var(--ease-out);
  }
  @keyframes sheet-in {
    from { transform: translateY(100%); }
    to   { transform: none; }
  }
}

/* Reveal-on-scroll and every other animation live in motion.css. */

/* --------------------------------------------------------------------------
   Misc
   -------------------------------------------------------------------------- */
.divider-label {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  color: var(--text-subtle);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
.divider-label::before,
.divider-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.kv { display: grid; gap: var(--sp-3); }
.kv__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  /* A label and a long value — an email, a full address — must wrap onto two
     lines rather than push the card off a narrow screen. The driver page
     overflowed a 320px viewport by exactly the width its longest email
     overshot. */
  flex-wrap: wrap;
}
.kv__key { font-size: var(--text-sm); color: var(--text-muted); }
.kv__val {
  font-weight: 600;
  color: var(--ink-900);
  text-align: end;
  min-width: 0;
  overflow-wrap: anywhere;
}

.money-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-2) 0;
  font-size: var(--text-sm);
}
.money-row--total {
  margin-top: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--text-md);
  font-weight: 650;
  color: var(--ink-950);
}
.money-row__amount { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --------------------------------------------------------------------------
   Live tracking
   --------------------------------------------------------------------------
   Two audiences, one visual language: the driver sees that sharing is on, the
   customer sees where the car is. The state colour is driven by a data
   attribute so the JavaScript only sets a word, never a style.
   -------------------------------------------------------------------------- */
.tracking__row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.tracking__pulse {
  position: relative;
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: var(--r-full);
  background: var(--success-500);
}
.tracking__pulse::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: var(--r-full);
  border: 2px solid var(--success-500);
  animation: ping 2.2s var(--ease-out) infinite;
}
.tracking__title {
  font-size: var(--text-sm);
  font-weight: 650;
  color: var(--ink-950);
}
.tracking__state {
  font-size: var(--text-xs);
  color: var(--ink-500);
}
.tracking__state[data-state="live"]      { color: var(--success-700); }
.tracking__state[data-state="denied"],
.tracking__state[data-state="blocked"],
.tracking__state[data-state="unsupported"] { color: var(--danger-500); }
.tracking__state[data-state="retrying"]  { color: var(--warning-700); }
.tracking__note {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--ink-100);
  font-size: var(--text-xs);
  line-height: 1.55;
  color: var(--ink-500);
}

/* ---- customer-facing live panel ---- */
.livetrack {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border: 1px solid var(--ink-100);
  border-radius: var(--r-lg);
  background: var(--ink-0);
}
.livetrack__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.livetrack__driver {
  font-size: var(--text-md);
  font-weight: 650;
  color: var(--ink-950);
}
.livetrack__meta {
  font-size: var(--text-xs);
  color: var(--ink-500);
}
.livetrack__figures {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
}
.livetrack__figure {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--ink-25);
}
.livetrack__label {
  font-size: var(--text-xs);
  color: var(--ink-400);
}
.livetrack__value {
  margin-top: 2px;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink-950);
  font-variant-numeric: tabular-nums;
}
.livetrack__foot {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--ink-400);
}
.livetrack--stale .livetrack__foot { color: var(--warning-700); }

/* --------------------------------------------------------------------------
   Star rating
   --------------------------------------------------------------------------
   Real radio inputs under a label treatment: keyboard and screen-reader
   behaviour comes free, and it works with JavaScript off. The stars are laid
   out in reverse (5 first) so a plain CSS sibling selector can light up every
   star to the left of the hovered one.
   -------------------------------------------------------------------------- */
.stars {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: var(--sp-1);
  border: 0;
  padding: 0;
  margin: 0;
}
.stars__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.stars__star {
  display: inline-flex;
  cursor: pointer;
  color: var(--ink-200);
  transition: color 0.15s var(--ease-out), transform 0.15s var(--ease-out);
}
.stars__star:hover,
.stars__star:hover ~ .stars__star,
.stars__input:checked ~ .stars__star,
.stars__input:checked + .stars__star {
  color: var(--warning-500);
}
.stars__star:hover { transform: scale(1.12); }
.stars__input:focus-visible + .stars__star {
  outline: 2px solid var(--surface-brand);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

.stars-static {
  display: inline-flex;
  gap: 2px;
  color: var(--ink-200);
}
.stars-static--on { color: var(--warning-500); }

/* --------------------------------------------------------------------------
   Promo code entry
   --------------------------------------------------------------------------
   Deliberately understated. A loud empty discount box makes every customer
   without a code feel they are overpaying, so it reads as a quiet extra
   rather than a headline.
   -------------------------------------------------------------------------- */
.field--promo {
  margin-top: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--ink-100);
}
.field__optional {
  margin-inline-start: var(--sp-1);
  font-weight: 400;
  color: var(--ink-400);
}
.input--code {
  max-width: 16rem;
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.input--code::placeholder {
  font-family: var(--font-sans);
  letter-spacing: normal;
  text-transform: none;
}

/* Row of small date chips, used by the repeating-bookings list. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.empty__icon {
  display: inline-grid;
  place-items: center;
  width: 60px;
  height: 60px;
  border-radius: var(--r-full);
  background: var(--ink-50);
  color: var(--ink-400);
}

/* --------------------------------------------------------------------------
   Language switch
   --------------------------------------------------------------------------
   Two languages, so it is one button that names the *other* one rather than
   a dropdown — fewer clicks and it states plainly what pressing it does.
   -------------------------------------------------------------------------- */
.lang-switch { display: inline-flex; }
.lang-switch__btn {
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: transparent;
  color: var(--ink-600);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out);
}
.lang-switch__btn:hover {
  border-color: var(--ink-400);
  color: var(--ink-950);
}

/* --------------------------------------------------------------------------
   Booking message thread
   --------------------------------------------------------------------------
   Two-sided, so the reader's own messages sit on the reading edge and the
   other party's on the opposite one. Logical properties throughout, so the
   whole thread mirrors under RTL without a second rule.
   -------------------------------------------------------------------------- */
.thread {
  display: grid;
  gap: var(--sp-3);
  max-height: 22rem;
  overflow-y: auto;
}
.thread__row { display: flex; }
.thread__row--customer { justify-content: flex-start; }
.thread__row--driver,
.thread__row--staff { justify-content: flex-end; }

.msg {
  max-width: 82%;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  background: var(--ink-25);
}
.thread__row--driver .msg { background: var(--brand-50); border-color: var(--brand-100); }
.thread__row--staff .msg { background: var(--ink-50); }

.msg__meta {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: 2px;
  font-size: var(--text-xs);
  color: var(--ink-400);
}
.msg__who { font-weight: 650; color: var(--ink-700); }
.msg__body {
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--ink-900);
  overflow-wrap: anywhere;
}

.msg-compose {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
}
.msg-compose .textarea { flex: 1; resize: vertical; }

/* Delete buttons sit inside table rows and card headers, not on their own line. */
.delete-form { display: inline-flex; margin: 0; }
