:root {
  --text: #6b6375;
  --text-h: #08060d;
  --bg: #fff;
  --border: #e5e4e7;
  --code-bg: #f4f3ec;
  --accent: #aa3bff;
  --accent-bg: rgba(170, 59, 255, 0.1);
  --accent-border: rgba(170, 59, 255, 0.5);
  --social-bg: rgba(244, 243, 236, 0.5);
  --shadow:
    rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;

  --sans: system-ui, 'Segoe UI', Roboto, sans-serif;
  --heading: system-ui, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, Consolas, monospace;

  font: 18px/145% var(--sans);
  letter-spacing: 0.18px;
  color-scheme: light dark;
  color: var(--text);
  background: var(--bg);
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  @media (max-width: 1024px) {
    font-size: 16px;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #9ca3af;
    --text-h: #f3f4f6;
    --bg: #16171d;
    --border: #2e303a;
    --code-bg: #1f2028;
    --accent: #c084fc;
    --accent-bg: rgba(192, 132, 252, 0.15);
    --accent-border: rgba(192, 132, 252, 0.5);
    --social-bg: rgba(47, 48, 58, 0.5);
    --shadow:
      rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
  }

  #social .button-icon {
    filter: invert(1) brightness(2);
  }
}

#root {
  /* Ancho fijo original del template de Vite (1126px) sacado a propósito:
     con una tabla tan ancha, ese límite hacía que el contenido se desbordara
     hacia la derecha y la página quedara con scroll horizontal global, dando
     la sensación de un margen "sobrante" a la izquierda. Ver docs/07-Frontend.md. */
  width: 100%;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}

body {
  margin: 0;
}

h1,
h2 {
  font-family: var(--heading);
  font-weight: 500;
  color: var(--text-h);
}

h1 {
  font-size: 56px;
  letter-spacing: -1.68px;
  margin: 32px 0;
  @media (max-width: 1024px) {
    font-size: 36px;
    margin: 20px 0;
  }
}
h2 {
  font-size: 24px;
  line-height: 118%;
  letter-spacing: -0.24px;
  margin: 0 0 8px;
  @media (max-width: 1024px) {
    font-size: 20px;
  }
}
p {
  margin: 0;
}

code,
.counter {
  font-family: var(--mono);
  display: inline-flex;
  border-radius: 4px;
  color: var(--text-h);
}

code {
  font-size: 15px;
  line-height: 135%;
  padding: 4px 8px;
  background: var(--code-bg);
}
.app {
  /* #root es flex (ver index.css). `width: 100%` explícito (en vez de
     dejar que `width:auto` se resuelva vía stretch) es necesario para que
     `.app` respete el ancho del viewport en vez de crecer al ancho mínimo
     de su contenido (la tabla ancha) — sin esto, toda la página quedaba
     más ancha que la pantalla y cualquier cosa pegada al borde derecho
     (ej. el botón de logout de Nav) terminaba fuera de la vista en
     ventanas angostas. `box-sizing: border-box` para que el padding no
     empuje ese 100% más allá del viewport. Encontrado probando el login
     en navegador, 2026-08-11 — era el "zoom de tabla acotado" que había
     quedado pendiente, ver docs/07-Frontend.md. */
  width: 100%;
  max-width: 1600px;
  box-sizing: border-box;
  margin: 0 auto;
  padding: 1.5rem;
  padding-bottom: 2.5rem; /* deja aire para que la barra fija de abajo no tape la última fila */
  font-family: system-ui, sans-serif;
  text-align: left;
}

.filters {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.filters input,
.filters select {
  padding: 0.4rem 0.6rem;
}

/* La tabla puede ser más ancha que la pantalla (muchas columnas de servicios);
   este wrapper contiene el scroll horizontal acá adentro en vez de dejar que
   toda la página se desborde (lo que rompía el centrado, ver index.css). El
   scrollbar nativo de este contenedor queda oculto (sigue funcionando el
   scroll con touch/trackpad) porque el control visible es `.sticky-scrollbar`,
   fijo abajo del viewport — ver docs/cambios_frontend.md. */
.table-scroll {
  width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.table-scroll::-webkit-scrollbar {
  display: none;
}

/* Barra de scroll horizontal fija al fondo del viewport, sincronizada por JS
   con el scroll real de `.table-scroll` (App.tsx). Existe para que se pueda
   arrastrar el scroll de la tabla viendo la primera fila, sin tener que bajar
   hasta el final de la tabla para encontrar el scrollbar.
   `left`/`width` se fijan por JS (recalcStickyBar en App.tsx) para que calcen
   exactamente con `.table-scroll`, no con todo el viewport — si no, al ser
   `.app` más angosto que la pantalla en monitores grandes, esta barra tendría
   más recorrido propio que la tabla y el scroll sincronizado se desfasaría
   cerca del final. */
.sticky-scrollbar {
  position: fixed;
  bottom: 0;
  height: 16px;
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--code-bg, #1f2028);
  border-top: 1px solid var(--border, #2e303a);
  z-index: 500;
}

.sticky-scrollbar.is-hidden {
  display: none;
}

.sticky-scrollbar-spacer {
  height: 1px;
}

.sticky-scrollbar::-webkit-scrollbar {
  height: 14px;
}

.sticky-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}

.sticky-scrollbar::-webkit-scrollbar-thumb {
  background: var(--border, #2e303a);
  border-radius: 8px;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 1rem;
  font-size: 0.85rem;
}

th,
td {
  border: 1px solid #ddd;
  padding: 0.35rem 0.5rem;
  text-align: left;
  white-space: nowrap;
}

th {
  background: #f3f3f3;
  text-align: center;
}

tr.row-clickable {
  cursor: pointer;
}

tr.row-clickable:hover {
  background: rgba(192, 132, 252, 0.1);
}

.text-danger {
  color: #ff6b6b;
  font-weight: 600;
}

.error {
  color: #b00020;
}

td.vencido {
  background: #b00020;
  color: #fff;
  font-weight: bold;
  text-align: center;
}

/* Widget de estado del daemon */
.daemon-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
  background: var(--code-bg, #1f2028);
  border: 1px solid var(--border, #2e303a);
  border-radius: 8px;
  padding: 0.6rem 1rem;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
}

.daemon-status button {
  padding: 0.35rem 0.9rem;
  cursor: pointer;
}

/* Notificación de comprobantes pendientes (ver docs/10-Modulo-Comprobantes.md,
   "Panel de revisión" — mismo patrón de polling que .daemon-status, pero
   como botón: clickearla abre ReceiptsReviewModal). Solo se renderiza cuando
   hay al menos un pendiente (ver ReceiptsNotification.tsx). */
.receipts-notification {
  display: block;
  width: 100%;
  text-align: left;
  background: #7c2d12;
  color: #fed7aa;
  border: 1px solid #9a3412;
  border-radius: 8px;
  padding: 0.6rem 1rem;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}

/* Panel de revisión de comprobantes (ReceiptsReviewModal.tsx). Reusa por
   completo el shell de modal de PropertyModal (useModalShell.ts) — acá solo
   se agrega el layout propio: header con contador de la cola, tabs
   (visibles solo en mobile, ver el media query de más abajo), dos paneles
   (comprobante / formulario) y acciones fijas abajo. */
.modal-content.receipts-review {
  width: min(96vw, 1300px);
  max-width: 100%;
  /* A diferencia de PropertyModal (que solo crece con el contenido), acá
     interesa que el visor de comprobante ocupe todo el alto disponible del
     modal en vez de una altura fija en `vh` (eso hacía que en mobile, donde
     el modal es pantalla completa, el visor quedara mucho más chico que el
     espacio real disponible — ver docs/10-Modulo-Comprobantes.md). Con
     `display: flex; flex-direction: column`, `.receipts-review-body` (más
     abajo, `flex: 1 1 auto`) reparte el alto real que le queda el modal
     (acotado por `max-height: 90vh` de `.modal-content` en desktop, o
     `height: 100%` en mobile) entre header/tabs/body/acciones. */
  display: flex;
  flex-direction: column;
}

.receipts-review-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.receipts-review-header h3 {
  margin: 0;
}

.receipts-queue-info {
  font-size: 0.85rem;
  opacity: 0.75;
  white-space: nowrap;
}

/* Pestañas "Comprobante"/"Datos" — solo tienen sentido en mobile (una
   columna a la vez); en desktop quedan ocultas por completo y las dos
   columnas de .receipts-review-body se muestran siempre juntas. */
.receipts-tabs {
  display: none;
}

.receipts-review-body {
  display: flex;
  gap: 1rem;
  align-items: stretch;
  /* Crece para llenar el alto que le sobra a `.modal-content` (flex column,
     ver arriba) — `min-height: 0` es necesario para que un hijo flex pueda
     encogerse por debajo de su contenido en vez de forzar overflow (el gotcha
     clásico de flexbox: sin esto, el alto real terminaba gobernado por el
     contenido/flex-basis en vez de por el espacio disponible). */
  flex: 1 1 auto;
  min-height: 0;
}

.receipts-review-viewer {
  flex: 1 1 60%;
  min-width: 0;
  min-height: 320px;
  background: #fff;
  border: 1px solid var(--border, #2e303a);
  border-radius: 6px;
  overflow: hidden;
}

.receipts-review-viewer iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}

.receipts-review-form {
  flex: 1 1 40%;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.receipts-review-form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.receipts-review-form input,
.receipts-review-form select {
  font-weight: normal;
  padding: 0.4rem 0.6rem;
}

.receipts-extra {
  margin: 0.5rem 0 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 1rem;
  font-size: 0.85rem;
}

.receipts-extra > div {
  display: contents;
}

.receipts-extra dt {
  font-weight: 600;
  opacity: 0.8;
}

.receipts-extra dd {
  margin: 0;
}

.receipts-review-actions {
  position: sticky;
  bottom: 0;
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border, #2e303a);
  background: var(--bg, #16171d);
}

.receipts-review-actions button {
  padding: 0.5rem 1.1rem;
  cursor: pointer;
}

.receipts-review-actions .btn-primary {
  background: #15803d;
  color: #fff;
  border: 1px solid #166534;
  border-radius: 4px;
}

.receipts-review-actions .btn-primary:disabled,
.receipts-review-actions button:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Modal de detalle (`PropertyModal.tsx`).
   Se probaron, en orden, `position: fixed` (varias variantes),
   `createPortal` a `<body>` con `fixed`, y `<dialog>` + `.showModal()`
   (top layer) — los tres fallaron en la práctica (confirmado por el
   usuario en celular real, no solo en devtools), con el mismo síntoma:
   el modal aparece en un punto fijo del documento, no del viewport visible.
   Causa: los tres dependen de que el navegador resuelva el "containing
   block" contra el viewport real, y cualquier ancestro con
   filter/transform/contain — incluido <html>/<body>, fuera de nuestro
   control — puede romper eso, incluso (en la práctica, pese a la
   especificación) para el top layer de `<dialog>`. Ver docs/07-Frontend.md.

   Solución actual: `.modal-overlay` se posiciona con `position: absolute`
   pero con `top`/`left`/`width`/`height` calculados a mano en JS
   (`PropertyModal.tsx`, `scrollX`/`scrollY`/`innerWidth`/`innerHeight`) en
   vez de dejar que el navegador los resuelva — así el resultado es
   correcto sin importar qué ancestro haya terminado siendo el containing
   block, porque el origen (0,0) de ese containing block es siempre el
   borde superior-izquierdo del documento, igual que `scrollX`/`scrollY`. */
.modal-overlay {
  position: absolute;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  overflow-y: auto;
  overflow-x: hidden; /* nunca scroll horizontal, ni siquiera si algo se desborda */
}

.modal-content {
  position: relative; /* para que .modal-close se ancle a la tarjeta, no al overlay */
  /* Sin esto, el padding y el borde se suman por fuera de `width` (modelo
     content-box, el default de CSS) — en pantallas angostas eso podía
     empujar el modal más ancho que el viewport. */
  box-sizing: border-box;
  background: var(--bg, #16171d);
  color: var(--text, #9ca3af);
  border: 1px solid var(--border, #2e303a);
  border-radius: 8px;
  width: min(92vw, 32rem); /* equivalente aprox. a max-w-lg */
  /* Tope incondicional (no solo en el media query de mobile más abajo): el
     modal nunca puede ser más ancho que `.modal-overlay`, que a su vez está
     calculado en JS al ancho real de la pantalla (`PropertyModal.tsx`) — así
     no depende de que el breakpoint de mobile matchee para no desbordar. */
  max-width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  padding: 1.5rem;
}

.modal-close {
  position: absolute;
  top: 0.5rem;
  right: 0.75rem;
  background: none;
  border: none;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: inherit;
}

.modal-header h3 {
  margin: 0 0 0.5rem;
}

.modal-header dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 1rem;
  margin: 0.5rem 0 1rem;
}

.modal-header dl > div {
  display: contents;
}

.modal-header dt {
  font-weight: 600;
  opacity: 0.8;
}

.modal-header dd {
  margin: 0;
}

.modal-services {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.modal-service {
  border: 1px solid var(--border, #2e303a);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
}

.modal-service.overdue {
  border-color: #b00020;
}

.modal-service-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.badge-overdue {
  background: #b00020;
  color: #fff;
  border-radius: 4px;
  padding: 0.1rem 0.5rem;
  font-size: 0.75rem;
  font-weight: bold;
}

.modal-service-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  font-size: 0.85rem;
}

/* A pedido explícito (2026-07-25): en celular el modal deja de ser una
   tarjeta centrada y pasa a ocupar toda la pantalla del celular. Esto es
   deliberado, no solo estético: mientras se investigaba por qué el modal
   seguía sin centrarse en celular real incluso ya con `<dialog>` (que debería
   ser inmune a esa clase de bug), no se pudo aislar la causa exacta — pero
   un modal a pantalla completa no tiene "centrado" que se pueda ver mal, así
   que el bug deja de ser visible sea cual sea la causa real.
   El corte "es celular" se hace por dos condiciones (una para portrait, otra
   para landscape) porque un solo `max-width` no alcanza: un celular acostado
   tiene un ancho grande (puede pasar de 768px en modelos grandes) pero una
   altura chica, así que también se entra por `max-height`. */
@media (max-width: 768px), (max-height: 768px) and (orientation: landscape) {
  .modal-content {
    /* 100%/100% del `.modal-overlay` (ya calculado en JS al tamaño exacto
       del viewport real), no `100vw`/`100dvh` de nuevo — evita depender
       otra vez de que el navegador resuelva unidades de viewport contra el
       ancestro correcto. */
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    border: none;
    border-radius: 0;
    padding: 1rem;
    /* Letra más grande que en desktop: a pedido explícito del usuario, para
       poder leer el modal en celular sin necesidad de hacer zoom (a
       diferencia de la tabla, que sigue chica — ver docs/07-Frontend.md). */
    font-size: 1.1rem;
    /* Scroll vertical sí (ya lo permite `overflow-y: auto` de la regla base),
       horizontal no — a pedido explícito del usuario. */
    overflow-x: hidden;
  }

  .modal-header dl {
    grid-template-columns: 1fr;
  }

  .modal-header dt {
    margin-top: 0.35rem;
  }

  /* Estos dos usan `rem` (relativo a la raíz del documento, no al `.modal-content`
     de arriba), así que el `font-size` de `.modal-content` no los agranda solo
     por herencia — hay que subirlos acá a mano. */
  .modal-service-fields {
    font-size: 1rem;
  }

  .badge-overdue {
    font-size: 0.9rem;
  }

  /* La tabla sigue necesitando zoom en celular para verse completa (son
     muchas columnas, y `white-space: nowrap` en las celdas es intencional —
     ver docs/cambios_frontend.md, la barra de scroll fija de abajo depende
     de eso) — a pedido del usuario no se rediseña, pero un poco más de
     letra ayuda a que sea legible sin tener que zoomear tanto. */
  table {
    font-size: 0.95rem;
  }

  /* Panel de revisión de comprobantes (ver docs/10-Modulo-Comprobantes.md,
     "Panel de revisión", sección Mobile): dos columnas lado a lado no entran
     legibles en una pantalla de celular, así que acá se muestran las
     pestañas "Comprobante"/"Datos" (ocultas en desktop) y una sola columna
     a la vez, con Confirmar/Descartar siempre visibles abajo (sticky, ya
     aplicado sin cambios en la regla base de `.receipts-review-actions`). */
  .receipts-tabs {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
  }

  .receipts-tabs button {
    flex: 1;
    padding: 0.5rem;
    cursor: pointer;
    border: 1px solid var(--border, #2e303a);
    border-radius: 6px;
    background: transparent;
    color: inherit;
    font-weight: 600;
  }

  .receipts-tabs button.active {
    background: var(--code-bg, #1f2028);
    border-color: #7c3aed;
  }

  /* Una sola columna a la vez (la otra queda `display: none` vía
     `.hide-on-mobile`) — como el hijo oculto no ocupa lugar, el visible
     puede quedarse con `flex: 1 1 auto` y llenar todo el alto real que le
     sobra a `.receipts-review-body` (ver comentario en la regla base de
     `.modal-content.receipts-review` sobre por qué esto reemplaza a la
     altura fija en `vh` que se usaba antes — con esa versión el visor de
     comprobante quedaba mucho más chico que el modal en la práctica). */
  .receipts-review-body {
    flex-direction: column;
  }

  .receipts-review-viewer,
  .receipts-review-form {
    flex: 1 1 auto;
    min-height: 0;
  }

  .hide-on-mobile {
    display: none;
  }
}

/* Usuario logueado + logout (ver docs/09-Autenticacion.md) — línea chica
   debajo del `<h1>`, separada de `.nav-bar`. Antes vivía adentro de la
   fila de pestañas de módulos (`.nav-user` ahí mismo) pero en pantalla
   angosta de celular el email + botón de logout (ambos `nowrap`) le
   dejaban muy poco lugar a las pestañas, apretándolas — reportado por el
   usuario probando en su celular, 2026-08-11. */
.user-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}

.user-bar-email {
  font-size: 0.85rem;
  color: var(--text, #9ca3af);
  opacity: 0.8;
}

.user-bar-logout {
  background: transparent;
  border: 1px solid var(--border, #2e303a);
  border-radius: 4px;
  padding: 0.3rem 0.7rem;
  font-size: 0.85rem;
  color: inherit;
  cursor: pointer;
}

/* Navegación entre módulos (ver docs/07-Frontend.md, "Navegación entre
   módulos") — pestañas horizontales, scrolleables si no entran en pantalla
   angosta (mismo principio que `.table-scroll`), no sidebar. */
.nav-bar {
  display: flex;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--border, #2e303a);
}

.nav-tabs {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  flex: 1 1 auto;
  min-width: 0;
}

.nav-tabs button {
  padding: 0.6rem 1.25rem;
  background: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  color: inherit;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.nav-tabs button.active {
  border-bottom-color: #7c3aed;
}

/* Pantalla de login (ver docs/09-Autenticacion.md) — sin pantalla de
   registro, así que es la única puerta de entrada al sistema. */
.login-page {
  min-height: 80vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: min(90vw, 22rem);
  padding: 2rem;
  background: var(--bg, #16171d);
  border: 1px solid var(--border, #2e303a);
  border-radius: 8px;
}

.login-card h1 {
  font-size: 1.1rem;
  margin: 0 0 0.5rem;
  text-align: center;
}

.login-card label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
}

.login-card input {
  padding: 0.5rem 0.6rem;
}

.login-card button {
  margin-top: 0.5rem;
  padding: 0.6rem;
}

/* Botón de acción principal, genérico (antes solo existía acotado a
   `.receipts-review-actions` — el módulo de Transporte lo reusa en varios
   modales nuevos). */
.btn-primary {
  background: #15803d;
  color: #fff;
  border: 1px solid #166534;
  border-radius: 4px;
}

.btn-primary:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Botón de acción destructiva/de baja (Dar de baja, Cancelar viaje). */
.btn-danger {
  background: #b00020;
  color: #fff;
  border: 1px solid #7f0017;
  border-radius: 4px;
}

.btn-danger:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Módulo de Transporte (ver docs/11-Modulo-Transporte.md). Formulario de
   viaje (TripFormModal.tsx) y calculador de ganancia (TripEstimateModal.tsx)
   comparten este layout de fieldsets — mismo estilo de label/input ya usado
   en `.receipts-review-form`. */
.trip-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.trip-form fieldset {
  border: 1px solid var(--border, #2e303a);
  border-radius: 6px;
  padding: 0.75rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.trip-form legend {
  font-weight: 600;
  padding: 0 0.4rem;
}

.trip-form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.trip-form label.checkbox-label {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}

.trip-form input,
.trip-form select {
  font-weight: normal;
  padding: 0.4rem 0.6rem;
}

/* En pantallas más anchas, cada fieldset pasa a dos columnas — en mobile
   (regla base de arriba) queda todo en una sola columna apilada. */
@media (min-width: 769px) {
  .trip-form fieldset {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem 1rem;
    align-items: start;
  }

  .trip-form label.checkbox-label {
    grid-column: 1 / -1;
  }
}

.inline-add {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: -0.25rem 0 0.25rem;
}

.inline-add input {
  padding: 0.35rem 0.5rem;
}

.trip-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border, #2e303a);
  position: sticky;
  bottom: 0;
  background: var(--bg, #16171d);
}

.trip-form-actions button {
  padding: 0.5rem 1.1rem;
  cursor: pointer;
}

.modal-content.trip-form-modal {
  width: min(96vw, 900px);
}

.modal-content.trip-estimate-modal {
  width: min(96vw, 1100px);
}

.trip-estimate-hint {
  font-size: 0.85rem;
  opacity: 0.8;
  margin: 0 0 1rem;
}

.trip-estimate-body {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.trip-estimate-form {
  flex: 1 1 320px;
  min-width: 0;
}

.trip-estimate-result {
  flex: 1 1 260px;
  min-width: 0;
  background: var(--code-bg, #1f2028);
  border: 1px solid var(--border, #2e303a);
  border-radius: 8px;
  padding: 1rem;
  align-self: flex-start;
  position: sticky;
  top: 0;
}

.admin-section {
  margin-bottom: 1.25rem;
}

.admin-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.admin-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  border: 1px solid var(--border, #2e303a);
  border-radius: 6px;
  padding: 0.4rem 0.75rem;
}

.admin-list button {
  padding: 0.3rem 0.7rem;
  cursor: pointer;
}

/* Fila de viaje incompleto/cancelado en la tabla de Transporte (ver
   docs/11-Modulo-Transporte.md, "Campos mínimos vs. completables después" y
   la sección de cancelación 2026-08-09). Cada celda faltante ya se marca
   individualmente con `.text-danger` (ver TransportModule.tsx) — este tinte
   de fondo es la señal "a nivel fila" que permite detectar de un vistazo
   qué filas necesitan atención sin tener que leer celda por celda. */
.row-incomplete td {
  background: rgba(176, 0, 32, 0.08);
}

/* Cancelado pisa el estilo de incompleto: un viaje cancelado ya no importa
   si le faltan datos (ver `isTripIncomplete` en tripFields.ts). */
.row-cancelled td {
  background: transparent;
  opacity: 0.55;
  text-decoration: line-through;
}

/* Viaje terminado (2026-08-10, pedido explícito) — verde claro para
   distinguirlo de un viaje activo incompleto (rojo) o cancelado (tachado).
   Terminado pisa el resaltado de incompleto (mismo criterio que ya usaba
   cancelado): una vez que el viaje se da por cerrado, ya no interesa
   marcarlo en rojo aunque le falte algún dato opcional. */
.row-finished td {
  background: rgba(21, 128, 61, 0.1);
}

.badge-cancelled {
  display: inline-block;
  background: #4b5563;
  color: #fff;
  border-radius: 4px;
  padding: 0.1rem 0.5rem;
  font-size: 0.75rem;
  font-weight: bold;
  margin-bottom: 0.5rem;
}

.badge-finished {
  display: inline-block;
  background: #15803d;
  color: #fff;
  border-radius: 4px;
  padding: 0.1rem 0.5rem;
  font-size: 0.75rem;
  font-weight: bold;
  margin-bottom: 0.5rem;
}

/* Modal de detalle de viaje (TripModal.tsx) — más ancho que el genérico
   (`.modal-content`) porque ahora muestra todos los campos del viaje, no
   solo un resumen (pedido explícito 2026-08-09). */
.modal-content.trip-modal {
  width: min(96vw, 700px);
}

/* Acciones del modal de detalle: centradas (pedido explícito), no pegadas a
   la derecha como en los formularios (`.trip-form-actions`). Sticky abajo
   para que sigan a mano aunque el contenido (ahora con todos los campos)
   necesite scroll. */
.trip-modal-actions {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border, #2e303a);
  position: sticky;
  bottom: 0;
  background: var(--bg, #16171d);
}

.trip-modal-actions button {
  padding: 0.5rem 1.1rem;
  cursor: pointer;
}

/* Desglose de resultado tipo "lista de sumas" (TripResultList.tsx, pedido
   explícito 2026-08-09) — reusado por TripModal.tsx y TripEstimateModal.tsx.
   Subtotal / costo total del flete / resultado neto son los tres totales
   (destacados); los ítems que se suman en el medio van más chicos, mismo
   lenguaje visual que un ticket. */
.trip-result-list {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.trip-result-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.trip-result-total {
  font-size: 1.05rem;
  font-weight: 700;
  padding: 0.4rem 0;
  border-top: 1px solid var(--border, #2e303a);
}

.trip-result-items {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.35rem 0 0.35rem 0.75rem;
}

.trip-result-item {
  font-size: 0.85rem;
  font-weight: 400;
  opacity: 0.85;
}

.trip-result-positive {
  color: #4ade80;
}

.trip-result-negative {
  color: #ff6b6b;
}
