/* ==========================================================================
   Mapa v2 — UI alineada con /calendario
   Header en flow estilo .calendar-header (compartido vía app.css)
   Cuerpo flex: canvas + panel + fabs
   ========================================================================== */

.mapa2-root {
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    min-height: 0;
    height: 100%;
    max-height: 100%;
    overflow: hidden;
    background: var(--ic-bg);
}

/* ── Header del mapa — extiende .calendar-header con ajustes propios ────── */
.mapa2-header {
    flex-shrink: 0;
}

.mapa2-status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin: 0 6px 0 4px;
}

.mapa2-status-dot.is-on {
    background: var(--lc-ok);
    box-shadow: 0 0 8px rgba(var(--lc-ok-rgb), 0.65);
}

.mapa2-status-dot.is-off {
    background: var(--lc-err);
    box-shadow: 0 0 6px rgba(var(--lc-err-rgb), 0.5);
}

/* Junto al punto de conexión: el fallo de ubicaciones y el «cargando» de las rentas. */
.mapa2-status-err { margin-left: 2px; flex-shrink: 0; }
.mapa2-status-cargando { margin-left: 4px; flex-shrink: 0; }

.mapa2-header-fecha {
    max-width: 60vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Fila colapsable de búsqueda ─────────────────────────────────────────── */
.mapa2-busqueda-bar {
    flex-shrink: 0;
    position: relative;
    z-index: 25;
}

.mapa2-busqueda-inner {
    display: flex;
    align-items: center;
    gap: 8px;
}

.mapa2-busqueda-icon {
    color: var(--mud-palette-text-secondary, #AEAEB2);
    flex-shrink: 0;
}

.mapa2-busqueda-input {
    flex: 1;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: none;
    color: var(--mud-palette-text-primary, #FFFFFF);
    font-family: inherit;
    font-size: var(--ic-text-md);
    padding: 6px 0;
    min-height: 32px;
}

.mapa2-busqueda-input::placeholder {
    color: var(--mud-palette-text-secondary, #AEAEB2);
}

.mapa2-busqueda-resultados {
    margin-top: 8px;
    background: rgba(var(--ic-bg-rgb), 0.98);
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: var(--ic-radius-md);
    max-height: 320px;
    overflow-y: auto;
    box-shadow: var(--ic-shadow);
}

.mapa2-busqueda-seccion {
    padding: 8px 14px 4px;
    font-size: var(--ic-text-xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    color: var(--mud-palette-text-secondary, #AEAEB2);
}

.mapa2-busqueda-row {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: transparent;
    border: 0;
    color: inherit;
    cursor: pointer;
    text-align: left;
    transition: background 0.12s;
    min-height: 44px;
}

.mapa2-busqueda-row:hover { background: rgba(var(--lc-accent-rgb), 0.1); }

.mapa2-busqueda-avatar {
    width: 28px;
    height: 28px;
    border-radius: var(--ic-radius-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(var(--lc-accent-rgb), 0.18);
    color: var(--lc-accent);
    font-weight: 700;
    flex-shrink: 0;
}

.mapa2-busqueda-avatar--renta { background: rgba(var(--lc-info-rgb), 0.18); color: var(--lc-info); }

.mapa2-busqueda-text {
    flex: 1;
    min-width: 0;
    font-size: var(--ic-text-sm);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--mud-palette-text-primary, #FFFFFF);
}

.mapa2-busqueda-meta {
    font-size: var(--ic-text-xs);
    color: var(--mud-palette-text-secondary, #AEAEB2);
    flex-shrink: 0;
}

.mapa2-busqueda-empty {
    padding: 14px;
    text-align: center;
    color: var(--mud-palette-text-secondary, #AEAEB2);
    font-size: var(--ic-text-sm);
}

/* ── Body: contiene canvas + panel + fabs ────────────────────────────────── */
.mapa2-body {
    flex: 1 1 0%;
    min-height: 0;
    position: relative;
    overflow: hidden;
}

/* ── Canvas Leaflet ─────────────────────────────────────────────────────── */
.mapa2-canvas-wrapper {
    position: absolute;
    inset: 0;
}

/* El fondo es el papel bajo las teselas, y NO es un token de superficie del panel: la base del mapa
   es clara en los dos temas, así que un `--ic-surface-2` dejaba bandas negras entre teselas al
   arrastrar en tema oscuro. `--map-teselas-bg` está declarado una sola vez, a propósito. */
/* El hueco lo dibuja Blazor; el lienzo de dentro lo crea y lo mueve `leaflet-map.js`. Los dos
   miden lo mismo a propósito: `computeAndSetUiInsets` mide la caja del HUECO —es el id que conoce
   .NET— y el solapamiento con la hoja tiene que salir igual que antes de partirlos en dos. */
.mapa2-canvas-slot {
    width: 100%;
    height: 100%;
    z-index: 1;
}

.mapa2-canvas-leaflet {
    width: 100%;
    height: 100%;
    background: var(--map-teselas-bg);
}

/* Respaldo cuando fallan las teselas de la base OSCURA: OSM sólo existe en claro, así que ahí se
   atemía por filtro —un mapa que quema la pantalla de noche es peor que uno sin respaldo—. Con la
   base clara, que es la que se usa hoy en los dos temas, el respaldo ya casa y esta regla no se
   aplica: la clase la pone leaflet-map.js según la BASE, no según el tema. */
.ic-teselas-respaldo {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.9);
}

.mapa2-canvas-loading,
.mapa2-canvas-error {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    /* Sin `backdrop-filter`. Es una capa a `inset: 0` sobre el LIENZO DEL MAPA, que mientras
       carga está vacío: no había nada que desenfocar, y en cambio costaba una capa de composición
       a pantalla completa que aparecía y desaparecía en cada montaje de la lente. */
    background: rgba(var(--ic-bg-rgb), 0.85);
}

.mapa2-canvas-loading-text,
.mapa2-canvas-error span {
    color: var(--ic-muted, #AEAEB2);
    font-size: var(--ic-text-sm);
}

/* El alto del sheet, publicado en la raíz: los flotantes son HERMANOS suyos y no pueden leer una
   variable declarada en él. Un solo sitio donde cambiarlo, en vez de repetir el porcentaje en cada
   `bottom: calc(… + 48% + 16px)` —que además dejaba de ser cierto en cuanto el snap cambiaba—. */
/* La banda que ocupa la fila de «Hoy · conmutador · Nueva», que flota sobre el lienzo: 12px de
   separación + 48 de alto (`calendario-nuevo.css`, `.cal-fab-row` y `.cal-fab-group`), más 8 de
   aire. Es lo que la hoja NO puede invadir por abajo: la fila es la única salida del mapa hacia el
   calendario y taparla fue un bug de producción de septiembre.

   `--mapa2-tope-h` es ese límite convertido en alto máximo. El `100%` se resuelve contra
   `.mapa2-body`, que llega hasta el fondo del viewport —medido en el teléfono: su borde inferior y
   el del viewport coinciden— y por eso hay que descontarle también la barra de navegación.

   `--mapa2-fondo-h` es lo que ocupa el FONDO del lienzo, que ya no es la hoja: sólo la tarjeta del
   modo campo. Nace separada de `--mapa2-sheet-h` porque una variable que significaba «alto de la
   hoja» y «cuánto hay ocupado abajo» a la vez no puede sobrevivir a que la hoja se mude arriba. */
.mapa2-root {
    --mapa2-sheet-h: 48%;
    --mapa2-fila-h: 68px;
    --mapa2-fondo-h: 0px;
    --mapa2-tope-h: calc(100% - var(--ic-bottom-nav-height, 0px) - var(--mapa2-fila-h));

    /* ── La ficha del pin: su tope y el alto de su CAJA ───────────────────────
       Desde que la ficha se mueve con `transform`, su caja NO cambia de alto: lo que se desplaza
       es el carril que la lleva. Así que hay dos números distintos donde antes había uno:

       `--mapa2-ficha-tope` es la altura a pantalla completa, y es la única copia de esa expresión
       —`is-ficha-full` la usa y el alto de la caja se deriva de ella—. Descuenta el alto REAL del
       panel de arriba, que vale 58 u 110 según haya línea accionable, y una franja de 64px que no
       es estética: es la salida «tocar el mapa». A pantalla completa no queda ningún otro sitio
       del lienzo que tocar, así que sin ella esa salida no existiría.

       `--mapa2-ficha-max` es el alto de la caja. Vale el tope para que a pantalla completa la caja
       y la banda visible COINCIDAN —si no, el cuerpo se extendería por debajo del borde y sus
       últimas filas serían inalcanzables—, con un suelo que tampoco es adorno: el asomo más alto
       es 170px (el que lleva aviso de puerta) y con el panel de arriba abierto del todo el tope da
       ~76px. Sin el suelo, la caja saldría MÁS BAJA que su propia banda y la ficha se dibujaría
       flotando sobre un hueco. Lo vigila `FichaDelPinTests`. */
    --mapa2-ficha-tope: calc(100% - var(--mapa2-sheet-h) - 64px);
    --mapa2-ficha-max: max(170px, var(--mapa2-ficha-tope));
}
/* El modo campo NO declara `--mapa2-sheet-h`: comparte especificidad (0,2,0) con los snaps, que van
   después, así que perdería —y el guardián de orden impide moverlo—. Declara sólo lo suyo, que
   ningún snap toca, y así la cascada deja de importar. */
.mapa2-root.is-modo-campo { --mapa2-fondo-h: 68%; --mapa2-fila-h: 0px; }
/* 110 = margen 8 + borde 1 + cabecera 48 + línea accionable 48 + su margen de 4 + borde 1.

   Es lo que MIDE el cabezal plegado, medido en `_bench/sheet-gesto.html` con la transición
   apagada, no calculado de memoria. Subió de 112 a 110 al volverse píldora flotante: gana los 8px
   de separación de la barra de la fecha y sus dos bordes, y pierde los 12 del asa, que ya no
   ocupa sitio propio —cabalga el borde del recorte y se dibuja DENTRO de la banda—.

   Que la banda coincida con el cabezal no es cosmética: si sobra, asoma por debajo la franja de
   fondo del contenido, que va a todo lo ancho, y la píldora deja de leerse como algo que flota.
   Medido: con 112 asomaban 2px.

   La cabecera pasó de 44 a 48 al convertirse ELLA en el botón de plegar: el objetivo táctil es la
   fila entera, así que tiene que cumplir el piso de la casa.

   Historia de este número: decía 156, que era el del mock y no el del porte —medido en el banco, el
   contenido real ocupaba 171 dentro de una caja de 156 con `overflow: hidden`, así que se recortaba
   en silencio el final del hueco y la fila se comía la línea accionable—. Se mide antes de tocarlo
   (`_bench/piel-mapa.html`, sección del sheet).

   Los dos peeks valen igual colgando de arriba que colgando de abajo: son el alto de su
   contenido. Lo que cambia es de qué borde cuelgan. */
.mapa2-root.is-panel-peek { --mapa2-sheet-h: 110px; }
/* Y 58 —margen 8 + borde 1 + cabecera 48 + borde 1— cuando no hay línea accionable, que es lo que
   pasa en un día sin paradas. El alto era fijo, así que ese día el sheet plegado dibujaba 52px de cristal vacío
   debajo de los contadores y tapaba mapa por nada. (0,3,0): gana a la regla de arriba sin depender
   del orden en el archivo.

   `is-sin-linea` dice sólo si HAY línea, no en qué snap estamos: así el gesto, que mide los altos
   poniéndose cada clase de snap encima, lee el peek de verdad también mientras el sheet está
   abierto. Con la clase atada al snap medía 108 y luego se plegaba a 56. */
.mapa2-root.is-panel-peek.is-sin-linea { --mapa2-sheet-h: 58px; }
/* Abierta baja hasta el tope y ni un pixel más: `full` ES el tope. `half` se queda en su 48%,
   acotado por si la pantalla es tan baja que el 48% ya lo rebasaría. */
.mapa2-root.is-panel-half { --mapa2-sheet-h: min(48%, var(--mapa2-tope-h)); }
.mapa2-root.is-panel-full { --mapa2-sheet-h: var(--mapa2-tope-h); }

/* ── Alturas de la FICHA del pin ────────────────────────────────────────────────
   Prefijo y variable PROPIOS, no los del sheet, y no por gusto: el gesto mide sus alturas
   poniéndose cada clase de snap en esta misma raíz. Si la ficha leyera `is-panel-*`, medirla
   movería la hoja de arriba tres layouts seguidos, en el instante en que el dedo se posa.

   TRES alturas —asomo, abierta y pantalla completa— reutilizando `PanelSnap`, que ya las tiene.
   Y una cuarta respuesta que no es una altura: CERRARSE. Por debajo del asomo esta hoja no tiene
   suelo, tiene salida.

   140 = asa 20 + cabecera 52,2 + fila de acciones 66 + borde 1 (139,2), medido en `_bench/sheet-gesto.html` con la
   transición apagada y redondeado hacia arriba: la cabecera tiene decimales porque su alto sale de
   dos line-heights, y por debajo se recortaría el borde de los botones. Escribirlo de memoria fue
   lo que dejó el peek del sheet en 156 cuando su contenido medía 171, recortado en silencio por el
   `overflow: hidden`.

   Subió de 125 a 167 cuando el asa pasó de 16 a 48 y los botones de la fila de acciones de 40 a 48, que era la fila
   que más se pulsa de toda la pantalla y estaba por debajo del mínimo. Son 42px más de mapa
   tapado en el asomo; a cambio, los dos controles que se usan con guantes desde una camioneta
   dejan de ser inalcanzables. La proporción resultante (27% del cuerpo) es la misma que enseña la
   hoja de Google Maps. Y bajó a 140 (2026-09-23) cuando el asa volvió a 20: su objetivo táctil lo
   cubre la cabecera, que hace lo mismo al tocarla y mide 48. */
.mapa2-root.is-ficha-peek { --mapa2-ficha-h: 140px; }
/* Y 170 cuando la parada trae confirmación de la puerta —el chip mide 29 con su hueco—: es lo
   único de esta ficha que puede evitar el viaje entero, así que no puede quedar debajo del recorte. (0,3,0): gana a la
   regla de arriba sin depender del orden en el archivo.

   `is-ficha-con-aviso` dice sólo si HAY aviso, no en qué altura estamos —igual que `is-sin-linea`
   en el sheet—: así el gesto, que mide poniéndose cada clase de altura encima, lee el asomo de
   verdad también mientras la ficha está abierta. */
.mapa2-root.is-ficha-peek.is-ficha-con-aviso { --mapa2-ficha-h: 170px; }
/* ABIERTA. Deja ver mapa: a diferencia del sheet, esta hoja habla de UN punto concreto y taparlo
   del todo sería perder el porqué de haberla abierto.

   Medida contra EL CUERPO, no contra `--mapa2-tope-h`. El tope es el hueco que queda tras
   descontar la barra de navegación y la fila del calendario, y desde que la ficha se las lleva por
   delante ese descuento describe un chrome que ya no está: la altura salía ~95px más corta de lo
   que podía. El tope tampoco se puede recalcular, porque lo consumen los snaps del panel de
   arriba y el motor del sheet mide poniéndose sus clases en esta misma raíz. */
.mapa2-root.is-ficha-half { --mapa2-ficha-h: 52%; }

/* PANTALLA COMPLETA. La hoja se queda con la pantalla. El chrome de abajo no está desde el asomo
   —lo esconden `app.css` y `calendario-nuevo.css` en cuanto la ficha existe, con el mismo `:has()`
   que usa la barra de acciones del detalle de renta—, así que aquí sólo queda decidir cuánto mapa
   se deja arriba.

   El alto se calcula RESTANDO el panel de arriba, no con un porcentaje: `--mapa2-sheet-h` es su
   alto real, que vale 60 u 112 según haya línea accionable, así que la franja de mapa que queda
   es la misma en los dos casos.

   Y esos 64px de franja NO son estética: son la salida «tocar el mapa». A pantalla completa no
   hay ningún otro sitio del lienzo que tocar, así que sin ellos esa salida no existiría. Si
   alguna vez la ficha se siente demasiado vacía aquí, lo que hay que subir es este número —no
   rellenarla de contenido que ya tiene su sitio en la página de detalle. */
.mapa2-root.is-ficha-full { --mapa2-ficha-h: var(--mapa2-ficha-tope); }

/* Los FAB del mapa, mientras hay ficha, cuelgan de ELLA y de nada más.
   
   No sirve `--mapa2-fondo-h`, que es lo que usaban: su `bottom` suma además
   `--ic-bottom-nav-height` y `--mapa2-fila-h`, y esos dos tokens siguen valiendo 72 y 68 aunque
   el chrome esté escondido —`display:none` no mueve una variable—. Los FAB se quedarían 140px por
   encima de la ficha, flotando en mitad del mapa.

   El tope del 40 % se conserva: siguiendo a la ficha hasta arriba se saldrían de pantalla.
   Sólo en móvil: en escritorio los FAB viven en `bottom: 24px` y el chrome no se esconde. */
html[data-chrome="app"] .mapa2-root.is-ficha-peek .mapa2-fabs,
html[data-chrome="app"] .mapa2-root.is-ficha-half .mapa2-fabs,
html[data-chrome="app"] .mapa2-root.is-ficha-full .mapa2-fabs {
    bottom: calc(min(var(--mapa2-ficha-h), 40%) + 16px);
}

/* Mientras el dedo arrastra, el alto lo escribe el gesto cuadro a cuadro: una transición encima
   convertiría el arrastre en un perseguir.

   La marca vive en `<html>` y no en `.mapa2-root` A PROPÓSITO: `MapaPlanificador` reescribe el
   atributo `class` de esa raíz en cada render, así que un tick del timer de 25s borraba la marca a
   mitad del gesto y devolvía la transición. Medido en el teléfono. */
:root[data-ic-sheet-drag] .mapa2-panel,
:root[data-ic-sheet-drag] .mapa2-panel-handle,
:root[data-ic-sheet-drag] .mapa2-ficha-carril,
:root[data-ic-sheet-drag] .mapa2-fabs,
:root[data-ic-sheet-drag] .mapa2-sinpin-chip { transition: none; }

/* Y el desenfoque se apaga mientras dura el gesto. Es lo más caro de la caja: un blur de fondo de
   14px se recompone en CADA cuadro mientras el alto cambia, y el alto cambia con el dedo.

   El chip va en la misma lista y no sólo en la de arriba: cuelga del alto de la hoja por `top`, así
   que se mueve en CADA cuadro del arrastre igual que el panel —y con su propio blur de 8px encima—.
   El arreglo de septiembre le quitó la transición y se dejó el desenfoque: media corrección. */
:root[data-ic-sheet-drag] .mapa2-sinpin-chip {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* La hoja mientras se COLOCA: el alto lo decide el propio componente, no el dedo.
   Hermano del bloque de arriba y deliberadamente un atributo DISTINTO —ver `icSheetQuieto` en
   `ic-deferred-loaders.js` para por qué no puede ser el mismo—. Cubre los tres que cuelgan del alto
   de la hoja: el panel, los FAB (`bottom`) y el chip (`top`).

   El desenfoque NO se apaga aquí: esto dura un pintado, no un gesto, y quitarlo y reponerlo se
   vería como un parpadeo del cristal, que es justo lo que se está persiguiendo. */
:root[data-ic-sheet-quieto] .mapa2-panel,
:root[data-ic-sheet-quieto] .mapa2-panel-handle,
:root[data-ic-sheet-quieto] .mapa2-ficha-carril,
:root[data-ic-sheet-quieto] .mapa2-fabs,
:root[data-ic-sheet-quieto] .mapa2-sinpin-chip { transition: none; }

/* Quien pidió menos movimiento no quiere que medio panel se deslice. El sheet sigue cambiando de
   alto; deja de animarlo.

   Las cuatro INFINITAS van en la misma lista, y son las que de verdad importan aquí: una animación
   de entrada dura 220ms y se acabó, pero un pulso `infinite` no para nunca. `mapa2-skeleton` es
   además la peor de todas —anima `background-position` sobre un degradado de `background-size:
   200%`, o sea pintado continuo mientras la lista carga—. Apagarlas no esconde nada: el estado
   «encendido» lo dicen el color, el borde y la sombra, que se quedan. */
@media (prefers-reduced-motion: reduce) {
    .mapa2-panel,
    .mapa2-panel-handle,
    /* La ficha faltaba en esta lista desde que existe: quien pidió menos movimiento veía
       deslizarse media pantalla cada vez que tocaba un pin. Va el CARRIL, que es lo que se
       mueve —la caja ya no cambia de alto—. */
    .mapa2-ficha-carril,
    .mapa2-fabs,
    .mapa2-sinpin-chip { transition: none; }

    .mapa2-tabs,
    .mapa2-panel-body,
    .mapa2-count-dot.is-on,
    .mapa2-emp-avatar.is-active::before,
    .mapa2-skel,
    .ic-pin-emp--on .ic-pin-emp-ring,
    .mapa2-onboarding,
    .mapa2-onboarding-card { animation: none; }

    .mapa2-item,
    .ic-pin-wrap.is-apareada .ic-pin-parada,
    .chofer-cta-navegar { transition: none; }
}

/* ── FABs flotantes (dentro de .mapa2-body) ─────────────────────────────── */
.mapa2-fabs {
    position: absolute;
    right: 16px;
    /* Con la hoja arriba, el bolsillo del pulgar derecho es de la fila de acciones: el FAB se
       queda 16px por encima de ella. En modo campo la banda de la fila vale 0 y `--mapa2-fondo-h`
       trae el 68% de la tarjeta del chofer, así que la cuenta da lo mismo que daba. */
    bottom: calc(var(--ic-bottom-nav-height, 0px) + var(--mapa2-fila-h, 0px) + var(--mapa2-fondo-h, 0px) + 16px);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 12px;
    transition: bottom 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}

html:not([data-chrome="app"]) .mapa2-fabs {
    bottom: 24px;
}

/* Ya no hace falta un caso por snap: el alto del sheet lo dice --mapa2-sheet-h. */

/* ── Chip "N sin ubicación" (rentas sin coords resolubles, no pintables) ──── */
/* Cuelga del borde inferior de la hoja y la sigue cuadro a cuadro durante el arrastre, porque el
   gesto escribe `--mapa2-sheet-h` en px. Acotado: en `full` la hoja llega hasta el tope y el chip,
   suelto, aterrizaría encima de la fila de acciones —que va en z 1100 y lo enterraría—. El `min()`
   lo deja siempre por encima de ella. En escritorio y en landscape la hoja no es una hoja, así que
   allí vuelve a su sitio de arriba (ver las dos media queries). */
.mapa2-sinpin-chip {
    position: absolute;
    top: min(calc(var(--mapa2-sheet-h) + 12px), calc(100% - var(--mapa2-fila-h) - 60px));
    transition: top 0.3s cubic-bezier(0.32, 0.72, 0, 1);
    left: 50%;
    transform: translateX(-50%);
    z-index: 1001;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: calc(100% - 24px);
    /* Es un botón —abre la lista de rentas sin coordenadas— y medía 30px de alto. El mock lo
       dibuja a 44; aquí el mínimo táctil son 48 y no 44, porque esto se toca desde la camioneta.
       El padding vertical sube a 10 para que el texto quede centrado sin depender del flex. */
    min-height: var(--ic-touch-min);
    padding: 10px 14px;
    border: 1px solid rgba(var(--lc-warn-rgb), 0.45);
    border-radius: 999px;
    background: rgba(var(--ic-surface-rgb), 0.92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--lc-warn);
    font-size: var(--ic-text-xs);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: var(--ic-chrome-shadow);
    transition: transform 0.15s ease, background 0.15s ease;
}

.mapa2-sinpin-chip:hover {
    background: rgba(var(--ic-surface-2-rgb), 0.95);
    transform: translateX(-50%) translateY(-1px);
}

.mapa2-sinpin-chip .mud-icon-root {
    font-size: 1rem;
    color: var(--lc-warn);
}

/* ── Panel (bottom sheet móvil / panel lateral desktop) ─────────────────── */
/* EL RECORTE, no la traslación, y no por gusto.

   Esta hoja cuelga del borde de ARRIBA y se abre hacia abajo: su borde superior está fijo y el
   inferior es el que se mueve. Eso es un RECORTE. `translateY` movería los DOS bordes, así que
   para dejar 112px a la vista habría que subirla entera y lo que quedaría fuera de pantalla sería
   su parte de arriba —los contadores y la línea accionable, o sea lo único que tiene que verse
   plegada—. La ficha del pin no tiene ese problema porque cuelga de abajo, y por eso ella sí va
   con `transform`.

   Lo que se gana es lo mismo: la caja deja de redimensionarse en cada cuadro, y con ella deja de
   re-maquetarse su contenido. Lo que se pierde es la promoción al compositor: esto anima PINTADO,
   no capa.

   POR QUÉ MIDE EL CUERPO ENTERO (`height: 100%`). Los porcentajes de un `inset()` resuelven contra
   la caja del propio elemento, y `--mapa2-sheet-h` es `min(48%, …)`. Si el panel midiera su alto
   abierto, ese 48% pasaría a ser el 48% de OTRA cosa —sin error y sin síntoma, sólo un medio que
   ya no está donde estaba—. Con el panel a la altura del cuerpo, la tabla de alturas de arriba
   sigue significando exactamente lo que significaba cuando era un `height`. Es la misma razón por
   la que la ficha lleva carril.

   El panel ya no pinta nada: la piel entera se mudó a `.mapa2-panel-caja`, que es quien tiene el
   alto ABIERTO y por tanto quien maqueta el contenido una sola vez. */
.mapa2-panel {
    position: absolute;
    left: 0;
    right: 0;
    /* Cuelga del BORDE DE ARRIBA del lienzo, que en la lente mapa es justo debajo de la etiqueta
       del día —«Sábado, 19 sept 2026»—, porque el chrome del día va en flujo por encima de
       `.mapa2-body`. No hay que medirlo desde JS ni nombrarlo aquí: basta con `top: 0`.
       Las dos media queries (sidebar de escritorio y columna de landscape) ponen su propio anclaje
       y sobrescriben esto entero. */
    top: 0;
    height: 100%;
    z-index: 1050;
    /* Lo que asoma. `100% - la banda visible` recorta por abajo justo el resto. */
    clip-path: inset(0 0 calc(100% - var(--mapa2-sheet-h)) 0);
    transition: clip-path 0.3s cubic-bezier(0.32, 0.72, 0, 1);
    /* Sin fondo ni borde: los lleva la caja. Un fondo aquí pintaría el cuerpo entero por debajo
       del recorte y, en cuanto la cabecera se vuelve píldora, asomaría por detrás de ella. */
    pointer-events: none;
    /* NADA de `touch-action: none` aquí. El de un ancestro restringe al de sus descendientes, así
       que puesto en el panel dejaba `.mapa2-panel-body` —que es `overflow-y: auto`— sin poder
       desplazarse con el dedo: la lista de paradas no pasaba de lo que cabía en pantalla. El
       gesto del sheet lo reclaman las zonas de arrastre de abajo, una por una. */
}

/* LA CAJA. Tiene el alto ABIERTO y no cambia nunca, así que su contenido se maqueta una sola vez
   y el recorte de arriba sólo decide cuánto de ella se ve. */
.mapa2-panel-caja {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    /* `--mapa2-tope-h` lleva un `100%` dentro, y aquí resuelve contra `.mapa2-panel`, que mide el
       cuerpo: exactamente la misma base que tenía antes. */
    height: var(--mapa2-tope-h);
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* SIN PIEL. La llevan sus dos grupos, y no por gusto: plegada, el cabezal se convierte en una
       píldora flotante de ancho automático, y un fondo en esta caja asomaría por detrás de ella
       como un rectángulo a todo lo ancho. */
}

/* EL CABEZAL: contadores y línea accionable. Es lo que se ve plegada. */
.mapa2-panel-cabezal {
    flex: 0 0 auto;
    background: var(--ic-surface);
    /* Sin blur y sin sombra. Lo dicen las dos autoridades a la vez: Material 3 pide hoja opaca con
       elevación mínima, y el sustrato de la casa lleva desde 2026-08 con «la línea sustituye a la
       caja». Y encima costaba: un desenfoque de fondo sobre un lienzo de mapa que se mueve se
       recompone en cada cuadro, tanto que había que apagarlo a mano durante el arrastre. */
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-top: 0;
    border-radius: 0 0 var(--ic-radius-lg) var(--ic-radius-lg);
}

/* EL CONTENIDO: pestañas y lista. Sólo se ve abierta. */
.mapa2-panel-contenido {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--ic-surface);
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-top: 0;
    border-radius: 0 0 var(--ic-radius-lg) var(--ic-radius-lg);
}

/* ── Plegada: el cabezal flota ───────────────────────────────────────────────
   A todo lo ancho, una franja oscura para decir «0 empleados · 0 paradas» se come la banda
   superior del mapa sin dar nada a cambio. Flotando, el mapa respira y la hoja se lee como lo que
   es: algo que está ENCIMA y se puede tirar hacia abajo.

   El radio completo se reserva para cuando el cabezal es UNA fila: una cápsula de 48px de alto es
   una píldora, pero con la línea accionable debajo son 96 y los extremos saldrían como dos medias
   lunas enormes. Con dos filas se queda en el radio de la casa. */
.mapa2-root.is-panel-peek .mapa2-panel-cabezal {
    align-self: center;
    width: auto;
    max-width: calc(100% - 24px);
    margin-top: 8px;
    border-top: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: var(--ic-radius-lg);
}

.mapa2-root.is-panel-peek.is-sin-linea .mapa2-panel-cabezal {
    border-radius: 999px;
}

/* Abierta, el contenido ya no tiene esquinas propias: se pega al cabezal y los dos leen como una
   sola tarjeta. */
.mapa2-root.is-panel-peek .mapa2-panel-contenido { border-radius: var(--ic-radius-lg); }

/* Plegada, el contenido está ENTERO fuera del recorte. `content-visibility: hidden` le ahorra
   maquetación, pintado, árbol de accesibilidad y buscar-en-página del subárbol completo — que es
   lo que hace asumible tenerlo siempre montado.

   Va atado al snap Y a que NO haya arrastre: el gesto mueve la variable, no la clase, así que
   colgado sólo del snap dejaría el contenido oculto durante todo el gesto de apertura y el dedo
   descubriría un hueco vacío. */
:root:not([data-ic-sheet-drag]) .mapa2-root.is-panel-peek .mapa2-panel-contenido {
    content-visibility: hidden;
    contain-intrinsic-size: auto 320px;
    /* `content-visibility: hidden` se salta el CONTENIDO, pero la caja del propio elemento sigue
       pintando su fondo y su borde. Sin esto, cualquier píxel que la banda declare de más asoma
       como una franja a todo lo ancho justo debajo de la píldora — y la píldora deja de flotar.
       Es la red contra la deriva de los dos números de arriba. */
    background: none;
    border-color: transparent;
}

/* LA SONDA. Un rectángulo de ancho cero que mide justo la banda visible del panel.

   Existe porque desde el recorte ya no hay ningún elemento cuya CAJA valga eso: la del panel mide
   el cuerpo y la de dentro mide el alto abierto, y `clip-path` no toca la geometría que devuelve
   `getBoundingClientRect()`. Dos cosas la necesitan y las dos la comparten, que es el motivo de
   que sea una y no dos: el gesto —que mide poniéndose cada clase de snap en la raíz— y el cálculo
   de insets del mapa, que tiene que descontar del lienzo lo que la hoja tapa DE VERDAD.

   Cuelga de `.mapa2-body` y no del panel: `--mapa2-sheet-h` lleva porcentajes dentro y tienen que
   resolver contra el cuerpo, como siempre. Dentro del panel valdrían otra cosa. */
.mapa2-panel-sonda {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: var(--mapa2-sheet-h);
    pointer-events: none;
    visibility: hidden;
}

/* Las tres clases por snap ya no deciden el alto —lo decide el recorte—, pero se conservan porque
   el bloque de landscape sí las usa de verdad (allí `--peek` vale 56px de ANCHO y apaga cabecera,
   pestañas y cuerpo): borrarlas rompería esa orientación en silencio. */

/* Por debajo de 1024 el panel es un sheet y no hay nada que plegar de lado. Va ANTES de la media
   query: a igual especificidad gana la última del archivo, y puesta después apagaba el botón
   también en escritorio. */
.mapa2-lateral-toggle { display: none; }

html:not([data-chrome="app"]) .mapa2-panel {
    top: 12px;
    bottom: 12px;
    left: 12px;
    right: auto;
    width: 312px;
    height: auto !important;
    pointer-events: auto;
    /* EL RECORTE SE NEUTRALIZA, y hay que decirlo. Aquí no hay gesto —el motor se autoexcluye
       por encima de 1023px— así que nadie escribe `--mapa2-sheet-h` y el recorte heredado del
       móvil dejaría la columna lateral cortada por donde estuviera el último snap, sin que
       nada lo delate. Es el fallo silencioso más probable de esta migración. */
    clip-path: none;
    transition: transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}

/* La piel vuelve a la caja: aquí no hay píldora que aislar ni recorte que asome por detrás. */
html:not([data-chrome="app"]) .mapa2-panel-caja {
    inset: 0;
    height: auto;
    background: var(--ic-surface);
    border-radius: var(--ic-radius-lg);
    border: var(--ic-hairline-w) solid var(--ic-border);
}
html:not([data-chrome="app"]) .mapa2-panel-cabezal,
html:not([data-chrome="app"]) .mapa2-panel-contenido {
    background: none;
    border: 0;
    border-radius: 0;
    margin-top: 0;
    width: auto;
    max-width: none;
    align-self: stretch;
}

/* La sonda no describe nada vertical en una columna lateral: mediría un alto que aquí no
   significa hoja, y el encuadre del mapa descontaría una banda superior que no existe. */
html:not([data-chrome="app"]) .mapa2-panel-sonda { height: 0; }
/* Con el ancestro delante, (0,2,0): la regla base de `.mapa2-panel-handle` está MÁS ABAJO en
   el archivo y a igual especificidad ganaba por orden, así que en el lateral de escritorio el
   asa se seguía dibujando —una barra de arrastre en un panel que no se arrastra—. Es la trampa
   de cascada de siempre: la regla base va antes, o la media query pesa más. */
html:not([data-chrome="app"]) .mapa2-panel .mapa2-panel-handle { display: none; }
/* Y se le quita el anclaje del móvil por si algún día deja de ocultarse: `top` colgado de
   `--mapa2-sheet-h` no significa nada en una columna lateral. */
html:not([data-chrome="app"]) .mapa2-panel .mapa2-panel-handle { top: auto; transform: none; transition: none; }

/* Aquí el panel es una columna lateral, así que `--mapa2-sheet-h` no describe nada vertical:
   el chip se queda en su esquina de arriba. */
html:not([data-chrome="app"]) .mapa2-sinpin-chip { top: 12px; }

/* ── Agenda partida: el lateral se pliega ─────────────────────────────────
   En el partido el mapa es una columna de ~640 y el panel se lleva 312. Abierto de entrada,
   lo que queda no es un mapa: es una tira de 330 en la que no cabe un barrio. Se sale por
   transform y no por display para que el botón de abrir tenga a dónde volver. */
html:not([data-chrome="app"]) .mapa2-root.is-lateral-plegado .mapa2-panel {
    transform: translateX(calc(-100% - 24px));
    pointer-events: none;
}

html:not([data-chrome="app"]) .mapa2-lateral-toggle {
    display: inline-flex;
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 1001;
    align-items: center;
    gap: 6px;
    min-height: var(--ic-touch-min);
    padding: 0 14px;
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: 999px;
    background: rgba(var(--ic-surface-rgb), 0.94);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--ic-text);
    font-family: var(--ic-font);
    font-size: var(--ic-text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: left 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}

/* Con el panel abierto el botón se aparta a su derecha, o quedaría encima de su cabecera. */
html:not([data-chrome="app"]) .mapa2-root:not(.is-lateral-plegado) .mapa2-lateral-toggle { left: 336px; }

html:not([data-chrome="app"]) .mapa2-lateral-toggle:hover { background: var(--ic-surface); }

/* ── Orientación landscape en móvil/tablet bajo: el panel se vuelve lateral ── */
@media (orientation: landscape) and (max-height: 540px) {
    .mapa2-panel--peek,
    .mapa2-panel--half,
    .mapa2-panel--full {
        top: 0;
        bottom: 0;
        left: auto;
        right: 0;
        width: min(45vw, 360px);
        height: 100% !important;
        pointer-events: auto;
        /* Por lo mismo que en escritorio: aquí tampoco hay gesto, y el recorte del móvil cortaría
           la columna por una altura que nadie va a actualizar. */
        clip-path: none;
    }

    /* La piel, en la caja. Toda esta lista apuntaba a `.mapa2-panel` cuando era él quien pintaba. */
    .mapa2-panel-cabezal,
    .mapa2-panel-contenido {
        background: none;
        border: 0;
        border-radius: 0;
        margin-top: 0;
        width: auto;
        max-width: none;
        align-self: stretch;
    }

    .mapa2-panel-caja {
        inset: 0;
        height: auto;
        background: var(--ic-surface);
        /* En landscape el panel es columna lateral de alto completo; el BottomNav sigue fixed
           abajo a todo el ancho. Reservar su alto para que los CTAs de Ruta no queden tapados. */
        padding-bottom: var(--ic-bottom-nav-height, 0px);
        box-sizing: border-box;
        border-radius: var(--ic-radius-lg) 0 0 var(--ic-radius-lg);
        border-left: var(--ic-hairline-w) solid var(--ic-border);
        border-top: none;
        /* La base trae el borde y la sombra de una hoja que cuelga de arriba; aquí el panel es una
           columna lateral y los dos apuntan al borde equivocado. */
        border-bottom: none;
        box-shadow: -8px 0 28px rgba(0, 0, 0, 0.5);
    }

    .mapa2-panel-sonda { height: 0; }
    .mapa2-panel--peek {
        width: 56px;
    }
    .mapa2-panel--peek .mapa2-panel-header,
    .mapa2-panel--peek .mapa2-tabs,
    .mapa2-panel--peek .mapa2-panel-body { display: none; }
    /* Con el ancestro delante por el mismo motivo que en ≥1024: la regla base del asa está más
       abajo en el archivo y a igual especificidad le ganaba el `width: 100%` y su padding, así que
       el asa rotada de landscape nunca llegó a medir lo que dice. */
    .mapa2-panel .mapa2-panel-handle {
        position: absolute;
        top: 50%;
        left: -2px;
        right: auto;
        transform: translateY(-50%) rotate(90deg);
        transition: none;
        padding: 6px 0;
        width: 44px;
    }

    .mapa2-sinpin-chip { top: 12px; }
    .mapa2-fabs {
        right: calc(min(45vw, 360px) + 12px);
        bottom: calc(var(--ic-bottom-nav-height, 0px) + 16px);
    }
    .mapa2-root.is-panel-full .mapa2-fabs {
        bottom: calc(var(--ic-bottom-nav-height, 0px) + 16px);
    }
}

/* ── Las zonas por las que se arrastra el sheet ───────────────────────────────
   Son las únicas que le quitan el gesto al navegador. Quedan disjuntas del asa de cada parada
   (`.mapa2-parada-handle`, que ya declara lo suyo) y del cuerpo, que vuelve a desplazarse.
   `.mapa2-panel-rutabar` se estila en `calendario-nuevo.css`, pero su gesto es del sheet y por
   eso vive aquí: son propiedades distintas, no compiten.

   EL DESCENDIENTE NO ES ADORNO. `app.css` declara `touch-action: manipulation` para, entre otros,
   `button[type="button"]` —que es lo que el asa ES—, y eso pesa (0,1,1) contra los (0,1,0) de una
   clase suelta: escrito como `.mapa2-panel-handle { … }` el navegador se quedaba con
   `manipulation` y seguía desplazando la página debajo del dedo. Medido en el banco; con el
   ancestro delante son (0,2,0) y ganan. */
.mapa2-panel .mapa2-panel-handle,
.mapa2-panel .mapa2-panel-header,
.mapa2-panel .mapa2-panel-rutabar { touch-action: none; }

/* ── QUIÉN SE QUEDA EL DEDO ───────────────────────────────────────────────────
   LA REGLA, igual en las dos hojas: el scroll de la lista es del NAVEGADOR; la altura de la hoja
   es del MOTOR. Mientras la hoja no está en `full`, su cuerpo no desplaza y el dedo mueve la hoja
   desde cualquier punto. En `full` el cuerpo desplaza con el scroll nativo y la hoja se mueve
   desde el asa y la cabecera (y, en la ficha, desde la tira de acciones). El modelo de Apple Maps.

   POR QUÉ NO HAY «REPARTO» (lo hubo hasta el 2026-09-23). El motor conducía el dedo en la hoja
   entera y repartía cada movimiento entre la hoja y la lista, con inercia escrita a mano. Se
   apoyaba en que el `pan-x` de la caja se INTERSECTABA con el `pan-y` del cuerpo y daba `none`.
   No es así: la intersección de `touch-action` se corta en el contenedor de scroll más cercano
   (Pointer Events, y así lo hace Chrome). Con el dedo en un cuerpo `overflow-y: auto` sólo cuenta
   el del cuerpo: el navegador y el motor se disputaban el mismo gesto, la lista se movía un poco
   y la hoja otro poco. Medido con toques reales por CDP; un `PointerEvent` sintético no lo ve,
   porque se salta `touch-action`.

   Por esa misma regla del corte, el cuerpo quieto lleva `overflow-y: hidden` además de
   `touch-action: none`: los dos juntos, o el navegador vuelve a reclamar el eje.

   `pan-x` en las cajas deja el eje horizontal a quien lo tenga (la tira de acciones de la ficha,
   que es su propio scroller). El vertical es del motor.

   LA MEDIA QUERY NO ES ADORNO: tiene que decir exactamente lo mismo que `esSheet()` en los dos
   motores. Donde el motor se autoexcluye (escritorio, landscape bajo), un cuerpo sin scroll es una
   lista que NO SE DESPLAZA. Lo vigilan `El_gesto_esta_acotado_a_donde_el_motor_conduce` y
   `El_scroll_es_del_navegador_y_la_altura_del_motor`. */
html[data-chrome="app"] .mapa2-root .mapa2-panel .mapa2-panel-caja { touch-action: pan-x; }
html[data-chrome="app"] .mapa2-root .mapa2-ficha-host { touch-action: pan-x; }

html[data-chrome="app"] .mapa2-root .mapa2-panel-body,
html[data-chrome="app"] .mapa2-root .mapa2-ficha-body { overflow-y: hidden; touch-action: none; }

html[data-chrome="app"] .mapa2-root.is-panel-full .mapa2-panel-body { overflow-y: auto; touch-action: pan-y; }

/* La ficha, en `full`, sólo le da el cuerpo al navegador cuando HAY algo que desplazar. Con una
   parada simple —dirección, teléfono, cuadrilla— el contenido cabe y la mitad de abajo era blanco
   muerto: el navegador se quedaba el dedo y no tenía nada que mover (reporte 2026-09-23). El
   estado lo mantiene `ic-ficha-gesto.js` en `data-scroll`:
     · sin atributo o `no` → cabe: sigue la regla quieta de arriba y el dedo mueve la hoja;
     · `arriba` → desborda y está arriba del todo: `pan-down` le deja al navegador SÓLO el dedo
       subiendo (bajar la lista); el dedo bajando es del motor y baja la ficha, como Apple Maps.
       `pan-down` nombra el sentido en que se DESPLAZA el contenido, no el del dedo;
     · `medio` → ya hay scroll: nativo en los dos sentidos.
   iOS no entiende `pan-down` y descarta la declaración: se queda con el `pan-y` que va antes. */
html[data-chrome="app"] .mapa2-root.is-ficha-full .mapa2-ficha-body[data-scroll="arriba"] { overflow-y: auto; touch-action: pan-y; touch-action: pan-down; }
html[data-chrome="app"] .mapa2-root.is-ficha-full .mapa2-ficha-body[data-scroll="medio"] { overflow-y: auto; touch-action: pan-y; }

/* Una pulsación larga sobre la dirección de una parada abriría el selector de texto en medio de
   un arrastre, porque `touch-action` no gobierna la selección. */
html[data-chrome="app"] .mapa2-panel-body,
html[data-chrome="app"] .mapa2-ficha-body {
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}

/* Y el estado ACTIVO: una parada tocada se quedaría resaltada mientras el dedo arrastra la hoja.
   Se apaga con la marca que ya existe. */
:root[data-ic-sheet-drag] .mapa2-parada-row:active,
:root[data-ic-sheet-drag] .mapa2-item:active,
:root[data-ic-sheet-drag] .mapa2-ficha-btn:active { transform: none; }

/* La excepción de `esSheet()`: aquí el panel es una columna lateral de alto completo y la lista es
   lo único que hay. Va DESPUÉS y con la MISMA especificidad que las reglas de arriba —con el
   `html[data-chrome]` delante—: sin él pesaba (0,2,0) contra (0,3,1) y no ganaba nunca. */
@media (orientation: landscape) and (max-height: 540px) {
    html[data-chrome="app"] .mapa2-root .mapa2-panel .mapa2-panel-caja,
    html[data-chrome="app"] .mapa2-root .mapa2-ficha-host { touch-action: auto; }

    html[data-chrome="app"] .mapa2-root .mapa2-panel-body,
    html[data-chrome="app"] .mapa2-root .mapa2-ficha-body { overflow-y: auto; touch-action: pan-y; }
}

.mapa2-panel-handle {
    /* CABALGA EL BORDE DEL RECORTE. Se ancla al panel —que mide el cuerpo, así que el porcentaje
       de `--mapa2-sheet-h` resuelve contra la misma base de siempre— y se sube su propio alto con
       un `translateY(-100%)`: el resultado es que su canto inferior coincide exactamente con la
       banda visible, en los tres snaps y en cada cuadro del arrastre.

       Por qué el desplazamiento no puede llevar la variable dentro: un porcentaje dentro de un
       `translate` resuelve contra la altura del PROPIO elemento —12px—, no contra el cuerpo. Por
       eso el sitio lo pone `top` y el transform sólo corrige por su propio alto.

       12px en total, como el mock: el asa es por donde se arrastra, pero el control que hay que
       poder tocar es el chevron, y ése sí mide 48. */
    position: absolute;
    left: 0;
    right: 0;
    top: var(--mapa2-sheet-h);
    transform: translateY(-100%);
    /* El panel no recibe toques —los reparte su caja— y el asa dejó de estar dentro de ella, así
       que tiene que recuperarlos por su cuenta o no se puede agarrar. Medido: sin esto el punto
       medio del asa devolvía el cuerpo de debajo. */
    pointer-events: auto;
    z-index: 1;
    transition: top 0.3s cubic-bezier(0.32, 0.72, 0, 1);
    width: auto;
    padding: 2px 0 6px;
    background: transparent;
    border: 0;
    cursor: grab;
    display: flex;
    justify-content: center;
    align-items: center;
    -webkit-tap-highlight-color: transparent;
}

/* 32×4 con radio 2: la medida de Material 3 para el asa de una hoja. Y el color sale del token,
   no de un rgba fijo —el que había no volteaba con el tema—. */
.mapa2-panel-handle-bar {
    width: 32px;
    height: 4px;
    border-radius: 2px;
    background: var(--ic-icon-muted);
}

/* La cabecera ES el botón de plegar y desplegar: la barra entera, no la flecha. Volvió a serlo
   siendo un `<button>` de verdad —antes fue un `div` con onclick, sin rol ni teclado, y por eso se
   había quitado—, así que aquí hay que deshacerle el chrome que el navegador le pone.

   `min-height` al piso táctil: ahora el objetivo es esta fila, y una fila de 44 sobre la que hay
   que acertar con el teléfono en una mano no cumple. */
.mapa2-panel-header {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: var(--ic-touch-min);
    /* Al revés que antes: ahora la cabecera es lo primero bajo la barra de la fecha, y 2px arriba
       la dejaban besando su hairline. */
    padding: 6px 16px 2px;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* El chevron ya no es un control: es la SEÑAL de a dónde lleva la barra que lo contiene. Dejó de
   necesitar zona táctil propia —y de poder tenerla: un botón dentro de un botón es marcado
   inválido—, así que se queda en su tamaño de icono y alineado a la derecha. */
.mapa2-panel-chevron {
    flex: 0 0 auto;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--ic-touch-min);
    color: var(--ic-muted);
}

.mapa2-panel-header:hover .mapa2-panel-chevron { color: var(--ic-text); }

.mapa2-panel-counts {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
}

html:not([data-chrome="app"]) .mapa2-panel-header { padding-top: 12px; }
html:not([data-chrome="app"]) .mapa2-panel-counts { justify-content: flex-start; }
/* En el lateral no hay nada que plegar: el panel no tiene snaps, así que la cabecera deja de
   ser un botón —pulsarla escondería las pestañas de una columna que no se pliega— y el chevron
   no tiene nada que señalar. */
html:not([data-chrome="app"]) .mapa2-panel-header { cursor: default; pointer-events: none; }
html:not([data-chrome="app"]) .mapa2-panel-chevron { display: none; }

.mapa2-count {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--ic-text, #FFFFFF);
    font-size: var(--ic-text-xs);
    font-weight: 600;
}

.mapa2-count strong { font-weight: 700; }
.mapa2-count-sep { color: var(--ic-muted, #AEAEB2); }

.mapa2-count-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--lc-neutral);
}

.mapa2-count-dot.is-on {
    background: var(--lc-ok);
    box-shadow: 0 0 8px var(--lc-ok);
    animation: mapa2-pulse 2s ease-in-out infinite;
}

.mapa2-count--ruta strong { color: var(--lc-accent); }

@keyframes mapa2-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

/* Las pestañas y el cuerpo aparecen de golpe en cuanto el snap deja de ser peek, mientras la caja
   todavía está creciendo. Entrar con opacidad los sincroniza con ella sin retrasar el montaje. */
.mapa2-tabs,
.mapa2-panel-body { animation: mapa2-entra-contenido 0.22s ease both; }

:root[data-ic-sheet-drag] .mapa2-tabs,
:root[data-ic-sheet-drag] .mapa2-panel-body { animation: none; }

@keyframes mapa2-entra-contenido {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ── Tabs ───────────────────────────────────────────────────────────────── */
.mapa2-tabs {
    display: flex;
    gap: 4px;
    padding: 0 12px 8px;
    border-bottom: var(--ic-hairline-w) solid var(--ic-border);
}

.mapa2-tab {
    flex: 1;
    background: transparent;
    border: 0;
    padding: 10px 6px;
    color: var(--ic-muted, #AEAEB2);
    cursor: pointer;
    font-size: var(--ic-text-sm);
    font-weight: 600;
    border-radius: var(--ic-radius-md) var(--ic-radius-md) 0 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    position: relative;
    transition: color 0.15s, background 0.15s;
    min-height: 44px;
}

.mapa2-tab:hover { background: rgba(var(--lc-accent-rgb), 0.08); color: var(--ic-text, #FFFFFF); }

.mapa2-tab.is-active {
    color: var(--ic-primary);
    background: rgba(var(--lc-accent-rgb), 0.12);
}

.mapa2-tab.is-active::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 12px;
    right: 12px;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--ic-primary), var(--lc-accent));
}

.mapa2-tab-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--ic-radius-sm);
    background: var(--ic-primary);
    color: var(--ic-on-primary);
    font-size: var(--ic-text-xs);
    font-weight: 800;
}

.mapa2-tab-badge--live {
    background: var(--lc-ok);
    box-shadow: 0 0 8px rgba(var(--lc-ok-rgb), 0.5);
}

/* ── Cuerpo del panel (listas) ──────────────────────────────────────────── */
.mapa2-panel-body {
    flex: 1;
    /* Lo que cede cuando no cabe todo es el cuerpo, que ya tiene scroll propio; sin esto su
       `min-height: auto` implícito se niega a encogerse y el recorte se lo come al asa. */
    min-height: 0;
    /* El contenido entra en el DOM 3ms ANTES del primer cuadro de la animación de altura, así que
       durante los 300ms siguientes la lista se redistribuye con la caja. `contain` deja ese
       reflujo dentro. Comprobado que no rompe el pie pegajoso de la ruta, y los popovers de
       MudBlazor se pintan en `MudPopoverProvider`, fuera del panel. */
    contain: layout paint;
    overflow-y: auto;
    padding: 8px 12px 16px;
    -webkit-overflow-scrolling: touch;
    /* Lo que el panel ya no reclama: aquí se desplaza, y el rebote no se contagia a la página. */
    touch-action: pan-y;
    overscroll-behavior: contain;
}

.mapa2-panel-body::-webkit-scrollbar { width: 4px; }
.mapa2-panel-body::-webkit-scrollbar-thumb {
    background: rgba(var(--lc-accent-rgb), 0.28);
    border-radius: var(--ic-radius-sm);
}

/* ── Items genéricos (renta, empleado) ──────────────────────────────────── */
.mapa2-lista { display: flex; flex-direction: column; gap: 8px; }

.mapa2-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    width: 100%;
    padding: 10px;
    background: rgba(var(--ic-bg-rgb), 0.4);
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: var(--cal-card-radius);
    text-align: left;
    cursor: pointer;
    /* Las tres que sus variantes cambian de verdad (`:hover`, `.is-selected`, `.is-en-ruta`), no
       `all`. Con `all` entra en la transición CUALQUIER propiedad que cambie —incluidas las de
       geometría cuando la fila crece o se reordena—, y esta lista se repinta entera en cada
       volcado de paradas. */
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
    min-height: 60px;
}

.mapa2-item:hover {
    border-color: rgba(var(--lc-accent-rgb), 0.4);
    background: rgba(var(--lc-accent-rgb), 0.06);
}

.mapa2-item.is-selected {
    border-color: rgba(var(--lc-accent-rgb), 0.6);
    background: rgba(var(--lc-accent-rgb), 0.12);
    box-shadow: 0 0 0 2px rgba(var(--lc-accent-rgb), 0.25);
}

.mapa2-item.is-en-ruta {
    /* Era rgba(165,180,252,.55) — el índigo-300 de la marca vieja, escrito a mano y por tanto
       invisible para el barrido de hojas, que sólo busca #hex. */
    border-color: rgba(var(--lc-accent-rgb), 0.55);
}

.mapa2-item-avatar {
    width: 36px;
    height: 36px;
    border-radius: var(--ic-radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--ic-on-primary);
    font-weight: 800;
    box-shadow: var(--ic-shadow-sm);
}

.mapa2-item-orden {
    background: rgba(var(--ic-surface-rgb), 0.92);
    color: var(--ic-text);
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--ic-text-xs);
    font-weight: 800;
}

.mapa2-item-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mapa2-item-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.mapa2-item-title {
    font-size: var(--ic-text-sm);
    font-weight: 700;
    color: var(--ic-text, #FFFFFF);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
    min-width: 0;
}

.mapa2-item-sub {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted, #AEAEB2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-item-meta {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--ic-text-xs);
    color: var(--ic-muted, #AEAEB2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-item-meta--hora { color: var(--lc-accent); }

.mapa2-item-meta .mud-icon-root { font-size: 14px !important; }

.mapa2-item-actions {
    display: flex;
    align-items: center;
    gap: 0;
    flex-shrink: 0;
}

/* ── Empleados ──────────────────────────────────────────────────────────── */
.mapa2-emp-avatar {
    position: relative;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--lc-neutral);
    font-weight: 800;
    background: rgba(var(--lc-neutral-rgb), 0.22);
    flex-shrink: 0;
}

.mapa2-emp-avatar.is-active {
    background: rgba(var(--lc-ok-rgb), 0.22);
    color: var(--lc-ok);
}

.mapa2-emp-avatar.is-active::before {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px solid var(--lc-ok);
    opacity: 0.5;
    animation: mapa2-halo 2s ease-out infinite;
}

@keyframes mapa2-halo {
    0% { transform: scale(0.9); opacity: 0.7; }
    100% { transform: scale(1.6); opacity: 0; }
}

.mapa2-emp-avatar.is-idle {
    background: rgba(var(--lc-neutral-rgb), 0.16);
    opacity: 0.7;
}

.mapa2-emp-tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 6px;
    border-radius: var(--ic-radius-sm);
    font-size: var(--ic-text-xs);
    font-weight: 800;
    letter-spacing: 0.05em;
    flex-shrink: 0;
}

.mapa2-emp-tag--on {
    background: rgba(var(--lc-ok-rgb), 0.18);
    color: var(--lc-ok);
}

.mapa2-emp-tag--off {
    background: rgba(var(--lc-neutral-rgb), 0.14);
    color: var(--ic-muted);
}

/* ── Ruta ───────────────────────────────────────────────────────────────── */
.mapa2-ruta { display: flex; flex-direction: column; gap: 12px; }

.mapa2-ruta-stat {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

.mapa2-ruta-stat-num {
    font-size: var(--ic-text-xl);
    font-weight: 800;
    color: var(--lc-accent);
    line-height: 1;
}

.mapa2-ruta-stat-lbl {
    font-size: var(--ic-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ic-muted, #AEAEB2);
}

.mapa2-ruta-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.mapa2-ruta-cta {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 8px;
    position: sticky;
    bottom: 0;
    background: linear-gradient(180deg, transparent, rgba(var(--ic-surface-rgb), 0.96) 30%);
    padding-bottom: 8px;
}

.mapa2-ruta-cta-row {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.mapa2-ruta-cta-row > .mud-button-root { flex: 1; }

/* Piso táctil del panel de ruta.
   Los botones de este panel van con Size.Small por caber en el bottom sheet, y ese tamaño de
   MudBlazor mide ~30px: por debajo del mínimo de la casa, en la superficie que se usa con el dedo
   dentro de la camioneta. Se sube el alto sin tocar la tipografía — que es para lo que se eligió
   Small — y se aprieta el relleno lateral para que sigan cabiendo dos por fila.
   El selector nombra los contenedores, no `.mud-button-root` a secas: una regla suelta restilaría
   también los botones de los diálogos que este panel abre. */
.mapa2-ruta-acciones .mud-button-root,
.mapa2-ruta-cta .mud-button-root,
.mapa2-sinasignar-head .mud-button-root,
.mapa2-parada-row .mud-button-root {
    min-height: var(--ic-touch-min, 48px);
}

.mapa2-ruta-acciones .mud-button-root,
.mapa2-parada-row .mud-button-root {
    padding-inline: 10px;
}

/* ── Estados vacíos ─────────────────────────────────────────────────────── */
.mapa2-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 32px 16px;
    gap: 8px;
    color: var(--ic-muted, #AEAEB2);
}

.mapa2-empty .mud-icon-root {
    color: color-mix(in srgb, var(--ic-muted) 45%, transparent) !important;
    font-size: 56px !important;
}

.mapa2-empty--ruta .mud-icon-root {
    color: var(--lc-accent) !important;
}

.mapa2-empty-title {
    font-size: var(--ic-text-md);
    font-weight: 700;
    color: var(--ic-text, #FFFFFF);
}

.mapa2-empty-sub {
    font-size: var(--ic-text-xs);
    line-height: 1.4;
    max-width: 280px;
}

/* ── Skeleton ───────────────────────────────────────────────────────────── */
.mapa2-skel {
    height: 68px;
    border-radius: var(--cal-card-radius);
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--ic-text) 8%, transparent) 0%,
        color-mix(in srgb, var(--ic-text) 16%, transparent) 50%,
        color-mix(in srgb, var(--ic-text) 8%, transparent) 100%);
    background-size: 200% 100%;
    animation: mapa2-skeleton 1.4s ease-in-out infinite;
}

@keyframes mapa2-skeleton {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ==========================================================================
   Marcadores Leaflet — pines SVG, halos, clusters, popups
   Estos selectores los inyecta leaflet-map.js como innerHTML de DivIcon.
   ========================================================================== */

.ic-pin-wrap {
    background: transparent !important;
    border: none !important;
    pointer-events: auto;
    /* Mantener pulsado un pin entra en modo ruta (leaflet-map.js, _instalarPulsacionLarga). Sin
       estas tres, iOS levanta su callout de «Copiar | Consultar» sobre la hora del pin, el dedo
       se desplaza y el propio gesto se cancela por el margen de 12px — lo mismo que pasaba con
       las tarjetas del calendario (`.cal-press`). `user-select` sola no basta en Safari. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
}

/* La pulsación larga en curso: el pin se encoge hacia su PUNTA durante los 520ms del
   temporizador —PULSACION_LARGA_MS en leaflet-map.js, los mismos de la tarjeta del calendario—.
   Es la barra de carga del gesto: termina de encogerse justo cuando la selección engancha, y
   al seleccionarse el pin se redibuja entero, así que no hace falta regla de vuelta. */
.ic-pin-wrap.is-press-armed .ic-pin-parada {
    transform: scale(0.88);
    transform-origin: 50% 100%;
    transition: transform 520ms cubic-bezier(0.33, 0.12, 0.28, 1);
}

@media (prefers-reduced-motion: reduce) {
    .ic-pin-wrap.is-press-armed .ic-pin-parada {
        transform: none;
        opacity: 0.7;
        transition: opacity 120ms linear;
    }
}

/* Pin de empleado: círculo con halo pulsante si activo */
.ic-pin-emp {
    position: relative;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ic-pin-emp-ring {
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    border: 2px solid var(--lc-ok);
    opacity: 0;
}

.ic-pin-emp--on .ic-pin-emp-ring {
    opacity: 0.6;
    animation: ic-pin-pulse 2s ease-out infinite;
}

@keyframes ic-pin-pulse {
    0% { transform: scale(0.9); opacity: 0.7; }
    100% { transform: scale(1.6); opacity: 0; }
}

.ic-pin-emp-circle {
    position: relative;
    z-index: 1;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--map-pin-ink);
    font-weight: 800;
    font-size: var(--ic-text-sm);
    font-family: var(--ic-font);
    border: 2.5px solid var(--map-pin-stroke);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}

.ic-pin-emp--on .ic-pin-emp-circle {
    background: var(--lc-ok);
}

.ic-pin-emp--off .ic-pin-emp-circle {
    background: var(--lc-neutral);
    opacity: 0.85;
}

/* ── La base del negocio ───────────────────────────────────────────────────
   CUADRADO y de otro tono, y la forma es la señal: las paradas son gotas de color de estado y los
   empleados discos con su inicial, así que otra gota se leería como una parada más — y es justo lo
   contrario, es lo único del mapa que NO es trabajo. El selector de dirección ya tomó esta misma
   decisión para este mismo punto.

   La sombra va con drop-shadow y no box-shadow por el motivo de siempre en este archivo: box-shadow
   dibujaría el rectángulo del div que Leaflet envuelve alrededor del icono. */
.ic-pin-base {
    position: relative;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--ic-radius-sm);
    background: var(--lc-teal);
    border: 3px solid var(--map-pin-stroke);
    box-sizing: border-box;
    filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.35));
}

/* Tinta DENTRO de un disco de color: el token del fondo de la app, no un blanco fijo. */
.ic-pin-base-glifo {
    fill: var(--map-pin-ink);
}

/* Mismo truco que la gota: la zona sensible la aporta el pseudo-elemento, sin tocar el dibujo ni
   el ancla. El pin mide 34 y el mínimo táctil de esta casa son 48, no 44. */
.ic-pin-base::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: var(--ic-touch-min, 48px);
    height: var(--ic-touch-min, 48px);
    transform: translate(-50%, -50%);
    border-radius: 50%;
}

/* La geocerca del almacén. Leaflet escribe `fill` y `stroke` como ATRIBUTOS del path, y una
   propiedad CSS le gana a un atributo: por eso el color puede vivir aquí, con tokens, en vez de
   viajar quemado desde el JavaScript. Muy tenue a propósito — es contexto, no un dato que se
   consulte — y sin eventos, o se comería los clics de los pines que caigan dentro. */
.ic-base-radio {
    fill: var(--lc-teal);
    fill-opacity: 0.08;
    stroke: var(--lc-teal);
    stroke-opacity: 0.45;
    stroke-width: 1.5;
    stroke-dasharray: 5 5;
}

/* ── «Tu negocio está por allá» ────────────────────────────────────────────
   El indicador que aparece en el borde cuando la base queda fuera de cuadro. Es la mitad que de
   verdad cumple «siempre visible»: el encuadre automático se apaga en cuanto alguien arrastra el
   mapa, y sin esto la base se pierde con el primer gesto.

   Colores de la familia --map-chip-*, que son FIJOS en los dos temas a propósito: esto va encima de
   las teselas, y las teselas son claras tanto de día como de noche.

   La posición la escribe el JavaScript en píxeles del contenedor (`left`/`top`), ya recortada al
   rectángulo útil del lienzo —el que queda descontando la hoja inferior—, así que aquí sólo se
   centra sobre ese punto. */
.mapa2-base-flecha {
    position: absolute;
    z-index: 900;
    display: none;
    align-items: center;
    gap: 6px;
    min-height: var(--ic-touch-min);
    min-width: var(--ic-touch-min);
    padding: 0 12px 0 8px;
    margin: 0;
    transform: translate(-50%, -50%);
    border: var(--ic-hairline-w) solid var(--map-chip-border);
    border-radius: 999px;
    background: var(--map-chip-bg);
    color: var(--map-chip-ink);
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 4px 14px var(--map-chip-shadow);
}

.mapa2-base-flecha.is-visible {
    display: inline-flex;
}

/* La punta es un triángulo CSS y rota sola; el texto no gira, o la distancia saldría del revés
   en media pantalla. El triángulo apunta a la derecha en reposo, que es el ángulo 0 de atan2.

   Va en --map-chip-ink y NO en el teal del pin, aunque el teal sería la señal bonita: este chip
   tiene fondo FIJO en los dos temas, y el --lc-teal del tema claro es un verde azulado oscuro que
   sobre ese fondo da 2.2:1 —medido en el banco—, por debajo del 3:1 que pide un objeto gráfico.
   Un token que voltea dentro de una superficie que no voltea es contraste a medias por definición.
   La identidad teal la lleva el pin, que sí se lee contra la superficie del panel. */
.mapa2-base-flecha-punta {
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 9px solid var(--map-chip-ink);
}

.mapa2-base-flecha-texto {
    flex: 0 0 auto;
}

/* Cuando salen los dos chips, el de configuración sube: el de «sin ubicación» habla del trabajo de
   hoy que no se ve y se queda pegado a la hoja. Se mueve con transform y no con `top` para no tocar
   el min() que mantiene al primero por encima de la fila de acciones. */
.mapa2-base-chip.is-segundo {
    transform: translateX(-50%) translateY(-56px);
}

.mapa2-base-chip.is-segundo:hover {
    transform: translateX(-50%) translateY(-57px);
}

/* El chip de configuración no es una alarma de hoy: va en el gris de la casa, no en el ámbar del
   otro. Dos avisos ámbar a la vez compiten y ninguno gana. */
.mapa2-base-chip {
    border-color: var(--ic-border);
    color: var(--ic-text);
}

.mapa2-base-chip .mud-icon-root {
    color: var(--ic-muted);
}

/* Pin de renta: teardrop SVG con badge de orden opcional.
   La sombra usa drop-shadow (no box-shadow) para que siga la silueta del SVG
   y no genere un rectángulo visible alrededor del div contenedor. */
.ic-pin-renta {
    position: relative;
    width: 34px;
    height: 44px;
    filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.35));
}

/* Pin marcado como parte de una ruta/selección: doble drop-shadow para resaltar
   el contorno con el color de acento + sombra base, sin caer en box-shadow rectangular. */
.ic-pin-renta--selected {
    filter:
        drop-shadow(0 0 2px rgba(var(--lc-accent-rgb), 0.95))
        drop-shadow(0 0 6px rgba(var(--lc-accent-rgb), 0.55))
        drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}

.ic-pin-renta svg {
    display: block;
}

.ic-pin-renta-badge {
    position: absolute;
    top: -6px;
    right: -10px;
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: var(--ic-radius-md);
    background: var(--ic-brand-gradient);
    color: var(--ic-on-primary);
    font-weight: 800;
    font-size: var(--ic-text-xs);
    font-family: var(--ic-font);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--map-pin-stroke);
    box-shadow: 0 2px 8px rgba(var(--lc-accent-rgb), 0.4);
}

/* ── Pin de PARADA ──────────────────────────────────────────────────────────
   La unidad del mapa es la parada (entrega o recolección), no la renta. Estas reglas se escriben
   con los prefijos de token --ic- y --lc-, que voltean solos con data-theme; el resto de esta hoja
   es anterior a esa regla y sigue con hex crudo, migración aparte.

   Los prefijos van SIN comodín a propósito. Escritos con «*» y separados por una barra, el
   asterisco pegado a la barra cerraba este comentario antes de tiempo y la regla base
   .ic-pin-parada de aquí abajo NO llegaba al navegador: ningún pin de parada tenía sombra y sus
   hijos absolutos (número de paso, palomita, hora, ✕) se anclaban al .ic-pin-wrap de Leaflet en
   vez de al div, salvando las posiciones de casualidad porque el wrap mide lo mismo (34×44,
   iconSize en leaflet-map.js). Corregido el 2026-09-17, medido en el banco. Lo vigila
   ComentariosCssCerradosTests.

   La sombra usa drop-shadow y no box-shadow: box-shadow dibujaría un rectángulo alrededor del div
   contenedor en vez de seguir la silueta de la gota. */
.ic-pin-parada {
    position: relative;
    width: 34px;
    height: 44px;
    filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.35));
}

/* Apareo con la lista de la agenda partida: el ratón pasa por una tarjeta y su pin se levanta.
   Crece desde la PUNTA (transform-origin abajo) o el pin se despegaría del domicilio al crecer. */
.ic-pin-wrap.is-apareada {
    z-index: 1200 !important;
}

.ic-pin-wrap.is-apareada .ic-pin-parada {
    transform: scale(1.18);
    transform-origin: 50% 100%;
    filter: drop-shadow(0 0 3px var(--cal-ruta-sel)) drop-shadow(0 4px 8px rgba(0, 0, 0, 0.45));
    transition: transform 0.12s ease-out;
}

/* Objetivo táctil de 48px sin alterar el dibujo ni el ancla: la zona sensible la aporta este
   pseudo-elemento centrado en la cabeza de la gota, no la etiqueta de hora (que es texto de 11px
   y nunca debe ser el blanco de un dedo). */
.ic-pin-parada::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 16px;
    width: var(--ic-touch-min, 48px);
    height: var(--ic-touch-min, 48px);
    transform: translate(-50%, -50%);
    border-radius: 50%;
}

.ic-pin-parada-gota {
    display: block;
}

/* Paso dentro de la ruta de su cuadrilla. Mismo lenguaje que el badge del calendario. */
.ic-pin-parada-num {
    position: absolute;
    top: -6px;
    right: -10px;
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: var(--ic-radius-md);
    background: var(--ic-primary, #0A84FF);
    color: var(--ic-on-primary, #fff);
    font-weight: 800;
    font-size: var(--ic-text-xs);
    font-family: var(--ic-font);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--map-pin-stroke);
}

/* Hora comprometida, legible sin abrir nada. Va debajo de la punta —el sitio convencional de una
   etiqueta de mapa, y el que menos choca, porque la gota apunta hacia abajo y deja ese hueco. */
.ic-pin-parada-hora {
    position: absolute;
    top: 46px;
    left: 50%;
    transform: translateX(-50%);
    padding: 1px 5px;
    border-radius: var(--ic-radius-sm);
    white-space: nowrap;
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    font-weight: 700;
    line-height: 1.3;
    color: var(--ic-text);
    background: var(--ic-surface);
    border: var(--ic-hairline-w) solid var(--ic-border);
    box-shadow: var(--ic-shadow-sm);
    pointer-events: none;
}

/* Por debajo del umbral de zoom la hora no se lee y sólo amontona: se apaga con una clase en el
   contenedor del mapa, sin reconstruir un solo icono. */
.ic-map--hora-oculta .ic-pin-parada-hora {
    display: none;
}

/* Parada ya hecha: NO se atenúa. Aquí vivía un `opacity: .45` con `saturate(.55)` que dejaba un
   domicilio ya entregado casi invisible sobre las teselas —justo el dato que se consulta para saber
   por dónde va el día—. Lo que dice «esto ya está» es la PALOMITA verde, que además sustituye al
   número de paso (leaflet-map.js, `_buildParadaIcon`): una señal que se lee a color pleno y no
   compite con el fondo del mapa.

   De paso desaparece un `filter` más de los que se pisaban sobre el mismo elemento (ver el bloque
   de desempate de más abajo): una parada hecha que además esté en la ruta activa o en alerta ya no
   depende del orden del archivo para saber qué halo le toca.

   Sin clase que ponga `filter`, una parada hecha queda como cualquier pin sin modificador: con la
   sombra base de `.ic-pin-parada`, que es la de reposo. Hasta el 2026-09-17 no era así —esa regla
   base no llegaba al navegador por el comentario que la precede, así que una parada hecha salía
   PLANA sobre las teselas— y eso hacía de la palomita la única señal. */

.ic-pin-parada-check {
    position: absolute;
    top: -4px;
    right: -6px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--lc-ok);
    color: var(--map-pin-ink);
    font-size: var(--ic-text-xs);
    font-weight: 800;
    line-height: 18px;
    text-align: center;
    border: 2px solid var(--ic-surface);
}

/* Trabajo que existe pero que nadie tiene asignado todavía: contorno punteado, sin relleno pleno.
   Mismo lenguaje que las filas discontinuas de "sin orden" en la vista de Rutas.

   El pin ENTERO ya no lleva alfa —aquí vivía un `opacity: .8`—: una renta agendada es trabajo que
   hay que ver, no contexto que se desvanece. Lo que sigue diciendo «nadie la tiene todavía» es el
   CUERPO de la gota (`fill-opacity` + `stroke-dasharray`, al final del archivo), que es además la
   señal por la que el wizard de rutas sabe qué se puede seleccionar. */
.ic-pin-parada--potencial {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.22));
}

/* Otra cuadrilla: presente como contexto —para ver si dos equipos se pisan la zona— pero sin
   competir por la atención con la ruta que se está ordenando. */
.ic-pin-parada--otra-crew {
    opacity: 0.5;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.22)) grayscale(0.8);
}

/* En la ruta activa: aro de acento siguiendo la silueta. */
.ic-pin-parada--ruta {
    filter:
        drop-shadow(0 0 2px var(--ic-primary, #0A84FF))
        drop-shadow(0 0 6px rgba(var(--lc-accent-rgb), 0.55))
        drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}

/* Su posición contradice su hora. ÁMBAR: el rojo está reservado al reloj del ahora. */
.ic-pin-parada--alerta {
    filter:
        drop-shadow(0 0 2px var(--cal-urgente))
        drop-shadow(0 0 7px rgba(var(--lc-warn-rgb), 0.6))
        drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}

/* Parada elegida para la ruta: el número es la POSICIÓN DE TOQUE, no un paso comprometido.
   El relleno del badge se conserva —sobre teselas de mapa un tinte no se leería— y lo que dice
   "esto aún no está comprometido" es el aro.

   El aro era ÁMBAR y pasa a --cal-ruta-sel. El código viejo defendía el ámbar porque no hay un
   texto legible sobre ámbar en los dos temas —cierto, pero el aro no lleva texto—. Lo que pesa es
   otra cosa: el ámbar YA significa "esta parada contradice su hora" (.ic-pin-parada--alerta), y un
   pin seleccionado que además va fuera de hora quedaba con dos halos ámbar y ninguna diferencia
   visible. Ahora seleccionar habla el mismo color que la selección del calendario, que es de donde
   viene la mitad de las rutas que se arman. */
.ic-pin-parada--sel .ic-pin-parada-num {
    border-color: var(--cal-ruta-sel);
}

.ic-pin-parada--sel {
    opacity: 1;
    filter:
        drop-shadow(0 0 2px var(--cal-ruta-sel))
        drop-shadow(0 0 6px color-mix(in srgb, var(--cal-ruta-sel) 50%, transparent))
        drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}

/* ── Quién gana cuando un pin está en dos estados a la vez ──────────────────
   Las seis clases de estado ponen `filter` sobre el MISMO elemento, así que sin esto la cascada
   las resolvía por orden en el archivo —y «sel», que está la última, ganaba a todas—. Medido:
   una parada de OTRA cuadrilla seleccionada para la ruta salía con su halo a todo color, que es
   justo lo contrario de lo que dice la clase.

   Otra cuadrilla gana a todo. Es contexto —está en el mapa para ver si dos equipos se pisan la
   zona— y no puede competir en atención con la ruta que se está ordenando. Su especificidad es
   (0,2,0) contra la (0,1,0) de cada estado suelto, así que gana sin depender de la posición. */
.ic-pin-parada--otra-crew.ic-pin-parada--ruta,
.ic-pin-parada--otra-crew.ic-pin-parada--sel,
.ic-pin-parada--otra-crew.ic-pin-parada--alerta,
.ic-pin-parada--otra-crew.ic-pin-parada--sin-nadie {
    opacity: 0.5;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.22)) grayscale(0.8);
}

/* Y su número tampoco: un paso de ruta ajeno pintado de marca se lee como propio. */
.ic-pin-parada--otra-crew .ic-pin-parada-num {
    background: var(--lc-neutral);
    color: var(--map-pin-ink);
}

/* ── Panel: paradas sin cuadrilla ─────────────────────────────────────────── */
.mapa2-sinasignar {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px;
    border-bottom: var(--ic-hairline-w) solid var(--ic-border);
}

.mapa2-sinasignar-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.mapa2-sinasignar-titulo {
    flex: 1 1 auto;
    font-family: var(--ic-font);
    font-weight: 700;
    color: var(--ic-text);
}

.mapa2-sinasignar-ayuda {
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
}

/* ── Panel: cuadrillas ────────────────────────────────────────────────────── */
.mapa2-crew-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 12px;
}

.mapa2-crew-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: var(--ic-touch-min, 48px);
    padding: 6px 12px;
    border-radius: 999px;
    border: var(--ic-hairline-w) solid var(--ic-border);
    background: var(--ic-surface);
    color: var(--ic-text);
    font-family: var(--ic-font);
    font-size: var(--ic-text-sm);
    font-weight: 600;
    cursor: pointer;
}

.mapa2-crew-chip.is-sel {
    border-color: var(--ic-primary);
    background: var(--ic-primary-dim);
}

.mapa2-crew-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.mapa2-crew-nombre {
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-crew-count {
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--ic-surface-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--ic-text-xs);
    font-weight: 800;
}

/* ── Panel: filas de parada ───────────────────────────────────────────────── */
.mapa2-ruta-acciones {
    display: flex;
    gap: 8px;
    padding: 0 12px 8px;
}

.mapa2-ruta-alerta {
    display: flex;
    align-items: center;
    gap: 8px;
    width: calc(100% - 24px);
    min-height: var(--ic-touch-min, 48px);
    margin: 0 12px 8px;
    padding: 8px 12px;
    border-radius: var(--ic-radius-md);
    border: 1px solid var(--cal-urgente);
    background: rgba(var(--lc-warn-rgb), 0.12);
    color: var(--ic-text);
    font-family: var(--ic-font);
    font-size: var(--ic-text-sm);
    font-weight: 700;
    cursor: pointer;
    text-align: left;
}

.mapa2-ruta-lista {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 0 12px;
    min-height: 48px;
}

/* La banda de estado: 2px del color y tinte al 12 %, lo mismo que la tarjeta de la vista día
   (calendario-dia.css, .event-card). Hasta el 2026-09-22 el --ev sólo llegaba al SVG del pin, así
   que la fila que describe esa MISMA parada era gris plana: la misma renta se contaba de dos
   maneras según la lente. El fallback a --ic-border cubre la parada sin estado reconocido. */
.mapa2-parada-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border-radius: var(--cal-card-radius);
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-left: 2px solid var(--ev, var(--ic-border));
    background: var(--ic-surface);
    background: color-mix(in srgb, var(--ev, transparent) 12%, var(--ic-surface));
    color: var(--ic-text);
    text-align: left;
}

/* Su posición contradice su hora: borde ámbar. El rojo está reservado al reloj del ahora. */
.mapa2-parada-row.is-fuera-hora {
    border-left: 3px solid var(--cal-urgente);
}

.mapa2-parada-row--pend {
    margin-top: 6px;
    border-style: dashed;
    cursor: pointer;
}

.mapa2-parada-row--pend.is-sel {
    border-style: solid;
    border-color: var(--cal-urgente);
    background: rgba(var(--lc-warn-rgb), 0.1);
}

.mapa2-parada-handle {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: var(--ic-touch-min, 48px);
    padding: 6px 2px;
    cursor: grab;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.mapa2-parada-handle:active { cursor: grabbing; }

.mapa2-parada-grip {
    color: var(--ic-muted);
    opacity: 0.65;
}

.mapa2-parada-num {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--ic-primary);
    color: var(--ic-on-primary, #fff);
    font-family: var(--ic-font);
    font-weight: 800;
    font-size: var(--ic-text-xs);
}

.mapa2-parada-num--sel {
    background: rgba(var(--lc-warn-rgb), 0.18);
    color: var(--cal-urgente);
}

.mapa2-parada-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: none;
    border: none;
    padding: 0;
    color: inherit;
    text-align: left;
    cursor: pointer;
    font-family: var(--ic-font);
}

.mapa2-parada-titulo {
    font-size: var(--ic-text-sm);
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-parada-hora {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
}

/* Hora deducida de las fechas de la renta: nadie la fijó para esta parada, y decirlo evita que se
   lea como un compromiso con el cliente. */
.mapa2-parada-hora-deducida {
    margin-left: 4px;
    padding: 0 4px;
    border-radius: var(--ic-radius-sm);
    background: var(--ic-surface-2);
    font-size: var(--ic-text-xs);
    font-weight: 700;
}

.mapa2-parada-aviso {
    font-size: var(--ic-text-xs);
    font-weight: 700;
    color: var(--cal-urgente);
}

.mapa2-parada-meta {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-ruta-pend {
    margin: 10px 12px 0;
    padding-top: 8px;
    border-top: var(--ic-hairline-w) dashed var(--ic-border);
}

.mapa2-ruta-pend-titulo {
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    font-weight: 700;
    color: var(--ic-muted);
}

/* ── Trayecto de la ruta activa ───────────────────────────────────────────── */
/* El color vive aquí y no en las opciones de Leaflet para que voltee con el tema. Los atributos
   de presentación que escribe Leaflet pierden contra cualquier regla CSS, así que esto gana. */
.ic-ruta-casing {
    stroke: var(--ic-surface);
    stroke-opacity: 0.9;
    fill: none;
}

.ic-ruta-trazo {
    stroke: var(--ic-primary);
    stroke-opacity: 0.95;
    fill: none;
}

/* Tramo que no se pudo medir por calles: punteado y apagado. Trazarlo sólido lo haría pasar por
   una calle que no existe. */
.ic-ruta-trazo--aprox {
    stroke: var(--ic-muted);
    stroke-opacity: 0.9;
}

/* ── Selector de dirección ──────────────────────────────────────────────────
   Comparte archivo y teselas con el mapa de flota, así que comparte también la regla: el color de
   un path de Leaflet sale como ATRIBUTO de SVG —que no acepta var()— y cualquier regla de autor
   gana a un atributo de presentación. Por eso el color entra por clase y no por opción. */

/* Círculo de incertidumbre: ámbar, que aquí significa «duda sobre este punto». */
.ic-picker-duda {
    stroke: var(--lc-warn);
    fill: var(--lc-warn);
}

/* Cobertura de la ciudad. Índigo y no ámbar a propósito: no es una duda, es un límite. */
.ic-picker-cobertura {
    stroke: var(--ic-primary);
    fill: var(--ic-primary);
}

/* ── Panel: resumen de la ruta ────────────────────────────────────────────── */
.mapa2-ruta-resumen {
    display: flex;
    gap: 16px;
    padding: 4px 12px 8px;
}

.mapa2-ruta-stat {
    display: flex;
    flex-direction: column;
    font-family: var(--ic-font);
}

.mapa2-ruta-stat-num {
    font-size: var(--ic-text-xl);
    font-weight: 800;
    color: var(--ic-text);
}

.mapa2-ruta-stat-lbl {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
}

.mapa2-ruta-parcial {
    display: block;
    padding: 0 12px 8px;
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
}

/* ── Presencia: sólo lo que rompe el viaje llega al pin ────────────────────── */
/* Nadie estará en la dirección. Aro rojo, calcado del ámbar de --alerta. En el marcado son
   EXCLUYENTES (ver leaflet-map.js): los dos ponen filter sobre el mismo elemento y aquí la cascada
   los resolvería por orden de archivo, que no lo dice nadie. */
.ic-pin-parada--sin-nadie {
    filter:
        drop-shadow(0 0 2px var(--lc-err))
        drop-shadow(0 0 7px rgba(var(--lc-err-rgb), 0.6))
        drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}

/* Esquina IZQUIERDA: la derecha ya la ocupan el número de paso y la palomita de finalizada. */
/* Disco de la superficie con el símbolo y el aro en rojo, NO relleno rojo con texto blanco:
   --lc-err es rojo claro en tema oscuro (#EF9A9A) y oscuro en tema claro, así que ningún color de
   texto fijo encima sirve para los dos. Es el mismo patrón que usan los chips lc-chip--err. */
.ic-pin-parada-nadie {
    position: absolute;
    top: -5px;
    left: -8px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--ic-surface);
    color: var(--lc-err);
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    font-weight: 800;
    line-height: 14px;
    text-align: center;
    border: 2px solid var(--lc-err);
}

/* ── Panel: presencia en la fila ───────────────────────────────────────────── */
.mapa2-parada-presencia {
    display: inline-flex;
    margin-top: 2px;
}

/* La condición del cliente. Sin esto, «ordenar por hora» parece un bug: la fila sigue mostrando la
   hora pactada y la parada aparece fuera de sitio sin explicación. */
.mapa2-parada-desde {
    margin-left: 6px;
    padding: 0 5px;
    border-radius: var(--ic-radius-sm);
    background: rgba(var(--lc-warn-rgb), 0.16);
    color: var(--cal-urgente);
    font-size: var(--ic-text-xs);
    font-weight: 700;
    white-space: nowrap;
}

/* El contador de pendientes por confirmar: mismo lenguaje que el aviso de orden, distinta voz. */
.mapa2-ruta-alerta--presencia {
    border-color: var(--ic-border);
    background: var(--ic-surface);
    color: var(--ic-muted);
}

.mapa2-ruta-alerta--presencia.is-activo {
    border-color: var(--ic-primary);
    background: var(--ic-primary-dim);
    color: var(--ic-text);
}

/* Cluster (markercluster wrapper) */
.ic-cluster-wrap {
    background: transparent !important;
    border: none !important;
}

.ic-cluster {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    color: var(--ic-text);
    font-weight: 800;
    font-family: var(--ic-font);
    border: 3px solid var(--map-pin-stroke);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), inset 0 0 0 2px rgba(255, 255, 255, 0.15);
    transition: transform 0.15s ease;
    /* Respaldo si el JS no setea un background inline (sin colores de hijos): índigo previo. */
    background: var(--ic-brand-gradient);
}

.ic-cluster:hover { transform: scale(1.05); }

/* Los tiers solo controlan tamaño/tipografía; el color del anillo lo pone el JS inline
   (conic-gradient multicolor por estado, o color sólido dominante en WebViews sin conic). */
.ic-cluster-sm {
    width: 36px;
    height: 36px;
    font-size: var(--ic-text-xs);
}

.ic-cluster-md {
    width: 44px;
    height: 44px;
    font-size: var(--ic-text-sm);
}

.ic-cluster-lg {
    width: 52px;
    height: 52px;
    font-size: var(--ic-text-base);
}

/* Disco interior neutro: mantiene el número legible sobre cualquier color del anillo. */
.ic-cluster-core {
    display: flex;
    align-items: center;
    justify-content: center;
    width: calc(100% - 12px);
    height: calc(100% - 12px);
    border-radius: 50%;
    background: rgba(var(--ic-surface-rgb), 0.94);
    box-shadow: inset 0 0 0 var(--ic-hairline-w) var(--ic-border);
}

.ic-cluster-num {
    line-height: 1;
    color: var(--ic-text);
}

/* Controles Leaflet adaptados al tema */
.leaflet-control-zoom a {
    background: var(--ic-surface) !important;
    color: var(--ic-text) !important;
    border-color: var(--ic-border) !important;
    backdrop-filter: blur(10px);
}

.leaflet-control-zoom a:hover {
    background: var(--ic-primary-dim) !important;
    color: var(--ic-text) !important;
}

.leaflet-control-attribution {
    background: rgba(var(--ic-bg-rgb), 0.7) !important;
    color: var(--ic-muted) !important;
    font-size: 10px !important;
    backdrop-filter: blur(8px);
}

.leaflet-control-attribution a { color: var(--lc-accent) !important; }

/* ==========================================================================
   Onboarding tour (overlay con 3 slides primera vez)
   ========================================================================== */
.mapa2-onboarding {
    position: fixed;
    inset: 0;
    z-index: 6500;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(8px);
    animation: mapa2-fadein 0.2s ease;
}

@keyframes mapa2-fadein {
    from { opacity: 0; }
    to { opacity: 1; }
}

.mapa2-onboarding-card {
    position: relative;
    width: 100%;
    max-width: 380px;
    background: linear-gradient(180deg, rgba(var(--ic-surface-rgb), 0.98), rgba(var(--ic-bg-rgb), 0.98));
    border: 1px solid rgba(var(--lc-accent-rgb), 0.3);
    border-radius: var(--ic-radius-lg);
    box-shadow: var(--ic-shadow);
    padding: 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    animation: mapa2-slidein 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}

@keyframes mapa2-slidein {
    from { transform: translateY(20px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

.mapa2-onboarding-skip {
    position: absolute;
    top: 12px;
    right: 12px;
    background: transparent;
    border: 0;
    color: var(--ic-muted);
    cursor: pointer;
    padding: 4px;
    border-radius: 50%;
}

.mapa2-onboarding-skip:hover { background: rgba(var(--lc-neutral-rgb), 0.12); color: var(--ic-text); }

.mapa2-onboarding-emoji {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: var(--ic-brand-gradient);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 8px;
    box-shadow: 0 8px 20px var(--ic-brand-ring);
}

.mapa2-onboarding-emoji .mud-icon-root { color: var(--ic-on-primary) !important; font-size: 40px !important; }

.mapa2-onboarding-titulo {
    margin: 0;
    font-size: var(--ic-text-xl);
    font-weight: 800;
    color: var(--ic-text);
    text-align: center;
}

.mapa2-onboarding-desc {
    margin: 0;
    font-size: var(--ic-text-md);
    line-height: 1.5;
    color: var(--ic-muted);
    text-align: center;
}

.mapa2-onboarding-dots {
    display: flex;
    gap: 6px;
    margin: 8px 0;
}

.mapa2-onboarding-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(var(--lc-neutral-rgb), 0.35);
    transition: width 0.2s, background 0.2s;
}

.mapa2-onboarding-dot.is-on {
    width: 24px;
    border-radius: var(--ic-radius-sm);
    background: var(--lc-accent);
}

.mapa2-onboarding-actions {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}

/* ==========================================================================
   La FICHA del pin — lo que sale al tocar un punto del mapa
   ==========================================================================

   Sustituye al popup de Leaflet. El recuadro con pestañita se plantaba ENCIMA del marcador que
   acababas de tocar y se comía el entorno, que es lo que da sentido a un mapa; y como era un
   `bindPopup` con HTML concatenado en JS, todo lo que sabemos de la parada —dirección, teléfono,
   cuadrilla, orden de ruta, confirmación de la puerta— se quedaba fuera por falta de sitio.

   Se ancla abajo por lo mismo que la tarjeta del chofer: el pulgar llega, y el mapa —que es el
   contexto— se queda arriba. De hecho es su vecina de carril y comparte sus dos decisiones caras:
   el `bottom` colgado de la barra de navegación y el z-index por debajo de la fila del calendario.
   ========================================================================== */
/* EL CARRIL. Es lo único que se mueve, y mide el CUERPO ENTERO.

   Que mida el cuerpo entero no es comodidad: `translateY(%)` resuelve contra la altura del propio
   elemento, mientras que `height:%` resuelve contra el bloque contenedor. Si el desplazamiento
   colgara de una caja de otro alto, `is-ficha-half: 52%` pasaría a significar otra cosa sin error
   y sin síntoma —medido: 333px se convertían en 260—. Con el carril a `inset: 0`, la tabla de
   alturas de arriba sigue resolviendo contra la misma base que resolvía cuando era un `height`, y
   no hubo que tocar ni un número.

   `translateY(100%)` lo deja entero fuera por abajo; restándole la banda visible, asoma justo eso.

   Sin `will-change`: una capa promovida de forma permanente encima de un lienzo de mapa cuesta
   memoria todo el rato, y el navegador ya promociona solo mientras dura la transición.

   `pointer-events: none` porque el carril cubre el cuerpo entero: sin esto se comería los toques
   del mapa. Los recupera la caja. */
.mapa2-ficha-carril {
    position: absolute;
    inset: 0;
    z-index: 1040;
    pointer-events: none;
    transform: translateY(calc(100% - var(--mapa2-ficha-h, 0px)));
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}

/* LA ENTRADA. Un elemento recién montado no tiene transición: nace ya en su sitio. Sin esto la
   ficha aparecía de golpe y —peor— no emitía `transitionend`, que es el latido con el que el host
   centra el pin en el hueco visible: el pin se quedaba tapado. `@starting-style` le da un punto de
   partida (entera fuera por abajo) y la ficha SUBE con la misma transición. Sólo en modo app: en
   escritorio el carril no se desplaza. Donde no se entienda, o con movimiento reducido, el motor
   tiene un respaldo por tiempo (`init` en `ic-ficha-gesto.js`). */
@starting-style {
    html[data-chrome="app"] .mapa2-ficha-carril { transform: translateY(100%); }
}

/* Y quien pidió menos movimiento no ve deslizarse la ficha. El carril ya estaba en la lista de
   `prefers-reduced-motion` de arriba, pero esa lista va ANTES que la regla base del carril y a la
   misma especificidad, así que perdía: la ficha se deslizaba igual. Medido por CDP con el medio
   emulado. Va aquí, DESPUÉS de la regla base. */
@media (prefers-reduced-motion: reduce) {
    .mapa2-ficha-carril { transition: none; }
}

/* LA CAJA. Pegada al borde de ARRIBA del carril y con alto FIJO: ya no cambia de alto nunca, que
   es lo que quita el re-maquetado de su contenido en cada cuadro del gesto.

   Conserva el nombre `mapa2-ficha-host` a propósito, aunque ya no sea ella quien se mueve: de ese
   nombre cuelgan las dos reglas `:has()` que esconden el chrome de abajo (`app.css` y
   `calendario-nuevo.css`) y el selector con el que `leaflet-map.js` descuenta la ficha del
   encuadre. Renombrarla las rompería todas a la vez, en silencio.

   Y el encuadre sigue valiendo sin tocar una línea porque sólo usa el borde SUPERIOR de esta caja
   (`mapRect.bottom - f.top`), que con el carril desplazado es exactamente el borde visible. */
.mapa2-ficha-host {
    position: absolute;
    left: 0;
    right: 0;
    /* A RAS DEL CARRIL, que es quien está a ras de suelo.

       En móvil la ficha se lleva por delante el chrome de abajo —la barra de navegación y la fila
       del calendario— desde que se abre, así que no hay nada que esquivar: debajo de ella no queda
       nada. Quien los esconde es `app.css` y `calendario-nuevo.css`, con el mismo `:has()` que usa
       la barra de acciones del detalle de renta.

       Esto estuvo colgado de `calc(--ic-bottom-nav-height + --mapa2-fila-h)`, que era lo correcto
       mientras el chrome seguía ahí: la fila flota entre 12 y 60px sobre la barra y se comía ENTERA
       la fila de acciones de la ficha —«Cómo llegar», «Llamar», «Ver detalle»—. Hoy ya no está, y
       apoyarse en esos tokens sería peor que inútil: `display:none` NO los pone a cero —siguen
       valiendo 72px+safe-area y 68px—, así que la ficha flotaría sobre un hueco vacío.

       En escritorio es al revés y lo resuelve la media query del final: allí el chrome NO se
       esconde, porque esa fila es la única barra de acciones que existe. */
    top: 0;
    bottom: auto;
    height: var(--mapa2-ficha-max);
    pointer-events: auto;
    /* 1040, el carril de la tarjeta del chofer, y nunca 1100 o más: la fila inferior del
       calendario —«Hoy», el conmutador de lente, vista y filtros— vive en 1100 y es la única
       salida del mapa. Taparla con algo opaco fue el bug de producción de septiembre. Por encima
       de los flotantes del mapa (1000/1001), que sí se pueden tapar. Se declara también aquí y no
       sólo en el carril: es donde lo busca `ApilamientoLenteMapaTests`, y donde se lee. */
    z-index: 1040;
    display: flex;
    flex-direction: column;
    /* El recorte lo hace ESTA caja y no un `@if` en el componente: así el gesto mide el alto real
       de la ficha completa y no el de un cuerpo que todavía no se ha renderizado. */
    overflow: hidden;
    border-radius: var(--ic-radius-lg) var(--ic-radius-lg) 0 0;
    /* La línea sustituye a la caja: el hairline delimita y nada más. Fuera el desenfoque y la
       sombra, que decían las dos autoridades a la vez —Material 3 pide hoja OPACA con elevación
       mínima, y el sustrato de la casa lleva desde 2026-08 sin blur ni sombra— y encima costaban:
       un blur de fondo sobre un lienzo de mapa se recompone en cada cuadro, tanto que había que
       apagarlo a mano durante el arrastre. */
    border-top: var(--ic-hairline-w) solid var(--ic-border);
    background: var(--ic-surface);
    /* Sin transición: la caja ya no cambia de alto. Lo que se anima es el `transform` del carril. */
}

/* ── Asa ──────────────────────────────────────────────────────────────────── */
/* Con el ancestro delante, (0,2,0). No es adorno: desde que el asa es un `<button>`, `app.css`
   le aplica `touch-action: manipulation` con (0,1,1) y le ganaba a la clase suelta — el navegador
   se habría quedado con el desplazamiento vertical y el arrastre habría dejado de seguir al dedo.
   Es la misma trampa que ya costó un arreglo en el asa del panel. */
.mapa2-ficha-host .mapa2-ficha-handle {
    flex: 0 0 auto;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    /* 20px y no 48 (pedido del dueño, 2026-09-23: la franja de 48 se leía como una pestaña
       gorda encima del título). No se pierde el objetivo táctil: tocar el asa hace lo mismo que
       tocar la cabecera —`Alternar`—, y la cabecera, justo debajo, sí mide 48. Y arrastrar ya
       funciona desde cualquier punto de la ficha, así que el asa dejó de ser el único agarre.
       Si esto cambia, cambian con ello los dos números del asomo (`is-ficha-peek`). */
    min-height: 20px;
    padding: 8px 0;
    border: 0;
    background: transparent;
    /* El gesto vive aquí, así que el navegador no puede quedarse con el desplazamiento vertical. */
    touch-action: none;
    cursor: grab;
    -webkit-tap-highlight-color: transparent;
}

/* La misma medida que la del panel: son la misma pieza en dos hojas hermanas, y tenerlas de dos
   anchos distintos no dice nada. */
.mapa2-ficha-handle span {
    width: 32px;
    height: 4px;
    border-radius: 2px;
    background: var(--ic-icon-muted);
}

/* ── Cabecera ─────────────────────────────────────────────────────────────── */
.mapa2-ficha-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 8px 0 16px;
    touch-action: none;
}

/* La cabecera entera alterna la altura: el objetivo táctil es la fila, no una tira de 12px. */
.mapa2-ficha-toggle {
    flex: 1 1 auto;
    min-width: 0;
    min-height: var(--ic-touch-min);
    display: flex;
    flex-direction: column;
    /* `stretch` EXPLÍCITO, y no por omisión: el navegador pone `align-items: center` a todos los
       `<button>`, así que al convertir éste en contenedor flex sus hijos dejaban de estirarse a lo
       ancho. El título —una línea con `nowrap` y el nombre de los productos dentro— se quedaba con
       su ancho natural de 613px dentro de una caja de 319 y se DESBORDABA POR LOS DOS LADOS: se
       leía «…uática Rosa + (3) Mesa…», cortado por la izquierda y sin puntos suspensivos, porque
       el `overflow:hidden` recorta contra su propia caja de 613, no contra la del padre.
       Visto en la app con datos reales; con un título corto no se nota. */
    align-items: stretch;
    justify-content: center;
    gap: 2px;
    padding: 6px 0;
    border: 0;
    background: transparent;
    color: var(--ic-text);
    text-align: left;
    cursor: pointer;
}

.mapa2-ficha-titulo {
    /* Con `stretch` arriba ya heredan el ancho del botón; esto los blinda de un contenedor que
       vuelva a dimensionarse por contenido. */
    min-width: 0;
    font-size: var(--ic-text-base);
    font-weight: 700;
    line-height: 1.25;
    color: var(--ic-text);
    /* Una línea y elipsis: el título lleva los productos de la renta y puede ser largo. Dos líneas
       cambiarían el alto del asomo, que es un número fijo. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-ficha-sub {
    min-width: 0;
    font-size: var(--ic-text-sm);
    line-height: 1.3;
    color: var(--ic-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-ficha-x {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--ic-touch-min);
    height: var(--ic-touch-min);
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--ic-muted);
    cursor: pointer;
}

.mapa2-ficha-x:hover { background: rgba(var(--lc-neutral-rgb), 0.18); color: var(--ic-text); }

/* ── Aviso de la puerta ───────────────────────────────────────────────────── */
/* Dentro del asomo a propósito: es lo único de esta ficha que puede evitar el viaje entero. */
.mapa2-ficha-aviso {
    flex: 0 0 auto;
    padding: 0 16px 4px;
}

/* ── Fila de acciones ─────────────────────────────────────────────────────── */
/* También dentro del asomo: «Cómo llegar» es lo que más se pulsa y no puede pedir que abras nada.
   Se desplaza en horizontal cuando no caben, que es mejor que apilarlas y empujar el mapa. */
.mapa2-ficha-acciones {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    padding: 4px 16px 12px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    /* El desplazamiento de esta tira es suyo: sin esto, llegar a su extremo arrastraba la ficha. */
    overscroll-behavior-x: contain;
    /* Y su EJE es suyo. Lo heredaría del efectivo del ancestro, pero escrito es lo que impide que
       alguien vuelva a poner `none` arriba sin enterarse de que deja esta tira muerta al tacto —
       que es exactamente lo que pasó. Lo vigila `El_carril_de_acciones_conserva_su_eje`. */
    touch-action: pan-x;
}

.mapa2-ficha-acciones::-webkit-scrollbar { display: none; }

.mapa2-ficha-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* 48 y no 40. Es la fila que MÁS se pulsa de toda la pantalla —«Cómo llegar» desde la
       camioneta— y estaba por debajo del mínimo de la casa y del de Material a la vez. Sube el
       asomo, y por eso sus dos números se vuelven a medir en el banco. */
    min-height: var(--ic-touch-min);
    padding: 0 14px;
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: 999px;
    background: var(--ic-surface-2);
    color: var(--ic-text);
    font-family: var(--ic-font);
    font-size: var(--ic-text-sm);
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}

.mapa2-ficha-btn .mud-icon-root { font-size: 18px; }

.mapa2-ficha-btn:active { transform: translateY(1px); }

.mapa2-ficha-btn--primary {
    border-color: transparent;
    background: var(--ic-primary);
    color: var(--ic-on-primary);
}

.mapa2-ficha-btn--accent {
    border-color: rgba(var(--lc-accent-rgb), 0.45);
    background: rgba(var(--lc-accent-rgb), 0.16);
}

/* ── Cuerpo ───────────────────────────────────────────────────────────────── */
.mapa2-ficha-body {
    flex: 1 1 auto;
    /* Sin esto un hijo largo —la lista de paradas— impide que el cuerpo ceda, y el recorte de la
       ficha se lleva por delante el asa, que es la zona de arrastre. */
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* El desplazamiento de la lista no arrastra la página detrás. */
    overscroll-behavior: contain;
    touch-action: pan-y;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 4px 16px 12px;
    border-top: var(--ic-hairline-w) solid var(--ic-border);
}

.mapa2-ficha-dato {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: var(--ic-text-sm);
    line-height: 1.4;
    color: var(--ic-text);
}

.mapa2-ficha-dato .mud-icon-root {
    font-size: 18px;
    flex-shrink: 0;
    margin-top: 1px;
    color: var(--ic-muted);
}

.mapa2-ficha-dato a { color: var(--ic-primary); text-decoration: none; }

.mapa2-ficha-orden {
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    background: rgba(var(--lc-neutral-rgb), 0.2);
    font-size: var(--ic-text-xs);
    font-weight: 700;
    color: var(--ic-muted);
}

/* ── Lista de paradas del mismo domicilio ─────────────────────────────────── */
.mapa2-ficha-lista {
    display: flex;
    flex-direction: column;
    border-top: var(--ic-hairline-w) solid var(--ic-border);
}

.mapa2-ficha-parada {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: var(--ic-touch-min);
    padding: 8px 0;
    border: 0;
    border-bottom: var(--ic-hairline-w) solid var(--ic-border);
    background: transparent;
    color: var(--ic-text);
    font-family: var(--ic-font);
    font-size: var(--ic-text-sm);
    text-align: left;
    cursor: pointer;
}

.mapa2-ficha-parada:last-child { border-bottom: 0; }

/* Lo hecho se marca con la MISMA palomita que el pin y no atenuando la fila: al 55 % se lee como
   deshabilitada cuando sigue abriendo su renta. `is-cerrada` se conserva como gancho del marcado. */
.mapa2-ficha-parada-check {
    margin-left: auto;
    font-weight: 700;
    color: var(--ic-muted);
}

.mapa2-ficha-parada-hora {
    flex: 0 0 auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.mapa2-ficha-parada-tipo {
    flex: 0 0 auto;
    font-size: var(--ic-text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ic-muted);
}

.mapa2-ficha-parada-quien {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Más aire a pantalla completa ─────────────────────────────────────────── */
/* Con ~490px y el contenido de una parada simple sobra sitio. No se rellena con datos que ya
   tienen su sitio en la página de detalle: se reparte lo que hay. */
.mapa2-root.is-ficha-full .mapa2-ficha-body {
    gap: 16px;
    padding: 12px 16px 16px;
}

.mapa2-root.is-ficha-full .mapa2-ficha-dato { font-size: var(--ic-text-md); }

.mapa2-root.is-ficha-full .mapa2-ficha-parada { padding: 12px 0; }

/* ── Escritorio ───────────────────────────────────────────────────────────── */
/* Ahí no hay gesto —el motor se autoexcluye por encima de 1023px— así que tampoco hay asa: una
   tira que invita a arrastrar algo que no se arrastra es peor que no tenerla. La ficha abre a su
   altura completa acotada, con scroll, y se cierra con la X. */
html:not([data-chrome="app"]) .mapa2-ficha-handle { display: none; }

/* El carril se NEUTRALIZA, y hay que hacerlo explícito: aquí no hay gesto, así que un
   desplazamiento heredado del móvil dejaría la ficha fuera de pantalla sin que nada lo
   delate. Se queda posicionado y cubriendo el cuerpo —es el bloque contenedor de la caja—,
   sólo deja de moverse. Lo vigila `FichaDelPinTests`. */
html:not([data-chrome="app"]) .mapa2-ficha-carril { transform: none; }

html:not([data-chrome="app"]) .mapa2-ficha-host {
    /* Vuelve a colgar del borde de ABAJO: sin gesto, la caja es la que se dimensiona sola. */
    top: auto;
    height: auto;
    max-height: 60%;
    /* Aquí la ficha SÍ termina donde empieza la fila del calendario, porque aquí esa fila no
       se esconde: en escritorio no hay barra de navegación y ella es la única barra de
       acciones que hay —«Hoy», «Nueva», modo ruta, y para el rol Empleado «Vista» y
       «Filtros», que no viven en ningún otro sitio—. */
    bottom: var(--mapa2-fila-h, 0px);
}

html:not([data-chrome="app"]) .mapa2-ficha-head { touch-action: auto; }

/* ==========================================================================
   Modo campo — una sola tarea: llegar a la próxima parada

   Venía de una página entera (MapaChofer) con su propia cabecera y su propio mapa. Ahora es la
   TARJETA dentro de la lente mapa del calendario: la cabecera, la franja de días y el mapa son los
   del calendario, y cambiar de lente no mueve un solo control de sitio.
   ========================================================================== */

/* Se ancla abajo como el sheet del admin y por los mismos motivos: el pulgar llega, y el mapa
   —que es el contexto— se queda arriba.

   El tope: medida en banco a 375×812, la tarjeta plegada ocupa ~470px con el aviso de ubicación
   dudosa y ~400 sin él. El 68 % del cuerpo (≈420) cubre el caso normal sin scroll y deja el caso
   largo con un poco; bajarlo más dejaba «No había nadie» fuera de pantalla, que es justo el botón
   que no se puede esconder. */
.chofer-card-host {
    position: absolute;
    left: 0;
    right: 0;
    bottom: var(--ic-bottom-nav-height, 0px);
    /* 1040 y no 1200: la fila inferior del calendario —«Hoy», el conmutador de lente, vista y
       filtros— vive en 1100, y esta tarjeta es OPACA. Con 1200 se la tragaba entera y el chofer
       se quedaba sin salida del mapa. Por encima de los flotantes del mapa (1000/1001) y por
       debajo de la fila, que es lo único que tiene que poder tocarse siempre. */
    z-index: 1040;
    max-height: 68%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    border-radius: var(--ic-radius-lg) var(--ic-radius-lg) 0 0;
    box-shadow: var(--ic-shadow-up);
    background: var(--ic-surface);
}

/* Abierta la lista, el mapa pierde casi todo: se le deja más sitio a cambio de que siga viéndose. */
.chofer-card-host.is-abierta { max-height: 82%; }

/* El sheet del admin publica su alto para que los flotantes se anclen. La tarjeta hace lo mismo
   con su tope, que es lo único que se puede saber sin medir en JS. */
/* El alto del sheet en modo campo se declara junto a los snaps, arriba del archivo: allí se
   ve que comparte especificidad con ellos y por qué tiene que ir antes. */

.chofer-card {
    background: var(--ic-surface);
    border-top: var(--ic-hairline-w) solid var(--ic-border);
    padding: 16px;
    /* 60 de hueco al final, igual que el sheet: la fila inferior del calendario flota por encima y
       sin esto tapa el último botón, que es el que menos se puede tapar. */
    padding-bottom: calc(env(safe-area-inset-bottom, 12px) + 60px);
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex-shrink: 0;
}

/* Tipo de parada junto al «3 de 7»: entregar y recoger se hacen al revés, y el chofer necesita
   saber cuál es ANTES de bajarse. */
.chofer-card-tipo {
    margin-left: auto;
    font-size: var(--ic-text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ic-muted);
}

.chofer-eta-hora { font-weight: 700; color: var(--ic-text); }

/* Aviso de ubicación poco fiable. Ámbar: es una duda, no un error. */
.chofer-card-ubicdudosa {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    padding: 8px 10px;
    border-radius: var(--ic-radius-sm);
    background: rgba(var(--lc-warn-rgb), 0.14);
    color: var(--lc-warn);
    font-size: var(--ic-text-sm);
    line-height: 1.35;
}

.chofer-card-ubicdudosa .mud-icon-root { font-size: 16px; flex-shrink: 0; margin-top: 1px; }

.chofer-vacio-ico { color: var(--lc-ok); }

.chofer-lista-chevron { color: var(--ic-muted); }

.chofer-card-pos {
    display: flex;
    align-items: baseline;
    gap: 4px;
    color: var(--lc-accent);
    font-weight: 800;
    letter-spacing: 0.05em;
    font-size: var(--ic-text-xs);
    text-transform: uppercase;
}

.chofer-card-pos-num {
    background: var(--ic-brand-gradient);
    color: var(--ic-on-primary);
    padding: 2px 8px;
    border-radius: var(--ic-radius-sm);
    font-size: var(--ic-text-sm);
}

.chofer-card-pos-total { color: var(--ic-muted); }

.chofer-card-titulo {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.chofer-card-renta {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
    font-weight: 700;
}

.chofer-card-cliente {
    font-size: var(--ic-text-2xl);
    font-weight: 800;
    line-height: 1.15;
    color: var(--ic-text);
}

.chofer-card-direccion {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    color: var(--ic-muted);
    font-size: var(--ic-text-md);
    line-height: 1.3;
}

.chofer-card-direccion .mud-icon-root { color: var(--lc-accent) !important; flex-shrink: 0; margin-top: 2px; }

.chofer-card-eta {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--ic-text-sm);
    color: var(--ic-muted);
}

.chofer-eta-num { color: var(--lc-ok); font-weight: 700; }
.chofer-eta-sep { color: var(--ic-text-tertiary); }

.chofer-cta-navegar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 18px;
    min-height: 64px;
    border: 0;
    border-radius: var(--ic-radius-lg);
    background: var(--ic-brand-gradient);
    color: var(--ic-on-primary);
    font-size: var(--ic-text-lg);
    font-weight: 800;
    letter-spacing: 0.05em;
    cursor: pointer;
    box-shadow: 0 8px 20px var(--ic-brand-ring);
    transition: transform 0.1s, box-shadow 0.15s;
}

.chofer-cta-navegar:hover { box-shadow: 0 12px 28px rgba(var(--lc-accent-rgb), 0.5); }
.chofer-cta-navegar:active { transform: scale(0.98); }

.chofer-cta-navegar .mud-icon-root { font-size: 28px !important; }

.chofer-cta-row {
    display: flex;
    gap: 8px;
}

.chofer-cta-sec {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px;
    min-height: 48px;
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-radius: var(--ic-radius-md);
    background: var(--ic-surface-2);
    color: var(--ic-text);
    text-decoration: none;
    font-weight: 700;
    font-size: var(--ic-text-md);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}

.chofer-cta-sec:hover {
    background: rgba(var(--lc-accent-rgb), 0.1);
    border-color: rgba(var(--lc-accent-rgb), 0.35);
}

/* Lo que oficina ya averiguó de la puerta, en la tarjeta de la próxima parada. Un chofer yendo a
   una dirección que ya se sabe vacía es el viaje en falso más caro que esta función previene. */
.chofer-card-presencia {
    display: flex;
    margin: 4px 0 10px;
}

/* Fuera de la fila de Llamar/Navegar y a lo ancho: es una acción de otra naturaleza —constatar un
   hecho— y compartir fila la convertiría en un botón más que se pulsa sin leer. */
.chofer-cta-nadie {
    width: 100%;
    margin-top: 8px;
    border-color: rgba(var(--lc-err-rgb), 0.35);
    color: var(--lc-err);
}

.chofer-cta-nadie:hover {
    background: rgba(var(--lc-err-rgb), 0.1);
    border-color: rgba(var(--lc-err-rgb), 0.5);
}

.chofer-cta-nadie:disabled {
    opacity: 0.6;
    cursor: default;
}

.chofer-card--vacio {
    align-items: center;
    text-align: center;
    padding: 32px 16px;
    gap: 12px;
}

.chofer-card--vacio strong { font-size: var(--ic-text-xl); color: var(--ic-text); }
.chofer-card--vacio span { color: var(--ic-muted); }
/* La lista vacía salió de un fallo: el icono avisa en ámbar y hay un botón para reintentar. */
.chofer-card--error .chofer-vacio-ico { color: var(--cal-urgente, var(--ic-warning, var(--ic-muted))); }

.chofer-card--skel { padding: 16px; }

.chofer-expand {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px;
    background: rgba(var(--ic-surface-rgb), 0.96);
    border: 0;
    border-top: var(--ic-hairline-w) solid var(--ic-border);
    color: var(--lc-accent);
    font-weight: 700;
    cursor: pointer;
    font-size: var(--ic-text-md);
    flex-shrink: 0;
}

.chofer-lista {
    background: rgba(var(--ic-surface-rgb), 0.96);
    border-top: var(--ic-hairline-w) solid var(--ic-border);
    max-height: 50vh;
    overflow-y: auto;
    padding: 8px 12px calc(env(safe-area-inset-bottom, 12px) + 12px);
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex-shrink: 0;
}

/* Misma banda de estado que .mapa2-parada-row y que la tarjeta del calendario. */
.chofer-lista-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px;
    background: rgba(var(--ic-bg-rgb), 0.5);
    background: color-mix(in srgb, var(--ev, transparent) 12%, var(--ic-surface));
    border: var(--ic-hairline-w) solid var(--ic-border);
    border-left: 2px solid var(--ev, var(--ic-border));
    border-radius: var(--ic-radius-md);
    color: inherit;
    cursor: pointer;
    text-align: left;
    min-height: 60px;
}

.chofer-lista-item:hover { border-color: rgba(var(--lc-accent-rgb), 0.4); background: rgba(var(--lc-accent-rgb), 0.06); }

.chofer-lista-num {
    width: 28px;
    height: 28px;
    border-radius: var(--ic-radius-sm);
    background: rgba(var(--lc-accent-rgb), 0.18);
    color: var(--lc-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    font-size: var(--ic-text-xs);
    flex-shrink: 0;
}

.chofer-lista-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.chofer-lista-titulo {
    font-size: var(--ic-text-sm);
    color: var(--ic-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chofer-lista-meta {
    font-size: var(--ic-text-xs);
    color: var(--ic-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chofer-lista-hora {
    font-size: var(--ic-text-xs);
    color: var(--lc-accent);
    font-weight: 700;
}

/* ── Responsive móvil ───────────────────────────────────────────────────── */
/* .mapa2-root ya hereda la altura del layout inmersivo — no recalcular */

html[data-chrome="app"] .mapa2-fab .mud-fab {
    min-width: 56px !important;
    min-height: 56px !important;
}

html[data-chrome="app"] .mapa2-item { min-height: 64px; }

html[data-chrome="app"] .mapa2-tab { min-height: 48px; }

/* ── La línea accionable del panel plegado ───────────────────────────────────
   Plegado, el panel decía tres números y nada que hacer. Esta línea es lo único accionable que
   cabe, y su color dice la gravedad: rojo rompe el viaje, ámbar lo desordena, neutro informa.
   Tinte al 14% con el color como TEXTO — nunca relleno sólido: --lc-err y --lc-warn son claros en
   tema oscuro y oscuros en claro, así que ningún color de texto fijo encima vale para los dos. */
.mapa2-panel-linea {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    margin: 0 var(--ic-space-4) 4px;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--ic-radius-md);
    font-family: inherit;
    font-size: var(--ic-text-md);
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    background: var(--ic-surface-2);
    color: var(--ic-text);
}

.mapa2-panel-linea--err {
    background: color-mix(in srgb, var(--lc-err) 14%, transparent);
    color: var(--lc-err);
}

.mapa2-panel-linea--warn {
    background: color-mix(in srgb, var(--lc-warn) 14%, transparent);
    color: var(--lc-warn);
}

/* El texto cede antes que el verbo: qué se puede hacer no se recorta nunca. */
.mapa2-panel-linea-txt {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mapa2-panel-linea-acc {
    flex: 0 0 auto;
    font-style: normal;
    font-weight: 700;
    font-size: var(--ic-text-sm);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Aquí vivía `.mapa2-panel-hueco`, los 60px que el sheet reservaba dentro para que la fila
   inferior no le tapara el pie. Ya no hace falta: el sheet termina donde empieza la fila
   (`--mapa2-fila-h`), así que no hay nada que esquivar y la fila flota sobre el mapa. */

/* ── El pin, pintado por CSS a partir de --ev ────────────────────────────────
   El color entra por UNA variable, igual que en las tarjetas del calendario. El marcado ya no
   lleva ningún hex: el JS sólo pone `style="--ev: var(--cal-ev-…)"` y de aquí salen el cuerpo, el
   disco y la flecha. Antes el mapa era la única superficie del panel con paleta propia —diez hex
   que no volteaban con el tema y que no coincidían con los del calendario, así que la misma renta
   salía de un color en la tarjeta y de otro en el pin.

   Ninguna de estas reglas lleva !important: el `style` inline del wrapper tiene que ganar. */
.ic-pin-parada .ic-pin-parada-cuerpo {
    fill: var(--ev, var(--cal-ev-default));
    stroke: var(--map-pin-stroke);
    stroke-width: 2.5;
}

/* El disco es el hueco donde vive la flecha: del color de la superficie, no blanco fijo. */
.ic-pin-parada .ic-pin-parada-disco {
    fill: var(--map-pin-stroke);
}

.ic-pin-parada .ic-pin-parada-flecha {
    fill: var(--ev, var(--cal-ev-default));
}

/* Cuántas paradas hay en esta puerta. Ocupa el sitio de la flecha cuando hay más de una: la
   flecha diría «entregar» sobre un domicilio donde también hay que recoger. Va en el color del
   estado, como la flecha, sobre el disco claro. */
.ic-pin-parada .ic-pin-parada-cuantas {
    fill: var(--ev, var(--cal-ev-default));
    font-family: var(--ic-font);
    font-size: var(--ic-text-xs);
    font-weight: 800;
}

/* Una recolección es la gota HUECA: el color del estado pasa del relleno al contorno y al disco, y
   la flecha se invierte sobre él. Antes sólo cambiaban la flechita de 8px y un 18 % de opacidad,
   y el domingo de las recolecciones se leía como «las entregas del sábado otra vez» (2026-09-22).
   La forma se distingue sin depender del color, que además es el del ESTADO y no el del tipo. */
.ic-pin-parada--recogida .ic-pin-parada-cuerpo {
    fill: var(--map-pin-stroke);
    stroke: var(--ev, var(--cal-ev-default));
    stroke-width: 3;
}

.ic-pin-parada--recogida .ic-pin-parada-disco {
    fill: var(--ev, var(--cal-ev-default));
}

.ic-pin-parada--recogida .ic-pin-parada-flecha,
.ic-pin-parada--recogida .ic-pin-parada-cuantas {
    fill: var(--map-pin-stroke);
}

/* Potencial: nadie la ha asignado todavía. Contorno punteado y relleno lavado. */
.ic-pin-parada--potencial .ic-pin-parada-cuerpo {
    fill-opacity: 0.35;
    stroke-dasharray: 3 2.5;
}
