* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #1f2937;
}

#app {
  display: flex;
  flex-direction: row;
  height: 100vh;
  height: 100dvh;
}

/* Todos los controles de "armar un recorrido" viven acá: alta de clientes,
   modo dibujo, buscador de paradas y radio. El mapa y los resultados
   ocupan el resto de la pantalla a la derecha (ver #main). */
#sidebar {
  width: 320px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px;
  background: #0f766e;
  color: white;
  overflow-y: auto;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

#sidebar h1 {
  font-size: 18px;
  margin: 0;
}

.sidebar-header-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.icon-btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.5);
  background: transparent;
  color: white;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
  padding: 0;
  text-decoration: none;
}

.icon-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

.sidebar-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.sidebar-actions .btn {
  width: 100%;
  text-align: left;
}

/* Agrupa deshacer/reiniciar/guardar para poder ocultarlos juntos hasta que
   haya un recorrido en curso (modo dibujo activo, o al menos una parada
   cargada por dirección). display:contents deja que sus botones participen
   del flex vertical de .sidebar-actions como si no hubiera wrapper -- el
   mismo gap y orden que antes, sin caja ni margen extra alrededor. Cuando
   está oculto, gana la regla .hidden (display:none !important) de más
   abajo en el archivo. */
#route-actions {
  display: contents;
}

.btn {
  border: 1px solid rgba(255, 255, 255, 0.5);
  background: transparent;
  color: white;
  padding: 6px 12px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
}

.btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.15);
}

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* #saved-routes-select usa la clase .btn para verse igual que los botones
   de la barra (texto blanco sobre el fondo teal), pero eso solo pinta el
   <select> cerrado. La lista desplegada la dibuja el navegador con su
   propio fondo blanco nativo, y hereda el mismo color:white de .btn --
   texto blanco sobre fondo blanco, invisible salvo al pasar el mouse
   (donde el navegador sí pinta un highlight). No es parte de la migración
   a Google, ya pasaba antes; se nota más ahora por casualidad. */
select.btn option {
  color: #1f2937;
  background: white;
}

.btn-primary {
  background: white;
  color: #0f766e;
  font-weight: 600;
}

/* Mismo problema de especificidad que .btn-add-stop: sin esto, en hover
   gana el fondo blanco translúcido genérico de .btn -- sobre un botón que
   ya es blanco, el hover queda sin efecto visible. */
.btn-primary:hover:not(:disabled) {
  background: #f0fdfa;
}

/* La acción principal del sidebar. Azul más oscuro que el de
   .client-marker (#2563eb se perdía contra el fondo teal; este
   #1d4ed8 -- el que antes era el hover -- contrasta mejor).
   Tiene que ir DESPUÉS de .btn en el archivo: misma especificidad, así
   que si quedara antes .btn se la pisaba (le pasó en el primer intento). */
.btn-cta {
  width: 100%;
  background: #1d4ed8;
  border-color: #1d4ed8;
  color: white;
  font-weight: 700;
  padding: 10px 12px;
}

.btn-cta:hover:not(:disabled) {
  background: #1e40af;
  border-color: #1e40af;
}

/* Gris neutro sólido en vez del opacity:0.4 genérico de .btn:disabled --
   ese apagaba cualquier color de fondo a un tono sucio (pasó con el ámbar
   del primer intento). Acá el botón cambia de color entero al
   deshabilitarse y lo recupera limpio al habilitarse, en vez de quedar
   "lavado". Mismo gris que .client-marker-fail, ya usado en la app para
   estados "sin acción disponible". */
.btn-cta:disabled {
  opacity: 1;
  background: #9ca3af;
  border-color: #9ca3af;
  color: white;
}

/* Buscador de paradas, lista y radio: tarjetas blancas flotando sobre el
   fondo teal del sidebar (antes eran franjas horizontales de ancho
   completo, con fondos claros que ya contrastaban bien contra el body
   blanco de la página -- acá hace falta además resetear el color de texto,
   porque el sidebar hereda blanco). */
#stops-bar {
  padding: 12px;
  background: #f0fdfa;
  border-radius: 8px;
  color: #1f2937;
}

#stop-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

#stop-address {
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font-size: 13px;
}

.btn-add-stop {
  background: #0f766e;
  color: white;
  border-color: #0f766e;
  width: 100%;
}

/* .btn:hover:not(:disabled) tiene más especificidad que .btn-add-stop
   sola (el :not() suma un pseudo-clase), así que en hover ganaba el fondo
   blanco translúcido genérico -- casi invisible sobre la tarjeta clara de
   #stops-bar. Necesita el mismo nivel de especificidad (clase + :hover +
   :not) para poder pisarlo. */
.btn-add-stop:hover:not(:disabled) {
  background: #0b5d56;
  border-color: #0b5d56;
}

.stops-list-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 10px;
  font-size: 12px;
  font-weight: 600;
  color: #6b7280;
}

#stops-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

#stops-list li {
  display: flex;
  align-items: center;
  gap: 6px;
  background: white;
  border: 1px solid #a7f3d0;
  border-radius: 14px;
  padding: 3px 6px 3px 10px;
  font-size: 12px;
  max-width: 260px;
  cursor: grab;
}

#stops-list li.dragging {
  opacity: 0.4;
}

#stops-list li.drag-over {
  border-color: #0f766e;
  border-style: dashed;
}

.stop-drag-handle {
  color: #9ca3af;
  flex-shrink: 0;
  line-height: 1;
}

.stop-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stop-remove {
  border: none;
  background: #e5e7eb;
  border-radius: 50%;
  width: 18px;
  height: 18px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  font-size: 10px;
}

.stop-remove:hover {
  background: #fca5a5;
}

.route-planned-date-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  margin-top: 12px;
  margin-bottom: 4px;
}

.route-planned-date-label input {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font-size: 13px;
  font-weight: normal;
}

.btn-save-route {
  margin-top: 8px;
}

#route-summary {
  margin: 8px 0 0;
  font-weight: 600;
  color: #0f766e;
}

/* Ficha del usuario logueado, siempre visible al fondo del sidebar sin
   importar cuánto contenido haya arriba (mismo truco de margin-top:auto
   que usaba antes "Filtrar clientes"). */
.sidebar-user {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.75);
  overflow-wrap: break-word;
}

#route-warning {
  margin: 8px 0 0;
}

#radius-bar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 12px;
  background: #ecfdf5;
  border-radius: 8px;
  color: #1f2937;
}

.hidden {
  display: none !important;
}

/* Ámbar a propósito, bien distinto del teal (#0f766e) del sidebar -- con el
   mismo color se perdía contra la barra de la izquierda. Sticky + sombra
   para que quede claramente por encima del resto de la UI. */
.demo-banner {
  position: sticky;
  top: 0;
  z-index: 1300;
  background: #f59e0b;
  color: #451a03;
  text-align: center;
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}

.demo-banner a {
  color: #451a03;
  text-decoration: underline;
  font-weight: 800;
}

.demo-tutorial-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.demo-tutorial-list li {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Mismos colores que los marcadores reales del mapa (.client-marker,
   .waypoint-marker, .client-marker-highlight en la sección de arriba), para
   que el tutorial señale exactamente lo que el usuario va a ver. */
.demo-tutorial-dot {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 10px;
  font-weight: 700;
}

.demo-tutorial-dot-client {
  background: #2563eb;
}

.demo-tutorial-dot-stop {
  background: #0f766e;
}

.demo-tutorial-dot-nearby {
  background: #f59e0b;
}

/* pointer-events: auto a propósito -- este overlay tiene que bloquear de
   verdad el mapa y el resto de los botones, no solo oscurecerlos. El
   "agujero" sobre el botón lo recorta clip-path (regla evenodd: rectángulo
   completo menos el rectángulo del botón), que en los navegadores
   modernos también saca esa zona de la detección de clicks -- así el click
   llega directo al botón real de abajo sin necesitar ningún truco extra. */
#demo-spotlight {
  position: fixed;
  inset: 0;
  z-index: 1250;
  background: rgba(15, 23, 42, 0.72);
  pointer-events: auto;
  cursor: not-allowed;
}

/* Anillo decorativo alrededor del botón, adentro del agujero -- no
   participa de los clicks (el click ya le llega directo al botón real de
   abajo, esto es puramente visual). Sin transition a propósito: se
   reposiciona en cada frame (app.js#showFilterSpotlight) mientras el
   spotlight está activo, así que una transition solo lo haría ir
   sistemáticamente un paso atrás del recorte real durante un drag. */
#demo-spotlight-hole {
  position: fixed;
  border-radius: 10px;
  border: 2px solid #f59e0b;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.35);
  pointer-events: none;
}

#demo-spotlight-tip {
  position: fixed;
  background: #f59e0b;
  color: #451a03;
  padding: 12px 18px;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 800;
  text-align: center;
  max-width: 260px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
}

#demo-spotlight-tip::after {
  content: '';
  position: absolute;
  left: var(--arrow-left, 50%);
  transform: translateX(-50%);
  border: 9px solid transparent;
}

/* Por defecto el tooltip va arriba del botón, así que la flecha apunta
   hacia abajo. Si no entra arriba (poco espacio) se manda abajo del botón
   y la flecha se da vuelta -- ver demo-spotlight-tip-below en app.js. */
#demo-spotlight-tip:not(.demo-spotlight-tip-below)::after {
  top: 100%;
  border-top-color: #f59e0b;
}

#demo-spotlight-tip.demo-spotlight-tip-below::after {
  bottom: 100%;
  border-bottom-color: #f59e0b;
}

#radius-stepper {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.radius-step-btn {
  flex: 0 0 44px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: #ffffff;
  color: #0f766e;
  font-size: 20px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}

.radius-step-btn:hover {
  background: #f0fdfa;
}

.radius-step-btn:active {
  background: #ccfbf1;
}

#radius-number {
  flex: 1;
  min-width: 0;
  width: auto;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
  padding: 4px;
}

.radius-unit {
  align-self: center;
  color: #6b7280;
  font-size: 14px;
}

#radius-range {
  accent-color: #0f766e;
}

#main {
  flex: 1;
  display: flex;
  min-height: 0;
}

#map {
  flex: 1;
}

#results-panel {
  width: 340px;
  overflow-y: auto;
  padding: 16px;
  border-left: 1px solid #e5e7eb;
  background: #fafafa;
}

#results-panel h2 {
  font-size: 15px;
  margin-top: 0;
}

.muted {
  color: #6b7280;
  font-size: 13px;
}

.result-card {
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 10px;
  margin-bottom: 10px;
}

.result-card .name {
  font-weight: 600;
}

.result-card .address {
  font-size: 12px;
  color: #6b7280;
  margin: 2px 0 6px;
}

.result-card .distance {
  font-size: 12px;
  color: #0f766e;
  font-weight: 600;
}

/* Cliente contactado hace poco: se atenúa la tarjeta entera para que la
   vista se lea de un golpe (los que conviene contactar quedan nítidos). */
.result-card-recent {
  opacity: 0.62;
}

.contact-status {
  font-size: 12px;
  color: #6b7280;
  margin-top: 2px;
}

.contact-status-recent {
  color: #b45309;
  font-weight: 600;
}

.result-card textarea {
  width: 100%;
  min-height: 60px;
  font-size: 12px;
  margin: 6px 0;
  resize: vertical;
}

.result-card input[type="date"] {
  width: 100%;
  margin-bottom: 6px;
  font-size: 12px;
}

.whatsapp-link {
  display: inline-block;
  background: #25d366;
  color: white;
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
}

#modal-overlay,
#csv-overlay,
#settings-overlay,
#confirm-delete-overlay,
#confirm-logout-overlay,
#welcome-warehouse-overlay,
#demo-welcome-overlay,
#demo-tutorial-overlay,
#route-import-column-overlay,
#csv-column-mapping-overlay,
#admin-block-overlay,
#admin-maxclients-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

/* La ficha de cliente y la confirmación de borrado se pueden abrir arriba
   del panel de configuración, así que necesitan quedar por encima. El
   selector de columnas del import CSV se abre arriba del propio modal de
   CSV (#csv-overlay), así que necesita quedar un escalón más arriba todavía. */
#modal-overlay,
#csv-overlay,
#confirm-delete-overlay {
  z-index: 1100;
}

#csv-column-mapping-overlay {
  z-index: 1200;
}

.modal {
  background: white;
  border-radius: 10px;
  padding: 20px;
  width: 360px;
  max-width: 90vw;
}

.modal-wide {
  width: 640px;
  max-width: 92vw;
  max-height: 85vh;
  overflow-y: auto;
}

.route-import-table-wrap {
  margin: 12px 0;
  max-height: 320px;
  overflow: auto;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
}

/* Look base tipo planilla, compartido entre el selector de columna de
   rutas (clickeable, una sola columna) y el de clientes (con un <select>
   de rol por columna, ver .csv-mapping-table más abajo). */
.data-preview-table {
  border-collapse: collapse;
  font-size: 12px;
  white-space: nowrap;
}

.data-preview-table th,
.data-preview-table td {
  padding: 6px 10px;
  border-bottom: 1px solid #e5e7eb;
  border-right: 1px solid #f0f0f0;
  text-align: left;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.data-preview-table thead th {
  position: sticky;
  top: 0;
  background: #f0fdfa;
  color: #0f766e;
  font-weight: 700;
}

.data-preview-table tbody tr:nth-child(even) {
  background: #fafafa;
}

.route-import-table thead th {
  cursor: pointer;
  user-select: none;
}

.route-import-table thead th:hover {
  background: #0f766e;
  color: white;
}

.route-import-table thead th.selected {
  background: #0f766e;
  color: white;
}

.route-import-table thead th.selected::after {
  content: ' ✓';
}

.csv-mapping-table thead tr:first-child th {
  white-space: normal;
}

.column-role-select {
  width: 100%;
  font-size: 11px;
  padding: 2px 4px;
  border-radius: 4px;
  border: 1px solid #d1d5db;
  color: #1f2937;
  background: white;
}

.route-import-column-btn:hover:not(:disabled) {
  background: #f0fdfa;
  border-color: #0f766e;
}

.modal h2 {
  margin-top: 0;
  font-size: 16px;
}

.modal label {
  display: block;
  margin-bottom: 10px;
  font-size: 13px;
}

.modal input[type="text"],
.modal input[type="file"],
.modal textarea {
  width: 100%;
  padding: 6px;
  margin-top: 4px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font: inherit;
}

.modal textarea {
  resize: vertical;
}

.hint code {
  background: #f3f4f6;
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 11px;
}

.hint {
  font-size: 12px;
  color: #6b7280;
}

.error {
  font-size: 12px;
  color: #dc2626;
}

.success {
  font-size: 12px;
  color: #0f766e;
  font-weight: 600;
  margin: 0;
}

.modal-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}

.modal-actions .btn {
  border-color: #d1d5db;
  color: #1f2937;
}

.modal-actions .btn-primary {
  background: #0f766e;
  color: white;
}

/* Mismo problema de especificidad que .btn-add-stop: sin esto, en hover
   gana el fondo verde clarito genérico de .btn-primary:hover -- sobre un
   texto que sigue blanco, queda casi invisible. */
.modal-actions .btn-primary:hover:not(:disabled) {
  background: #0b5d56;
}

.btn-danger {
  background: #fee2e2;
  border-color: #fca5a5;
  color: #b91c1c;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.btn-close {
  border: none;
  background: none;
  font-size: 16px;
  cursor: pointer;
  color: #6b7280;
}

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid #e5e7eb;
  margin: 12px 0 16px;
}

.tab-btn {
  border: none;
  background: none;
  padding: 8px 14px;
  font-size: 13px;
  cursor: pointer;
  color: #6b7280;
  border-bottom: 2px solid transparent;
}

.tab-btn.active {
  color: #0f766e;
  border-bottom-color: #0f766e;
  font-weight: 600;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.checkbox-label input {
  width: auto;
}

.clients-admin-toolbar {
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.clients-admin-buttons {
  display: flex;
  gap: 8px;
}

/* .btn a secas está pensado para el fondo teal del sidebar (texto blanco
   sobre transparente); acá vive sobre el fondo blanco del modal, así que
   sin esto "Importar CSV" quedaría invisible -- mismo reset que ya usan
   .modal-actions .btn y .btn-small en este mismo modal. */
.clients-admin-buttons .btn:not(.btn-primary) {
  border-color: #d1d5db;
  color: #1f2937;
}

#clients-search {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font-size: 13px;
}

.filter-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.chip {
  border: 1px solid #d1d5db;
  background: white;
  color: #6b7280;
  padding: 3px 10px;
  border-radius: 12px;
  font-size: 12px;
  cursor: pointer;
}

.chip:hover {
  border-color: #0f766e;
}

.chip.active {
  background: #0f766e;
  border-color: #0f766e;
  color: white;
  font-weight: 600;
}

#clients-count {
  margin: 0;
}

.badge-warn {
  display: inline-block;
  background: #fef3c7;
  color: #92400e;
  border-radius: 10px;
  padding: 1px 8px;
  font-size: 11px;
  font-weight: 600;
}

.tab-badge {
  display: inline-block;
  background: #fca5a5;
  color: #7f1d1d;
  border-radius: 10px;
  padding: 0 6px;
  font-size: 11px;
  font-weight: 700;
  margin-left: 4px;
}

.section-divider {
  border: none;
  border-top: 1px solid #e5e7eb;
  margin: 18px 0 14px;
}

.section-title {
  font-size: 14px;
  margin: 0 0 6px;
}

#unlocated-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

#unlocated-table th,
#unlocated-table td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid #e5e7eb;
}

.csv-preview {
  background: #f9fafb;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  padding: 8px 10px;
  margin: 10px 0;
}

.csv-preview p {
  margin: 0 0 4px;
}

.csv-preview-list {
  margin: 0;
  padding-left: 18px;
  font-size: 12px;
  color: #6b7280;
}

.csv-progress {
  height: 8px;
  border-radius: 999px;
  background: #e5e7eb;
  overflow: hidden;
  margin: 10px 0 4px;
}

.csv-progress-bar {
  height: 100%;
  width: 0%;
  background: #0f766e;
  border-radius: 999px;
  transition: width 0.3s ease;
}

#clients-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

#clients-table th,
#clients-table td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid #e5e7eb;
}

#clients-table tr.row-disabled {
  color: #9ca3af;
}

.row-actions {
  display: flex;
  gap: 6px;
  white-space: nowrap;
}

.col-checkbox {
  width: 28px;
}

.clients-bulk-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: #f0fdfa;
  border: 1px solid #a7f3d0;
  border-radius: 6px;
  padding: 8px 10px;
  margin-bottom: 10px;
}

.clients-bulk-buttons {
  display: flex;
  gap: 6px;
}

.bulk-progress {
  margin: -4px 0 12px;
}

#bulk-progress-text {
  font-size: 12px;
  color: #6b7280;
}

.btn-small {
  padding: 3px 8px;
  font-size: 11px;
  border-color: #d1d5db;
  color: #1f2937;
}

.popup-fail {
  color: #dc2626;
  font-size: 12px;
}

#map {
  position: relative;
}

.map-load-error {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  background: #fef2f2;
  color: #b91c1c;
  font-size: 14px;
}

/* Marcadores del mapa (AdvancedMarkerElement). Reemplazan los divIcon de
   Leaflet: son simples <div> redondos que Google posiciona y ancla solo. */

.client-marker {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #2563eb;
  border: 2px solid white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.client-marker-fail {
  background: #9ca3af;
}

.client-marker-highlight {
  width: 20px;
  height: 20px;
  background: #f59e0b;
  border: 2px solid white;
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.4);
}

/* DEMO_MAP_ID (el mapId de referencia que se usa cuando no hay
   GOOGLE_MAPS_MAP_ID configurado) ignora fullscreenControl:false y muestra
   igual el botón de pantalla completa -- lo tapamos por CSS ya que la
   opción de la API no alcanza. */
.gm-fullscreen-control {
  display: none !important;
}

.map-recenter-btn {
  width: 40px;
  height: 40px;
  margin: 10px;
  border: none;
  border-radius: 2px;
  background: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  color: #1f2937;
}

.map-recenter-btn:hover {
  background: #f5f5f5;
}

.map-help-btn {
  width: 34px;
  height: 34px;
  margin: 10px;
  border: none;
  border-radius: 50%;
  background: #f59e0b;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  font-size: 17px;
  font-weight: 800;
  line-height: 1;
  color: #451a03;
}

.map-help-btn:hover {
  background: #d97706;
}

.warehouse-marker {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #b45309;
  border: 3px solid white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}

/* Pin fijo de la oficina (Gus Satelital GPS) -- forma distinta (cuadrada,
   no redonda) y color propio para no confundirse con clientes o depósito. */
.brand-marker {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: white;
  border: 2px solid #7c3aed;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  cursor: pointer;
}

.waypoint-marker {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #0f766e;
  border: 2px solid white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 11px;
  font-weight: 700;
  transition: transform 0.15s, box-shadow 0.15s;
}

/* Al pasar el mouse sobre la parada en la lista lateral -- la agranda y le
   pone un halo ámbar para poder ubicarla rápido entre varias paradas
   juntas en el mapa. */
.waypoint-marker-highlight {
  transform: scale(1.5);
  background: #f59e0b;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.35), 0 2px 6px rgba(0, 0, 0, 0.5);
}

/* El widget de autocompletado de Google (gmp-place-autocomplete) reemplaza
   los <input type="text"> de dirección. Estas reglas solo alcanzan al
   elemento host (ancho, layout); el interior es shadow DOM CERRADO, así
   que ningún selector ni variable CSS de acá llega a estilar el fondo
   oscuro por defecto del input real. Ese fix vive en
   public/js/addressAutocomplete.js (patchAutocompleteShadowStyling). */
/* El host trae su propio fondo oscuro por defecto (#131314) puesto por
   Google -- confirmado con el inspector de DevTools. Es DOM normal, así
   que un selector de tag común alcanza para pisarlo (con !important
   porque compite contra el :host de Google, que tiene la misma
   especificidad). Sin este fix, ese fondo oscuro asoma como un "marco"
   alrededor del recuadro blanco de adentro del shadow. No tocamos el
   padding del host: al quedar blanco sobre blanco, deja de notarse. */
gmp-place-autocomplete {
  display: block;
  width: 100%;
  background-color: #ffffff !important;
  border-radius: 6px;
}

/* El elemento host SÍ es DOM normal (no shadow), así que esto es CSS común
   y corriente: cuando el usuario tipea, el navegador (o el propio :host de
   Google) le agrega un anillo de foco separado del recuadro real de
   adentro (el borde teal de .input-container:focus-within), y quedan los
   dos superpuestos con un hueco blanco entre uno y otro. Igual que con el
   background, necesita !important para ganarle a la regla de Google. */
gmp-place-autocomplete:focus,
gmp-place-autocomplete:focus-within,
gmp-place-autocomplete:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

#stop-form gmp-place-autocomplete {
  flex: 1;
}

/* Páginas de login/registro/recuperación: mismo fondo teal que #sidebar,
   pero centradas en toda la pantalla en vez de ser una barra lateral. */
.auth-page {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0f766e;
  padding: 16px;
}

.auth-card {
  background: white;
  border-radius: 10px;
  padding: 28px;
  width: 360px;
  max-width: 100%;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}

.auth-card h1 {
  font-size: 18px;
  margin: 0 0 18px;
  color: #1f2937;
}

.auth-card form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.auth-card label {
  display: block;
  font-size: 13px;
  color: #1f2937;
}

.auth-card input[type="text"],
.auth-card input[type="email"],
.auth-card input[type="password"] {
  width: 100%;
  padding: 8px 10px;
  margin-top: 4px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font-size: 14px;
}

.password-field {
  position: relative;
}

.password-field input {
  padding-right: 34px;
}

.btn-toggle-password {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(calc(-50% + 2px));
  background: none;
  border: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 6px;
  color: #6b7280;
  border-radius: 4px;
}

.btn-toggle-password:hover {
  color: #1f2937;
}

.btn-toggle-password:focus-visible {
  outline: 2px solid #0f766e;
  outline-offset: 1px;
}

.auth-card .btn-primary {
  background: #0f766e;
  color: white;
  border: none;
  padding: 9px 12px;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
  width: 100%;
}

.auth-card .btn-primary:hover:not(:disabled) {
  background: #0b5d56;
}

.auth-card .btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #9ca3af;
  font-size: 12px;
  margin: 4px 0;
}

.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  border-top: 1px solid #e5e7eb;
}

.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: white;
  color: #1f2937;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.btn-google:hover {
  background: #f9fafb;
}

.google-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.auth-links {
  margin-top: 16px;
  font-size: 13px;
  color: #6b7280;
  text-align: center;
}

.auth-links a {
  color: #0f766e;
  font-weight: 600;
  text-decoration: none;
}

.auth-links a:hover {
  text-decoration: underline;
}

/* Panel de superadmin (admin.html) -- página propia, no reusa el layout
   #sidebar/#main del mapa (no tiene sentido acá, es una tabla de datos). */
.admin-page {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 16px 60px;
  color: #1f2937;
}

.admin-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.admin-header h1 {
  font-size: 20px;
  margin: 0;
}

.admin-header-actions {
  display: flex;
  gap: 8px;
}

.admin-header-actions .btn {
  border-color: #d1d5db;
  color: #1f2937;
}

.admin-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-bottom: 28px;
}

.admin-card {
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 14px;
  text-align: center;
}

.admin-card-highlight {
  border-color: #0f766e;
  background: #f0fdfa;
}

.admin-card-cost {
  border-color: #f59e0b;
  background: #fffbeb;
}

.admin-card-cost .admin-card-value {
  color: #b45309;
}

.admin-card-value {
  font-size: 24px;
  font-weight: 700;
  color: #0f766e;
}

.admin-card-label {
  font-size: 12px;
  color: #6b7280;
  margin-top: 2px;
}

.admin-section {
  margin-bottom: 32px;
}

.admin-section h2 {
  font-size: 15px;
  margin-bottom: 4px;
}

.admin-table-wrap {
  overflow-x: auto;
  margin-top: 10px;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  white-space: nowrap;
}

.admin-table th,
.admin-table td {
  text-align: left;
  padding: 6px 10px;
  border-bottom: 1px solid #e5e7eb;
}

.admin-table tr.row-disabled {
  color: #9ca3af;
}

.admin-actions-cell {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.online-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #22c55e;
}

.admin-bars {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 140px;
  margin-top: 10px;
  padding: 10px;
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
}

.admin-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  height: 100%;
  min-width: 20px;
}

.admin-bar-fill {
  width: 100%;
  background: #0f766e;
  border-radius: 3px 3px 0 0;
  min-height: 2px;
}

.admin-bar-label {
  font-size: 9px;
  color: #6b7280;
  margin-top: 4px;
  white-space: nowrap;
}

.auth-success {
  font-size: 13px;
  color: #0f766e;
  background: #f0fdfa;
  border: 1px solid #a7f3d0;
  border-radius: 6px;
  padding: 10px;
}

/* ==========================================================================
   MOBILE (<=767px) -- ver public/js/mobileSheet.js, que usa este mismo
   breakpoint como MOBILE_MQ. Todo lo de mobile vive acá abajo a propósito:
   el resto del archivo no tiene NINGUNA media query, así que el diff de
   desktop queda puramente aditivo (si algo se rompe en desktop, se rompió
   en las 2 líneas sueltas de 100vh->100dvh de más arriba, no acá).
   ========================================================================== */

.mobile-only { display: none; }

/* Oculto por defecto (desktop): el div solo cobra vida dentro del
   media query de más abajo. Sin esto es un tercer hijo de flujo normal
   del flex #app y le roba espacio a #main. */
#mobile-sheet { display: none; }

@media (max-width: 767px) {
  body { overscroll-behavior: none; }

  .mobile-only { display: revert; }
  .desktop-only { display: none; }

  /* --------------------------------------------------------------------
     Layout: el sidebar y el panel de resultados dejan de ser columnas
     fijas de 320px/340px -- mobileSheet.js los reparenta adentro de
     #mobile-sheet, así que acá solo hace falta que dejen de tener un
     ancho fijo y un alto propio con scroll (eso lo pasa a controlar
     .sheet-panes).
     -------------------------------------------------------------------- */
  #app {
    flex-direction: column;
    height: 100dvh;
    overflow: hidden;
  }

  #sidebar {
    width: auto;
    flex: 1 1 auto;
    min-height: 0;
    padding: 12px 14px;
    gap: 10px;
    border-radius: 0;
  }

  .sidebar-header h1 {
    font-size: 15px;
  }

  #main {
    height: 100dvh;
  }

  #map {
    height: 100%;
  }

  #results-panel {
    width: auto;
    border-left: none;
    padding: 12px 14px;
  }

  /* 4 botones apilados en columna se comen ~180px del peek del sheet; en
     grilla 2x2 son ~90px. */
  .sidebar-actions {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .sidebar-actions .btn {
    flex: 1 1 45%;
    text-align: center;
  }

  /* Dentro de un sheet corto, margin-top:auto estira la columna entera
     sin necesidad -- la ficha de usuario simplemente va después del
     resto del contenido. */
  .sidebar-user {
    margin-top: 12px;
  }

  #stops-list {
    flex-direction: column;
    flex-wrap: nowrap;
  }

  #stops-list li {
    max-width: 100%;
  }

  .stop-move {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex-shrink: 0;
  }

  .stop-move-btn {
    width: 26px;
    height: 20px;
    line-height: 1;
    padding: 0;
    border: none;
    border-radius: 4px;
    background: #e5e7eb;
    color: #1f2937;
    font-size: 10px;
    cursor: pointer;
  }

  .stop-move-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
  }

  /* --------------------------------------------------------------------
     iOS hace auto-zoom al enfocar cualquier input con font-size < 16px.
     El gmp-place-autocomplete vive en shadow DOM cerrado y no lo alcanza
     esta regla -- ver public/js/addressAutocomplete.js.
     -------------------------------------------------------------------- */
  input:not([type="range"]):not([type="checkbox"]),
  select,
  textarea {
    font-size: 16px;
  }

  /* --------------------------------------------------------------------
     Touch targets >=44px.
     -------------------------------------------------------------------- */
  .icon-btn {
    width: 40px;
    height: 40px;
  }

  .btn {
    padding: 10px 14px;
    min-height: 44px;
  }

  .stop-remove {
    width: 32px;
    height: 32px;
    font-size: 14px;
  }

  .btn-close {
    min-width: 44px;
    min-height: 44px;
  }

  .chip {
    padding: 8px 14px;
  }

  .tab-btn {
    padding: 12px 14px;
  }

  .btn-small {
    padding: 8px 12px;
    font-size: 13px;
  }

  .whatsapp-link {
    display: block;
    text-align: center;
    padding: 12px;
  }

  #radius-range {
    height: 32px;
    accent-color: #0f766e;
  }

  .btn-toggle-password {
    min-width: 44px;
    min-height: 44px;
  }

  .password-field input {
    padding-right: 46px;
  }

  /* --------------------------------------------------------------------
     Modales: los chicos (borrar, logout, bienvenida, ficha de cliente)
     quedan como hojas ancladas abajo, alcanzables con el pulgar; los
     anchos (config, CSV) pasan a pantalla completa.
     -------------------------------------------------------------------- */
  #modal-overlay,
  #csv-overlay,
  #settings-overlay,
  #confirm-delete-overlay,
  #confirm-logout-overlay,
  #welcome-warehouse-overlay,
  #route-import-column-overlay,
  #csv-column-mapping-overlay,
  #admin-block-overlay,
  #admin-maxclients-overlay {
    align-items: flex-end;
    justify-content: stretch;
    padding: 0;
  }

  .modal {
    width: 100%;
    max-width: 100%;
    max-height: 90dvh;
    overflow-y: auto;
    border-radius: 16px 16px 0 0;
    padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
  }

  .modal-wide {
    width: 100%;
    height: 100dvh;
    max-height: 100dvh;
    border-radius: 0;
  }

  .modal-header {
    position: sticky;
    top: 0;
    background: #fff;
    z-index: 1;
  }

  .modal-actions {
    position: sticky;
    bottom: 0;
    background: #fff;
    border-top: 1px solid #e5e7eb;
    padding: 10px 0 calc(10px + env(safe-area-inset-bottom));
    margin-top: 16px;
  }

  .modal-actions .btn {
    flex: 1;
  }

  /* --------------------------------------------------------------------
     Tablas de clientes/sin-ubicar: en vez de scroll horizontal, cada
     <tr> se convierte en una tarjeta. Cero cambios en settings.js: el
     orden de <td> que genera (checkbox/nombre/dirección/teléfono/estado)
     se lee bien apilado sin agregar etiquetas.
     -------------------------------------------------------------------- */
  #clients-table thead,
  #unlocated-table thead {
    display: none;
  }

  #clients-table tr,
  #unlocated-table tr {
    display: block;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 10px;
    margin-bottom: 8px;
    position: relative;
  }

  #clients-table td,
  #unlocated-table td {
    display: block;
    border: none;
    padding: 2px 0;
  }

  #clients-table td:nth-child(2) {
    font-weight: 600;
    font-size: 15px;
    padding-right: 32px;
  }

  #clients-table td.col-checkbox {
    position: absolute;
    top: 10px;
    right: 10px;
    width: auto;
  }

  .row-actions {
    flex-wrap: wrap;
  }

  .route-import-table-wrap {
    max-height: 45dvh;
  }

  .data-preview-table th,
  .data-preview-table td {
    max-width: 140px;
  }

  /* --------------------------------------------------------------------
     Auth
     -------------------------------------------------------------------- */
  .auth-page {
    padding: 16px calc(16px + env(safe-area-inset-left))
      calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-right));
  }

  .auth-card {
    padding: 20px;
  }

  /* --------------------------------------------------------------------
     Bottom sheet: reemplaza al #sidebar/#results-panel como columnas del
     flex de #app. mobileSheet.js reparenta esos dos nodos adentro de
     #sheet-panes con appendChild -- se mueven, no se clonan, así que
     conservan sus ids y listeners intactos.
     -------------------------------------------------------------------- */

  /* Mientras siguen colgando de #app/#main (o sea: ANTES de que corra el
     reparenting) el CSS de mobile les da flex:1 1 auto y #sidebar se comía
     la pantalla entera -- un panel teal tapando el mapa en cada carga.
     Duraba bastante porque initMobileSheet() está detrás del
     `await requireLogin()` de app.js, que es un fetch a /api/auth/me: el
     layout roto se quedaba a la vista todo ese viaje de red.
     Se testea la posición real en el árbol (combinador de hijo directo) en
     vez de una clase que ponga el JS, así se corrige solo en cuanto el
     nodo se muda, sin depender de que nadie avise. */
  #app > #sidebar,
  #main > #results-panel {
    display: none;
  }

  :root {
    /* Fila de acciones (admin/config/logout, ~48px) + grabber (~20px) +
       tabs (~40px). Tiene que coincidir con el alto real del contenido:
       si queda corto, "peek" recorta el chrome; si sobra, deja un
       colchón vacío -- ninguno de los dos es grave, pero se ajustó a ojo
       viendo el resultado en el navegador. */
    --sheet-chrome-h: 108px;
  }

  #mobile-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--kb-inset, 0px);
    display: flex;
    flex-direction: column;
    z-index: 500; /* debajo de los overlays de modal (1000/1100/1200) */
    background: #0f766e;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.25);
    height: var(--sheet-h);
    transition: height 0.28s ease; /* snaps programáticos: height, nunca transform */
  }

  #mobile-sheet.sheet-peek {
    --sheet-h: calc(var(--sheet-chrome-h) + env(safe-area-inset-bottom));
  }

  #mobile-sheet.sheet-half {
    --sheet-h: 52dvh;
  }

  #mobile-sheet.sheet-full {
    --sheet-h: calc(100dvh - 56px); /* 56px de mapa siempre visible arriba */
  }

  /* Durante el arrastre el alto lo escribe JS en --sheet-h frame a frame:
     la transición tiene que estar apagada para que el panel siga al dedo
     en vez de ir persiguiéndolo con 0.28s de atraso. Nada de
     will-change:transform acá -- el drag ya no usa transform, y esa
     propiedad crea un containing block nuevo para los position:fixed de
     adentro (el dropdown de gmp-place-autocomplete), rompiendo su
     posicionamiento. */
  #mobile-sheet.is-dragging {
    transition: none;
  }

  #mobile-sheet.is-animating {
    transition: height 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
  }

  .sheet-chrome {
    flex: 0 0 auto;
    touch-action: none; /* el gesto de arrastre es 100% nuestro acá (salvo los <button>/<a>, ver onPointerDown) */
    user-select: none;
  }

  /* mobileSheet.js mueve acá todo .sidebar-header (título + íconos
     admin/config/logout) -- fila propia y fija, siempre visible sin
     importar el estado del sheet. .sidebar-header ya trae su propio
     flex/space-between del layout desktop, así que el título queda a la
     misma altura que los íconos. Mismos estilos que en desktop
     (.icon-btn), pero sobre el fondo teal del chrome en vez del de
     #sidebar. */
  .sheet-chrome-header {
    color: #fff;
    padding: 8px 10px 0;
    min-height: 48px;
  }

  .sheet-chrome-header .sidebar-header {
    min-width: 0;
  }

  .sheet-chrome-header .sidebar-header h1 {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .sheet-grabber {
    width: 36px;
    height: 4px;
    margin: 8px auto 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.5);
  }

  .sheet-tabs {
    display: flex;
    gap: 4px;
    padding: 0 10px;
  }

  .sheet-tab {
    flex: 1;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.75);
    font-size: 14px;
    font-weight: 600;
    padding: 10px 8px;
    border-radius: 8px 8px 0 0;
    cursor: pointer;
  }

  .sheet-tab.is-active {
    color: #0f766e;
    background: #fff;
  }

  .sheet-tab:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .sheet-tab-count {
    font-size: 11px;
    font-weight: 700;
  }

  .sheet-panes {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    background: #fff;
  }

  .sheet-panes > * {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }

  /* La solapa activa se elige togglando #sidebar/#results-panel por
     atributo, NO con .hidden -- esa clase (display:none!important) la
     usa routeDraw.updateRouteUiVisibility() sobre #results-panel para
     "no hay recorrido en curso" y tiene que seguir ganando siempre. */
  #mobile-sheet[data-tab="recorrido"] #results-panel {
    display: none;
  }

  #mobile-sheet[data-tab="clientes"] #sidebar {
    display: none;
  }

  .map-recenter-btn {
    width: 48px;
    height: 48px;
  }
}
