:root {
  --bg: #f1f5f9;
  --surface: #ffffff;
  --ink: #0f172a;
  --muted: #64748b;
  --border: #e2e8f0;
  --primary: #2563eb;
  --primary-ink: #ffffff;
  --success: #16a34a;
  --danger: #dc2626;
  --warning: #d97706;
  /* Paleta categórica (Resumen de gastos): validada por CVD (adjacent ΔE 9.1
     light, normal-vision ΔE 19.6). Se asigna por id de categoría, no por
     posición, para que el color sea estable ante cambios de filtro. */
  --series-1: #2a78d6; --series-2: #008300; --series-3: #e87ba4;
  --series-4: #eda100; --series-5: #1baf7a; --series-6: #eb6834; --series-7: #4a3aa7;
  --radius: 14px;
  --shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
  --tabbar-h: 64px;
  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  /* Nada debe generar scroll horizontal de página: si un componente
     se pasa de ancho es un bug de ese componente, no de la página. */
  overflow-x: clip;
}

img { max-width: 100%; }

/* ── Skip link (accesibilidad por teclado) ──────────────────── */
/* Invisible hasta que se enfoca con Tab; z-index por encima de todo
   (appbar 20, tabbar 30, net-status 40, modal 200, toast 250). */
.skip-link {
  position: absolute; top: -48px; left: 8px; z-index: 1000;
  background: var(--primary); color: var(--primary-ink);
  padding: 10px 16px; border-radius: 0 0 8px 8px;
  font-weight: 700; text-decoration: none; transition: top .15s;
}
.skip-link:focus { top: 0; }

/* ── App bar ─────────────────────────────────── */
.appbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: env(safe-area-inset-top, 0px) 16px 0;
  /* min-height (no altura fija): con fuentes grandes el appbar crece en
     lugar de recortar el texto. */
  min-height: calc(52px + env(safe-area-inset-top, 0px));
  /* Fijo (no var(--ink)): en dark --ink es claro y el texto blanco
     del appbar quedaría ilegible. */
  background: #0f172a; color: #fff;
}
.appbar__brand {
  color: #fff; text-decoration: none; font-weight: 700;
  display: inline-flex; align-items: center; gap: 8px;
  min-width: 0; overflow: hidden;  /* deja que el nombre se recorte */
}
/* El logo no escala con la fuente (flex-shrink:0 + tamaño fijo): en la
   captura con fuente grande se veía enorme. */
.appbar__logo { width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0; }
.appbar__user { font-size: .8rem; color: #cbd5e1; flex-shrink: 0; }
.appbar__search { flex: 1 1 auto; min-width: 0; max-width: 180px; }
.appbar__search input {
  width: 100%; padding: 7px 10px; font-size: .85rem;
  border-radius: 999px; border: 1px solid rgba(255,255,255,.25);
  background: rgba(255,255,255,.1); color: #fff;
}
.appbar__search input::placeholder { color: rgba(255,255,255,.6); }
.appbar__search input:focus {
  outline: none; background: #fff; color: var(--ink);
  box-shadow: 0 0 0 3px rgba(37,99,235,.35);
}
/* z-index entre .appbar (20) y .modal (200): por encima del contenido,
   por debajo de cualquier modal que llegue a abrirse. */
.search-results {
  position: absolute; left: 0; right: 0; z-index: 60;
  max-width: 560px; margin: 0 auto; max-height: 60vh; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 0 0 var(--radius) var(--radius); box-shadow: var(--shadow);
  padding: 10px 14px;
}
.search-results[hidden] { display: none; }
.search-results__group { margin-bottom: 12px; }
.search-results__group:last-child { margin-bottom: 0; }
.search-results__group h3 { font-size: .8rem; color: var(--muted); margin: 0 0 6px; }
.search-results__hint { color: var(--muted); text-align: center; padding: 8px 0; margin: 0; }

/* ── Layout ──────────────────────────────────── */
.container {
  max-width: 560px; margin: 0 auto;
  padding: 16px 16px calc(var(--tabbar-h) + var(--safe-b) + 16px);
}
.page-title { font-size: 1.4rem; margin: 4px 0 16px; }
.section { margin-top: 24px; }
.section__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; }
.section__head h2, .section h2 { font-size: 1.05rem; margin: 0 0 10px; }
.section__total { font-weight: 700; color: var(--primary); }
.doc-type-block { margin-top: 22px; }
.doc-type-block:first-child { margin-top: 0; }
.doc-type-block h3 { font-size: 0.95rem; margin: 0 0 8px; }

/* ── Cards & lists ───────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px;
}
.list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
/* min-width:auto de los grid items dejaría que una tarjeta con texto
   largo empuje el ancho de la página (overflow en el celular). */
.list > li { min-width: 0; }
.list--tight { gap: 8px; }
/* El display de .field/.form (flex/grid) le ganaría al [hidden] del
   user-agent: forzamos que hidden siempre oculte. */
[hidden] { display: none !important; }

.empty { color: var(--muted); text-align: center; padding: 24px 0; }
.empty--sm { padding: 12px 0; }

/* ── Stats ───────────────────────────────────── */
.stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
/* min-width:0: sin esto, un monto largo ($ 5.811.788,46) sin puntos de
   corte fuerza el ancho de la celda y desborda la grilla con fuentes
   grandes. overflow-wrap deja que el número se parta si de verdad no entra. */
.stat { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* Algunos .stat son <a> (atajo a la sección correspondiente): sin esto
   se ven como un link roto (azul y subrayado). */
a.stat { text-decoration: none; color: inherit; }
/* Otros .stat son <button> (abren una solapa, ver .js-tab-btn): .card ya
   pone background/border, solo falta resetear el chrome nativo del botón
   (mismo criterio que button.chip/button.link) y que ocupe el ancho de la
   celda del grid, que un <button> no toma por defecto. */
button.stat { font: inherit; text-align: left; cursor: pointer; width: 100%; }
.stat--wide { grid-column: 1 / -1; }
/* clamp: los montos grandes ($ 5.883.400,00) entran en media pantalla
   de celular sin desbordar; en desktop mantiene 1.5rem. */
.stat__value {
  font-size: clamp(1.1rem, 5.2vw, 1.5rem); font-weight: 800;
  overflow-wrap: anywhere;
}
.stat__value--neg { color: var(--danger); }
.stat__label { font-size: .78rem; color: var(--muted); }

/* ── Trip card ───────────────────────────────── */
.trip-card {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 12px;
  padding: 14px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  text-decoration: none; color: inherit;
}
.trip-card:active { transform: scale(.99); }
.trip-card__main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 60%; }
.trip-card__route { font-weight: 600; }
/* La carga puede ser larga: envuelve hacia abajo (la tarjeta tiene
   espacio) en vez de cortarse con elipsis. */
.trip-card__meta { font-size: .78rem; color: var(--muted); overflow-wrap: anywhere; }
/* min-width:0 + sin nowrap/flex-shrink:0: con fuentes grandes el lado
   derecho (montos) se achica y envuelve en vez de empujar la tarjeta más
   ancha que la pantalla (que arrastraba el origen/destino y el botón fuera
   de la vista). */
.trip-card__side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; min-width: 0; flex: 1 1 auto; }
.trip-card__amount { font-weight: 700; text-align: right; overflow-wrap: anywhere; }
.trip-card__amount--billed { color: #15803d; }
.trip-card__km { font-weight: 500; color: var(--muted); }
.trip-card__tag { display: block; font-size: .65rem; font-weight: 500; color: var(--muted); text-align: right; }

/* ── Badges ──────────────────────────────────── */
.badge {
  display: inline-block; font-size: .7rem; font-weight: 700;
  padding: 3px 8px; border-radius: 999px; text-transform: uppercase; letter-spacing: .02em;
}
.badge--pendiente { background: #f1f5f9; color: #475569; }
.badge--en_curso { background: #dbeafe; color: #1d4ed8; }
.badge--finalizado { background: #dcfce7; color: #15803d; }
.badge--cancelado { background: #fee2e2; color: #b91c1c; }
.badge--role { background: #ede9fe; color: #6d28d9; }
.badge--vencida { background: #fee2e2; color: #b91c1c; }
.badge--por_vencer { background: #fef3c7; color: #b45309; }
.badge--vigente { background: #dcfce7; color: #15803d; }
/* Paleta de alertas de vencimiento configurables (/expiry-alert-tipos).
   --vencida/--por_vencer/--vigente quedan como compat (help.html). */
.badge--amarillo { background: #fef3c7; color: #b45309; }
.badge--naranja { background: #ffedd5; color: #c2410c; }
.badge--rojo { background: #fee2e2; color: #b91c1c; }
.badge--verde { background: #dcfce7; color: #15803d; }
.badge--azul { background: #dbeafe; color: #1d4ed8; }
.badge--gris { background: #f3f4f6; color: #374151; }
/* Destello para vencimientos YA vencidos: se notan aunque el badge esté
   en una lista larga. */
.badge--pulse { animation: badge-pulse 1.2s ease-in-out infinite; }
@keyframes badge-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(185, 28, 28, .45); }
  50% { opacity: .55; box-shadow: 0 0 0 4px rgba(185, 28, 28, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .badge--pulse { animation: none; }
}

/* ── Filters / chips ─────────────────────────── */
.filters { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 14px; }
.chip {
  flex: 0 0 auto; padding: 7px 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border);
  text-decoration: none; color: var(--muted); font-size: .85rem; font-weight: 600;
}
.chip--active { background: var(--ink); color: #fff; border-color: var(--ink); }
/* .chip usado sobre <button> (selector de apariencia): resetea el chrome
   nativo del botón, el resto de las reglas de .chip ya cubren color/fondo. */
button.chip { font: inherit; cursor: pointer; }

/* ── Data grid (detail) ──────────────────────── */
.data-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 14px 0; }
.data-grid > div { display: flex; flex-direction: column; }
.data-grid__k { font-size: .72rem; color: var(--muted); text-transform: uppercase; }
.note { margin: 12px 0; color: var(--muted); white-space: pre-wrap; }

/* ── Expenses ────────────────────────────────── */
.expense { display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.expense__icon { font-size: 1.3rem; }
.expense__main { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.expense__type { font-weight: 600; }
.expense__meta { font-size: .75rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Proveedor + factura: mejor dos líneas que un nro de factura cortado. */
.expense__meta--wrap { white-space: normal; }
.expense__amount { font-weight: 700; }
.expense__del { border: none; background: none; color: var(--muted); font-size: 1rem;
  padding: 4px 6px; cursor: pointer; }
.expense-form { margin-top: 12px; }

/* Variante apilada (/expenses): info + monto arriba, estado de pago y
   acciones (editar/pagar/eliminar) en un pie aparte — en el celular no
   entra todo en una sola fila. position:relative + overflow:hidden: base
   para el swipe-to-delete (swipe-delete.js) — el fondo rojo vive detrás,
   recortado por overflow:hidden hasta que la fila se corre con el gesto. */
.expense--stacked {
  flex-direction: column; align-items: stretch; gap: 8px;
  position: relative; overflow: hidden;
}
.expense__swipe-bg {
  position: absolute; inset: 0; z-index: 0;
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: 18px; font-size: 1.2rem;
  background: var(--danger); border-radius: var(--radius);
}
/* El contenido real va por encima del fondo rojo y es lo que se corre
   (swipe-delete.js transforma cada hijo directo por igual). */
.expense--stacked > *:not(.expense__swipe-bg) {
  position: relative; z-index: 1; background: var(--surface);
}
.expense--stacked > *.expense__swipe-back { transition: transform .2s ease-out; }
.expense__row { display: flex; align-items: center; gap: 10px; min-width: 0; }
.expense__row .expense__amount { flex-shrink: 0; }
/* Chips de comprobantes adjuntos del gasto. */
.expense__files { display: flex; flex-wrap: wrap; gap: 6px; }
.expense__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  border-top: 1px solid var(--border); padding-top: 8px;
}
.expense__paystate { font-size: .75rem; color: var(--muted); min-width: 0; }
.expense__actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

/* ── Forms ───────────────────────────────────── */
.form { display: grid; gap: 14px; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* Los inputs de fecha tienen min-width intrínseco grande: sin esto,
   dos por fila desbordan en pantallas angostas. */
.form__row > * { min-width: 0; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field > span { font-size: .8rem; color: var(--muted); font-weight: 600; }
/* Inline variant for checkbox+text rows (e.g. tax lines in billing form) */
.field--inline { flex-direction: row; align-items: center; gap: 8px; }
.field--inline > span { display: flex; align-items: center; gap: 4px; }
.field--inline .tax-rate { width: 64px; padding: 6px 8px; font-size: .9rem; }
input, select, textarea {
  width: 100%; min-width: 0; padding: 12px; font-size: 16px; /* 16px evita zoom en iOS */
  border: 1px solid var(--border); border-radius: 10px; background: #fff; color: var(--ink);
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,.15);
}
/* Foco visible al navegar con teclado (links, botones, tabbar). Los
   inputs ya tienen su propio estilo de foco arriba, sin tocar. */
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.form__actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; }

.hint { font-size: .8rem; color: var(--muted); margin: -2px 0 0; }

/* Agrupador de campos (ej. datos de seguro del vehículo) */
.fieldset {
  border: 1px solid var(--border); border-radius: 12px; padding: 12px;
  display: flex; flex-direction: column; gap: 12px;
}
.fieldset > legend { font-size: .8rem; font-weight: 700; color: var(--muted); padding: 0 6px; }

/* Panel de alertas de vencimiento en el inicio */
.alerts { border-left: 4px solid #f59e0b; }
.alerts__title { font-size: 1rem; margin: 0 0 8px; }
.alerts__item {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 6px 0;
}
.alerts__item a { color: var(--ink); text-decoration: none; min-width: 0; }
.alerts__item .badge { flex-shrink: 0; }
/* Pago pendiente: apilado — info arriba, adjuntos y vencimiento debajo. */
.alerts__item--stack { display: block; }
.alerts__item--stack .alerts__line { display: block; overflow-wrap: anywhere; }
.alerts__files { display: flex; flex-wrap: wrap; gap: 6px; margin: 5px 0 2px; }
.alerts__due {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 3px;
}
.alerts__spent { font-size: .78rem; color: var(--muted); }
/* Cobros por vencer: sublista de facturas dentro de un ítem de cliente. */
.alerts__sub { list-style: none; margin: 4px 0 0; padding-left: 6px; }
.alerts__sub .alerts__line {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: 3px 0; font-size: .86rem;
}
.attach-chip {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  padding: 3px 9px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--ink); font-size: .72rem;
  text-decoration: none; cursor: pointer;
}
.attach-chip:hover { border-color: var(--primary); color: var(--primary); }
.attach-chip__icon { flex-shrink: 0; }
/* El nombre (factura larga) se recorta con elipsis dentro del chip. */
.attach-chip__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Alta rápida de cliente dentro del form de viaje */
.quick-client { margin-top: -2px; }
.quick-client__summary {
  cursor: pointer; font-size: .82rem; color: var(--primary);
  font-weight: 600; padding: 4px 0; list-style: none;
}
.quick-client__summary::-webkit-details-marker { display: none; }
.quick-client__body { margin-top: 8px; display: flex; flex-direction: column; gap: 12px; }
.finish-form { margin-top: 16px; }
.danger-zone { margin-top: 28px; }

/* ── Cobro / facturación ─────────────────────── */
.section__title { font-size: 1.05rem; margin: 0; }
.billing__calc { display: grid; gap: 8px; padding: 12px; margin: 2px 0 4px;
  background: var(--bg); border-radius: 10px; }
.billing__line { display: flex; justify-content: space-between; align-items: baseline; }
.billing__line span { color: var(--muted); font-size: .9rem; }
.billing__line strong { font-weight: 700; }
.billing__line--total strong { color: var(--primary); font-size: 1.3rem; }
.billing__line--muted strong { color: var(--success); }

/* ── Buttons ─────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 12px 18px; border-radius: 10px; border: 1px solid transparent;
  font-size: .95rem; font-weight: 700; cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.btn:active { transform: scale(.98); }
.btn--block { width: 100%; }
.btn--lg { padding: 15px; font-size: 1rem; }
.btn--sm { padding: 8px 12px; font-size: .82rem; }
.btn--primary { background: var(--primary); color: var(--primary-ink); }
.btn--success { background: var(--success); color: #fff; }
.btn--danger { background: #fff; color: var(--danger); border-color: var(--danger); }
.btn--ghost { background: #fff; color: var(--ink); border-color: var(--border); }

/* ── Alerts ──────────────────────────────────── */
.alert { padding: 12px 14px; border-radius: 10px; margin-bottom: 14px; font-weight: 600; font-size: .9rem; }
.alert--error { background: #fee2e2; color: #b91c1c; }
.alert--warn { background: #fef3c7; color: #92400e; }
.alert--ok { background: #dcfce7; color: #15803d; }

/* Reset de contraseña inline (panel de usuarios) */
.pwd-reset { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pwd-reset input { padding: 8px 10px; font-size: 14px; }
.appbar__user { color: #cbd5e1; text-decoration: none; }

/* ── Links ───────────────────────────────────── */
.link { color: var(--primary); text-decoration: none; font-weight: 600; font-size: .9rem; }
/* .link sobre <button> (ej. "Editar" inline de permisos): resetea el
   chrome nativo del botón, el resto de .link ya cubre color/peso. */
button.link { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }
.detail-head { display: flex; justify-content: space-between; margin-bottom: 8px; }

/* ── Solapas (permisos de circulación: Listado / Cargar y editar) ── */
.tabs { display: flex; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.tab-btn {
  flex: 1; padding: 12px; background: none; border: none;
  border-bottom: 2px solid transparent; font: inherit; font-weight: 600;
  font-size: .9rem; color: var(--muted); cursor: pointer;
}
.tab-btn--active { color: var(--ink); border-bottom-color: var(--primary); }
/* Variante para 5+ solapas (ficha de vehículo): con flex:1 (default de
   .tabs) se comprimen demasiado para caber emoji+texto. En vez de eso,
   ancho natural + scroll horizontal (oculto, ver ::-webkit-scrollbar). */
.tabs--scroll { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.tabs--scroll::-webkit-scrollbar { display: none; }
.tabs--scroll .tab-btn { flex: 0 0 auto; padding-left: 14px; padding-right: 14px; }

/* ── Pólizas: acciones por fila (editar inline / borrar) ── */
.policy-row__actions { margin-top: 8px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.policy-edit { align-self: stretch; }
.policy-edit > summary { list-style: none; cursor: pointer; }
.policy-edit > summary::-webkit-details-marker { display: none; }
.policy-edit .form { margin-top: 8px; }

/* ── Auth ────────────────────────────────────── */
.auth { max-width: 380px; margin: 8vh auto 0; text-align: center; padding: 0 8px; }
.auth__logo { font-size: 3rem; }
.auth__logo img { width: 180px; height: 180px; border-radius: 50%; }
.auth__title { margin: 8px 0 2px; }
.auth__subtitle { color: var(--muted); margin: 0 0 22px; }
.auth .form { text-align: left; }

/* ── Users ───────────────────────────────────── */
.user-row { display: flex; flex-direction: column; gap: 8px; }
.user-row__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.user-row__main { display: flex; flex-direction: column; min-width: 0; }
.user-row__name { font-weight: 600; display: flex; align-items: center; gap: 6px; }
.user-row__email { font-size: .8rem; color: var(--muted); }
.user-row__meta { font-size: .8rem; color: var(--muted); margin-top: 2px; }
.user-row__actions { display: flex; align-items: center; gap: 8px; }

/* ── Ordenar por (listados) ──────────────────── */
/* flex-wrap: en listados con 2+ selects (ej. /trips: Cliente + Conductor +
   Ordenar por) no entran en una sola fila en pantallas angostas — sin wrap,
   justify-content: flex-end empuja los primeros campos fuera de la vista
   por la izquierda en vez de bajarlos de línea. */
.sort-bar { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px 12px; }
.section__head--center { align-items: center; }
.sort-bar__field { display: flex; align-items: center; gap: 8px; }
.sort-bar__field > span { font-size: .8rem; color: var(--muted); font-weight: 600; }
.sort-bar select { width: auto; padding: 8px 10px; font-size: 14px; }

/* Barra de filtros de PÁGINA en /expenses (Período + Categorías): a diferencia
   del "Ordenar por" (que se alinea a la derecha con .sort-bar), estos van en
   columna y a la IZQUIERDA, y el rango Desde/Hasta cae justo debajo de Período.
   Reusa .sort-bar__field para cada fila; no lleva la clase .sort-bar a propósito
   (así "sort-bar" sigue identificando solo la barra de orden del Listado). */
.filters { display: flex; flex-direction: column; align-items: flex-start; gap: 10px 12px; margin-bottom: 16px; }
.filters select { width: auto; padding: 8px 10px; font-size: 14px; }
.filters__range { display: flex; flex-wrap: wrap; gap: 10px 12px; }

/* ── Buscador ────────────────────────────────── */
.search { display: flex; gap: 8px; margin-bottom: 14px; }
.search input { flex: 1; }

/* ── Tab bar ─────────────────────────────────── */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex; justify-content: space-around; align-items: stretch;
  /* min-height: con fuentes grandes crece hacia arriba en vez de recortar
     los íconos/etiquetas. */
  min-height: calc(var(--tabbar-h) + var(--safe-b)); padding-bottom: var(--safe-b);
  background: var(--surface); border-top: 1px solid var(--border);
}
.tabbar__item, .tabbar__btn, .tabbar__submenu > summary {
  /* flex-basis 0 + min-width 0: los 8 ítems se reparten el ancho en
     partes iguales y SIEMPRE entran (la etiqueta se corta con …). */
  flex: 1 1 0; min-width: 0; padding: 0 2px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; font-size: .66rem; color: var(--muted); text-decoration: none;
  background: none; border: none; cursor: pointer; font-family: inherit;
}
.tabbar__item > span:last-child, .tabbar__btn > span:last-child,
.tabbar__submenu > summary > span:last-child {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tabbar__icon { font-size: 1.25rem; }
.tabbar__item--cta { color: var(--primary); }
.tabbar__logout { padding: 0; }
.tabbar__logout .tabbar__btn { width: 100%; height: 100%; }

/* Submenú de administración en la tabbar (details nativo, sin JS): los
   ítems de gestión (Usuarios / Backups / Alertas de vencimiento) se
   agrupan detrás de "Admin" y despliegan hacia ARRIBA, sobre el contenido. */
.tabbar__submenu { position: relative; display: flex; flex: 1 1 0; min-width: 0; }
.tabbar__submenu > summary::-webkit-details-marker { display: none; }
.tabbar__submenu-panel {
  position: absolute; bottom: calc(100% + 10px); right: 8px;
  width: min(280px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  padding: 6px; display: flex; flex-direction: column; gap: 2px; z-index: 40;
}
.tabbar__submenu-link {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px;
  border-radius: 8px; color: var(--muted); text-decoration: none;
  font-size: .9rem;
}
.tabbar__submenu-link:hover, .tabbar__submenu-link:active {
  background: var(--border);
}

/* ── Estado de conexión / offline ────────────── */
.net-status {
  position: sticky; top: 0; z-index: 40;
  background: var(--warning); color: #fff;
  text-align: center; font-size: .82rem; font-weight: 600;
  padding: 7px 12px;
}
.expense--pending { opacity: .85; border-style: dashed; }
.expense--pending .expense__type small { color: var(--warning); font-weight: 700; }

/* ── Error page ──────────────────────────────── */
.error-page { text-align: center; padding: 12vh 0; }
.error-page__code { font-size: 3rem; margin: 0; }
.error-page__msg { color: var(--muted); margin: 8px 0 24px; }

/* ── Pantallas grandes (notebook / PC) ───────── */
@media (min-width: 768px) {
  .container { max-width: 760px; }
  .stats { grid-template-columns: repeat(3, 1fr); }
  /* La barra inferior no se estira de borde a borde: ítems centrados. */
  .tabbar { justify-content: center; }
  .tabbar > .tabbar__item, .tabbar > .tabbar__logout,
  .tabbar > .tabbar__submenu { flex: 0 1 104px; }
}

/* Modo oscuro: sigue el SO por defecto (@media), pero el toggle manual de
   "Mi cuenta" (theme.js/theme-toggle.js) puede forzarlo con
   :root[data-theme="dark"|"light"], que le gana al SO en cualquier
   dirección (:not([data-theme="light"]) evita que el bloque del SO se
   aplique si el usuario forzó "claro" con el SO en oscuro). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b1220; --surface: #131c2e; --ink: #e8eef7; --muted: #94a3b8;
    --border: #243049;
    /* Paleta categórica en dark (adjacent ΔE 8.4, normal-vision ΔE 19.3). */
    --series-1: #3987e5; --series-2: #008300; --series-3: #d55181;
    --series-4: #c98500; --series-5: #199e70; --series-6: #d95926; --series-7: #9085e9;
  }
  :root:not([data-theme="light"]) input,
  :root:not([data-theme="light"]) select,
  :root:not([data-theme="light"]) textarea { background: #0f1828; color: var(--ink); }
  :root:not([data-theme="light"]) .btn--ghost,
  :root:not([data-theme="light"]) .btn--danger { background: #131c2e; }
  /* --ink es claro en dark: el chip activo lleva texto oscuro. */
  :root:not([data-theme="light"]) .chip--active { color: #0b1220; }
}

:root[data-theme="dark"] {
  --bg: #0b1220; --surface: #131c2e; --ink: #e8eef7; --muted: #94a3b8;
  --border: #243049;
  --series-1: #3987e5; --series-2: #008300; --series-3: #d55181;
  --series-4: #c98500; --series-5: #199e70; --series-6: #d95926; --series-7: #9085e9;
}
:root[data-theme="dark"] input,
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea { background: #0f1828; color: var(--ink); }
:root[data-theme="dark"] .btn--ghost,
:root[data-theme="dark"] .btn--danger { background: #131c2e; }
:root[data-theme="dark"] .chip--active { color: #0b1220; }

:root[data-theme="light"] {
  --bg: #f1f5f9; --surface: #ffffff; --ink: #0f172a; --muted: #64748b;
  --border: #e2e8f0;
}

/* ── Adjuntos (imágenes / PDF de gastos, viajes, vehículos, usuarios) ── */
.attachments__title { font-size: 1rem; margin-bottom: 10px; }
.attach-list {
  list-style: none; margin: 0 0 14px; padding: 0;
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.attach-item {
  position: relative; min-width: 0; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.attach-item__link {
  display: flex; flex-direction: column; min-width: 0;
  text-decoration: none; color: var(--ink);
}
.attach-item__thumb {
  width: 100%; height: 110px; display: block;
  object-fit: cover; background: var(--bg);
}
.attach-item__thumb--file {
  display: flex; align-items: center; justify-content: center; font-size: 2.4rem;
}
.attach-item__info {
  display: flex; flex-direction: column; min-width: 0; padding: 6px 8px;
}
.attach-item__name {
  font-size: .78rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.attach-item__size { font-size: .7rem; color: var(--muted); }
.attach-item__del { position: absolute; top: 4px; right: 4px; margin: 0; }
.attach-item__del .btn {
  width: 26px; height: 26px; padding: 0; line-height: 1;
  border: none; border-radius: 999px;
  background: rgba(15, 23, 42, .6); color: #fff;
}
.attach-item--pending { opacity: .6; }
.attach-list__empty, .attach-list__error, .attach-item--more { grid-column: 1 / -1; }
.attach-form { margin-top: 6px; }
.attach-form__field input[type="file"] { padding: 8px 0; font-size: .9rem; }
/* Checkbox "Factura" en los PDF del viaje (invoice.js → /attachments/{id}/invoice-flag) */
.attach-item__invoice {
  display: flex; align-items: center; gap: 5px;
  padding: 4px 8px 6px; font-size: .72rem; color: var(--muted);
  cursor: pointer; user-select: none;
}
.attach-item__invoice input { margin: 0; accent-color: var(--accent, #2563eb); }

/* ── Factura por mail: historial de envíos (detalle del viaje) ── */
.invoice-history { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.invoice-history__item { display: flex; align-items: flex-start; gap: 8px; }
.invoice-history__item .badge { flex-shrink: 0; }
.invoice-history__main { display: flex; flex-direction: column; min-width: 0; }
.invoice-history__to { font-size: .85rem; overflow-wrap: anywhere; }
.invoice-history__when { font-size: .75rem; color: var(--muted); }
.invoice-history__error { font-size: .75rem; color: #b91c1c; overflow-wrap: anywhere; }

/* ── Modal / visor de adjuntos ───────────────────────────────── */
.modal[hidden] { display: none; }
.modal {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.modal__backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .6); }
.modal__dialog {
  position: relative; z-index: 1; width: 100%; max-width: 900px; max-height: 90vh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface); border-radius: var(--radius);
  box-shadow: 0 12px 44px rgba(0, 0, 0, .45);
}
.modal__head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--border);
}
.modal__title {
  flex: 1 1 0; min-width: 0; font-weight: 600; font-size: .9rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.modal__open { font-size: .85rem; flex-shrink: 0; }
.modal__close {
  flex-shrink: 0; border: none; background: none; cursor: pointer;
  font-size: 1.1rem; color: var(--muted); padding: 4px 8px;
}
.modal__body {
  flex: 1 1 auto; min-height: 0; overflow: auto; background: var(--bg);
  display: flex; align-items: center; justify-content: center;
}
.modal__img { max-width: 100%; max-height: 82vh; display: block; }
body.modal-open { overflow: hidden; }

/* Variante chica (confirmación): sin la caja de imagen a pantalla ancha
   del visor de adjuntos, texto alineado a la izquierda con padding, y
   un pie con los botones Cancelar/Confirmar. */
.modal__dialog--sm { max-width: 380px; }
.modal__body--text {
  display: block; text-align: left; padding: 16px; background: var(--surface);
}
.modal__body--text p { margin: 0; line-height: 1.5; }
.modal__foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 10px 12px; border-top: 1px solid var(--border);
}

/* ── Toasts ──────────────────────────────────────────────────────── */
/* z-index 250: por encima del modal de adjuntos (200) y de la tabbar (30). */
.toast-container {
  position: fixed; z-index: 250;
  left: 0; right: 0; bottom: calc(var(--tabbar-h) + var(--safe-b) + 12px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 0 16px; pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: 10px;
  max-width: 420px; width: 100%;
  background: var(--surface); color: var(--ink);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 12px 14px; font-size: .9rem; font-weight: 600;
  animation: toast-in .18s ease-out;
}
.toast--out { animation: toast-out .18s ease-in forwards; }
.toast--success { border-left: 4px solid var(--success); }
.toast--error { border-left: 4px solid var(--danger); }
.toast--warn { border-left: 4px solid var(--warning); }
.toast__msg { flex: 1 1 auto; min-width: 0; }
.toast__undo {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  color: var(--primary); font-weight: 700; font-size: .85rem; padding: 4px;
}
.toast__close {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 1rem; padding: 4px;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes toast-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(8px); }
}
@media (min-width: 768px) {
  .toast-container { left: auto; right: 24px; align-items: flex-end; bottom: 24px; }
}

/* ── Ayuda (/ayuda): flujo de trabajo + FAQ ──────────────────────── */
/* margin-left:auto agrupa el ❓ con el usuario a la derecha (el appbar
   es space-between y sin esto quedaría flotando en el medio). */
.appbar__help {
  margin-left: auto; flex-shrink: 0; text-decoration: none;
  font-size: .95rem; padding: 4px 2px;
}
.help-flow__list { margin: 0; padding-left: 20px; display: grid; gap: 12px; }
.help-flow__list li { line-height: 1.45; }
.faq { display: grid; gap: 0; padding: 4px 14px; }
.faq__group { font-size: .9rem; color: var(--muted); margin: 18px 0 8px; }
.faq__item { border-bottom: 1px solid var(--border); }
.faq__item:last-child { border-bottom: none; }
.faq__item summary {
  cursor: pointer; font-weight: 600; padding: 12px 0;
  list-style: none; position: relative; padding-right: 22px;
}
.faq__item summary::-webkit-details-marker { display: none; }
/* Flecha propia (el marker nativo se ve distinto en cada navegador). */
.faq__item summary::after {
  content: "▾"; position: absolute; right: 2px; color: var(--muted);
  transition: transform .15s;
}
.faq__item[open] summary::after { transform: rotate(180deg); }
.faq__item p { margin: 0 0 12px; line-height: 1.5; }
.faq__item .badge { margin-right: 2px; }

/* --- Passkeys (ingreso con huella / cara) --- */
.passkey-login { margin-top: 10px; }
.passkey-offer { border-left: 4px solid var(--primary, #2563eb); }
.passkey-offer__text { margin: 0 0 10px; line-height: 1.5; }
.passkey-item {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px;
}
.passkey-item .hint { display: block; font-weight: 400; }
.passkey-item__del { margin: 0; }

/* ── Resumen de gastos: desglose por categoría ─────────────────────────── */
.cat-row + .cat-row { margin-top: 16px; }
.cat-row__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.cat-row__label { font-weight: 600; font-size: .92rem; min-width: 0; overflow-wrap: anywhere; }
.cat-row__amount { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cat-row__track { height: 10px; border-radius: 5px; background: var(--bg); overflow: hidden; border: 1px solid var(--border); }
.cat-row__fill { height: 100%; border-radius: 5px; }
.cat-row__foot { display: flex; justify-content: space-between; margin-top: 5px; font-size: .74rem; color: var(--muted); }
.cat-row__foot strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.insight { margin-top: 16px; padding-top: 14px; border-top: 1px dashed var(--border); font-size: .84rem; color: var(--muted); }
.insight strong { color: var(--ink); }

/* ── Combobox multiselección de categorías (progressive enhancement de un
   <select multiple>; lo monta expense_summary.js) ─────────────────────── */
.msel { position: relative; }
.msel__control {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); padding: 0 8px; min-width: 200px;
}
.msel__input {
  flex: 1; min-width: 0; border: none; background: transparent;
  padding: 8px 2px; font-size: 14px; color: var(--ink); outline: none;
}
.msel__clear {
  border: none; background: transparent; cursor: pointer; padding: 4px;
  color: var(--muted); font-size: 15px; line-height: 1; border-radius: 6px;
}
.msel__clear:hover { color: var(--ink); background: var(--bg); }
.msel__panel {
  position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; right: 0;
  max-height: 260px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 6px;
}
.msel__option {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 14px;
}
.msel__option:hover { background: var(--bg); }
.msel__option input { margin: 0; }
.msel__empty { padding: 10px; color: var(--muted); font-size: 13px; text-align: center; }
