/* ==========================================================================
   IRON ROUTE — EL PLANIFICADOR DE VIAJE

   Sale de un rediseño con cinco críticas independientes de la misma pantalla
   —cabina, jerarquía visual, arquitectura de información, competencia
   (Google Maps / Waze / Hammer / TruckMap) y accesibilidad— y una síntesis.
   Cada número de aquí es una decisión, no una preferencia.

   EL DEFECTO QUE LO ORDENA TODO, medido en 390×844:

       contenido 544 px en una hoja de 464
       «CALCULAR RUTA» empezaba en y=864, en un viewport de 844

   La única acción de la pantalla estaba fuera de la pantalla. Y no por exceso
   de cosas: **el camión estaba dos veces**, ocupando 266 de 464 px — más que
   origen y destino juntos.

   ESCALA TIPOGRÁFICA: base 20, razón 1.25 → 13 · 16 · 20 · 25 · 32.
   Base 20 y no 16 porque la regla de la casa prohíbe bajar de 20 px en modo
   navegación: anclar ahí hace que esta hoja y la pantalla de marcha compartan
   escala sin reescalar nada. En la hoja conviven TRES tamaños: 13, 16 y 20.

   REPARTO DE LA HOJA (móvil, 580 px):
       asa 24 + cabecera 56 + región desplazable 390 + pie 76 + zona segura 34
   ========================================================================== */

:root {
  /* El acento de Iron Route, FIJADO aquí y no heredado de `--accent`.
     Medido: `--accent` resuelve a oro `#D4A84B` en esta pantalla, porque más de
     una hoja lo redefine. El acento de producto de Iron Route es el naranja
     —así está en ecosystem-core— y el botón principal no puede depender de
     quién cargue el último. El oro es el acento COMPARTIDO del ecosistema, para
     superficies de marketing; este es un botón de producto. */
  --ir-naranja: #F58220;
  --ir-naranja-tinta: #0B1F33;   /* 7.3:1 sobre el naranja */

  --ir-plan-alto: 580px;
  --ir-plan-asa: 24px;
  --ir-plan-cab: 56px;
  --ir-plan-pie: 76px;
  --ir-plan-btn: 60px;
  --ir-plan-fila: 56px;
}

/* ══════════════════════════════════════════════════════════════════════════
   1 · LA HOJA: UN SOLO SITIO CON SCROLL, Y EL PIE QUIETO

   Antes la hoja entera tenía `overflow-y: auto`, así que el pie se desplazaba
   con el contenido y podía irse por debajo del borde. Con una única región
   desplazable en medio, el pie se queda pegado abajo y **no se mueve nunca**,
   tenga el contenido el alto que tenga. Es la condición para que el botón
   principal esté siempre a la vista.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-sheet {
  /* `100dvh` y no `100vh`: en Safari `vh` incluye la banda que tapa la barra
     de direcciones, y el pie quedaría debajo de ella. */
  height: min(var(--ir-plan-alto), calc(100dvh - 96px));
  max-height: calc(100dvh - 96px);
  display: flex;
  flex-direction: column;
  overflow: hidden;                /* el scroll vive dentro, no aquí */
  padding-bottom: 0;
}
html.ir-plan-v2 .ir-dir-sheet.ir-sheet-peek { height: 320px; }
html.ir-plan-v2 .ir-dir-sheet.ir-sheet-half { height: min(var(--ir-plan-alto), calc(100dvh - 96px)); }
html.ir-plan-v2 .ir-dir-sheet.ir-sheet-full { height: calc(100dvh - 47px); }

html.ir-plan-v2 .ir-dir-scroll {
  flex: 1 1 auto;
  min-height: 0;                   /* sin esto un hijo flex no encoge y el
                                      `overflow` no llega a activarse nunca */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;    /* al llegar al final no arrastra el mapa */
  padding: 0 16px 8px;
}

html.ir-plan-v2 .ir-dir-handle { flex: 0 0 auto; padding: 10px 0 6px; }
html.ir-plan-v2 .ir-dir-header { flex: 0 0 auto; min-height: var(--ir-plan-cab); padding: 0 16px 8px; }
html.ir-plan-v2 .ir-dir-title { font-size: 16px; }

/* El pie: pegado abajo, con fondo sólido y una línea que lo separa del
   contenido que pasa por detrás. Sin fondo sólido, el texto que se desplaza se
   lee a través del botón. */
html.ir-plan-v2 .ir-dir-calc-wrap {
  flex: 0 0 auto;
  position: sticky;
  bottom: 0;
  z-index: 2;
  padding: 8px 16px;
  padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  background: var(--surface, #0A1B33);
  border-top: 1px solid var(--line, #1E3A5F);
}
html.ir-plan-v2 .ir-dir-actions {
  flex: 0 0 auto;
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  gap: 8px;
  padding: 8px 16px;
  padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  background: var(--surface, #0A1B33);
  border-top: 1px solid var(--line, #1E3A5F);
}

/* ══════════════════════════════════════════════════════════════════════════
   2 · EL BOTÓN PRINCIPAL

   Estaba en un degradado azul `#3B82F6` que no está en la paleta de Iron
   Route, con letra blanca encima: 2.59:1 medido, cuando el mínimo es 4.5.

   Ahora es el acento de marca `#F58220` PLANO —el color fuerte va al fondo, no
   a la letra— con tinta casi negra encima: **7,3:1**. Y 60 px de alto, que
   aloja una etiqueta de 20 px con aire suficiente y deja 12 px de margen sobre
   el mínimo táctil con guante.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-btn-calc,
html.ir-plan-v2 #irDirNavigate {
  width: 100%;
  min-height: var(--ir-plan-btn);
  border: 0;
  border-radius: 14px;
  background: var(--ir-naranja);
  background-image: none;
  color: var(--ir-naranja-tinta);        /* 7.3:1 medido */
  font-family: 'Syne', system-ui, sans-serif;
  font-weight: 700;
  font-size: 20px;
  letter-spacing: .02em;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: filter .15s ease;
}
html.ir-plan-v2 .ir-dir-btn-calc:hover,
html.ir-plan-v2 #irDirNavigate:hover { filter: brightness(1.06); }
html.ir-plan-v2 .ir-dir-btn-calc:active { filter: brightness(.94); }

/* Ocupado: MISMO alto, para que nada salte bajo el pulgar mientras se calcula. */
html.ir-plan-v2 .ir-dir-btn-calc.ir-dir-btn-ocupado {
  background: var(--surface-2, #10294A);
  color: var(--text-muted, #9FB0C3);
  cursor: progress;
}
html.ir-plan-v2 .ir-dir-btn-calc[disabled]:not(.ir-dir-btn-ocupado) {
  background: var(--surface-2, #10294A);
  color: var(--text-muted, #9FB0C3);
  cursor: not-allowed;
}

html.ir-plan-v2 #irDirShareRoute {
  min-height: var(--ir-plan-btn);
  min-width: 60px;
  border-radius: 14px;
  border: 1px solid var(--line, #1E3A5F);
  background: transparent;
  color: inherit;
  font-size: 16px;
}

/* ══════════════════════════════════════════════════════════════════════════
   4 · EL CHIP DEL CAMIÓN — 56 px en lugar de 266

   Lo que ocurre en cada apertura es VERIFICAR: «¿estoy ruteando con el 53 pies
   o con algo por defecto?». Eso cuesta 56 px. Editar ocurre entre cero y dos
   veces al año, y ahora vive en su propia hoja.

   Las cifras van en monoespaciada con `tabular-nums`: es lo que impide
   confundir 0 con O y 1 con l de un vistazo, y lo que hace que dos camiones
   guardados se comparen alineados.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-chip {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: var(--ir-plan-fila);
  margin: 16px 0 0;
  padding: 8px 12px;
  border-radius: 12px;
  border: 1px solid var(--line, #1E3A5F);
  background: var(--surface-2, #10294A);
  color: inherit;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
html.ir-plan-v2 .ir-dir-chip:hover { background: rgba(127,127,127,.16); }
html.ir-plan-v2 .ir-dir-chip-ic { font-size: 22px; line-height: 1; flex: 0 0 auto; }
html.ir-plan-v2 .ir-dir-chip-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
html.ir-plan-v2 .ir-dir-chip-et {
  font-size: 13px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; opacity: .72;
}
html.ir-plan-v2 .ir-dir-chip-val {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 16px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html.ir-plan-v2 .ir-dir-chip-mas { flex: 0 0 auto; font-size: 13px; font-weight: 700; opacity: .8; }

/* Sin confirmar: borde de aviso Y texto que lo dice. Nunca solo color — y el
   botón de calcular SIGUE funcionando. Un conductor bloqueado abre Google
   Maps, que no sabe nada del puente: bloquear no es seguridad, es perder al
   usuario justo cuando más lo necesita. */
html.ir-plan-v2 .ir-dir-chip-aviso {
  border: 2px solid var(--warning, #F5A623);
  padding: 7px 11px;
}

/* ══════════════════════════════════════════════════════════════════════════
   5 · LA HOJA «MI CAMIÓN» — donde el editor sí tiene sitio
   ══════════════════════════════════════════════════════════════════════════ */
.ir-camion-hoja {
  position: fixed;
  inset: 0;
  z-index: 1500;
  display: none;
  background: rgba(3, 13, 28, .62);
  backdrop-filter: blur(3px);
}
.ir-camion-hoja.abierta { display: block; }

.ir-camion-hoja .ir-camion-cab,
.ir-camion-hoja .ir-camion-cuerpo,
.ir-camion-hoja .ir-camion-nota {
  background: var(--surface, #0A1B33);
  color: var(--text, #F5F7FA);
}
.ir-camion-hoja .ir-camion-cab {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between;
  min-height: 64px; padding: 8px 12px 8px 20px;
  border-bottom: 1px solid var(--line, #1E3A5F);
}
.ir-camion-tit { margin: 0; font-family: 'Syne', sans-serif; font-size: 20px; font-weight: 700; }
.ir-camion-x {
  width: 48px; height: 48px; border: 0; border-radius: 50%;
  background: rgba(127,127,127,.16); color: inherit;
  font-size: 26px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.ir-camion-cuerpo {
  position: absolute; top: 64px; left: 0; right: 0; bottom: 0;
  overflow-y: auto;
  padding: 16px 20px calc(96px + env(safe-area-inset-bottom, 0px));
}
.ir-camion-nota {
  position: absolute; left: 0; right: 0; bottom: 0;
  margin: 0; padding: 14px 20px calc(14px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line, #1E3A5F);
  font-size: 13px; line-height: 1.4; opacity: .8;
}

/* Aquí los campos del camión dejan de ser cajas de 60×48 con letra de 12. */
.ir-camion-cuerpo .ir-dir-ts-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
.ir-camion-cuerpo .ir-dir-ts-item {
  display: flex; align-items: center; gap: 10px;
  min-height: 56px; font-size: 16px;
}
.ir-camion-cuerpo .ir-dir-ts-select,
.ir-camion-cuerpo .ir-dir-ts-input,
.ir-camion-cuerpo #pcSel {
  flex: 1 1 auto; min-width: 0;
  min-height: 56px; padding: 0 12px;
  border-radius: 12px;
  border: 1px solid var(--line, #1E3A5F);
  background: var(--surface-2, #10294A);
  color: inherit;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 18px;
  font-variant-numeric: tabular-nums;
}
.ir-camion-cuerpo .ir-dir-ts-select,
.ir-camion-cuerpo #pcSel { font-family: 'DM Sans', system-ui, sans-serif; }
.ir-camion-cuerpo #pcGuardar {
  width: 100%; min-height: 56px; margin-top: 12px;
  border-radius: 12px; border: 1px solid var(--line, #1E3A5F);
  background: transparent; color: inherit;
  font-family: 'DM Sans', system-ui, sans-serif; font-size: 16px; font-weight: 600;
  cursor: pointer;
}
.ir-camion-cuerpo #pcNota {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px; line-height: 1.45; opacity: .78; margin: 12px 0 0;
}

@media (min-width: 900px) {
  .ir-camion-hoja .ir-camion-cab,
  .ir-camion-hoja .ir-camion-cuerpo,
  .ir-camion-hoja .ir-camion-nota {
    left: 50%; transform: translateX(-50%); width: 480px; max-width: calc(100vw - 32px);
  }
  .ir-camion-hoja .ir-camion-cab { top: 40px; border-radius: 16px 16px 0 0; }
  .ir-camion-hoja .ir-camion-cuerpo { top: 104px; bottom: 120px; }
  .ir-camion-hoja .ir-camion-nota { bottom: 40px; border-radius: 0 0 16px 16px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   6 · EL FOCO, SIEMPRE VISIBLE

   Con teclado, con conmutador, o con un lector de pantalla, no saber dónde
   está el foco es no poder usar la pantalla.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-sheet :focus-visible,
.ir-camion-hoja :focus-visible {
  outline: 3px solid var(--ir-naranja);
  outline-offset: 2px;
  border-radius: 12px;
}

/* ══════════════════════════════════════════════════════════════════════════
   7 · ESCRITORIO — el mismo reparto, más sitio
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 900px) {
  html.ir-plan-v2 .ir-dir-sheet {
    height: auto !important;
    max-height: calc(100vh - 28px);
  }
  html.ir-plan-v2 .ir-dir-handle { display: none; }
  html.ir-plan-v2 .ir-dir-calc-wrap,
  html.ir-plan-v2 .ir-dir-actions { padding: 16px; }
  html.ir-plan-v2 .ir-dir-btn-calc,
  html.ir-plan-v2 #irDirNavigate { min-height: 56px; font-size: 18px; }
  html.ir-plan-v2 .ir-dir-field { font-size: 17px; min-height: 52px; }
  html.ir-plan-v2 .ir-dir-swap { width: 44px; height: 44px; min-width: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  html.ir-plan-v2 .ir-dir-sheet,
  html.ir-plan-v2 .ir-dir-btn-calc { transition: none; }
}



/* ══════════════════════════════════════════════════════════════════════════
   3 · LA ESPINA — origen, paradas y destino en UNA sola pieza

   Antes eran dos cajas sueltas, cada una con su borde, unidas por un guion de
   2 px que no llegaba a ninguna parte. **Dos cajas con borde se leen como dos
   cosas.** Un viaje es una cosa con dos extremos.

   Uber, Google Maps y Waze lo resuelven igual, y no por copiarse: lo que
   comparte un contorno se lee como un grupo (conexión uniforme). El raíl
   vertical que baja del origen al destino dice «esto es un trayecto» sin
   gastar una palabra.

   De ahí salen las decisiones de composición:
     · Los campos PIERDEN su borde. El contorno lo pone la tarjeta. Que cada
       campo lleve el suyo es lo que hacía que esto pareciera un formulario de
       alta y no un mapa.
     · Los separadores van sangrados 56 px por la izquierda, hasta donde
       empieza el texto — así el raíl los cruza sin cortarse.
     · Sangría de 56 px = 16 de padding + 24 de icono + 16 de hueco. Todo en
       esta hoja cae en la misma rejilla de 4.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-esp {
  position: relative;
  border: 1px solid var(--line, #1E3A5F);
  border-radius: 16px;
  background: var(--surface-2, #10294A);
  overflow: hidden;
}

html.ir-plan-v2 .ir-esp-fila {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: var(--ir-plan-fila);
  padding: 0 16px;
  background: transparent;
  border: 0;
  color: inherit;
  font-family: inherit;
  text-align: left;
}
/* El separador, sangrado hasta el texto. De borde a borde cortaría el raíl. */
html.ir-plan-v2 .ir-esp-fila + .ir-esp-fila::before,
html.ir-plan-v2 .ir-esp-paradas + .ir-esp-fila::before,
html.ir-plan-v2 .ir-esp-paradas .ir-esp-fila::before {
  content: '';
  position: absolute;
  left: 56px; right: 0; top: 0;
  height: 1px;
  background: var(--line, #1E3A5F);
  opacity: .85;
}

/* EL RAÍL. Baja por el centro de la columna de iconos y une los extremos.
   `top`/`bottom` en 28 px = medio alto de fila: empieza en el centro del punto
   de origen y termina en el centro del pin de destino, no en los bordes de la
   tarjeta. */
html.ir-plan-v2 .ir-esp::before {
  content: '';
  position: absolute;
  left: 27px;
  top: 28px;
  bottom: 84px;                 /* deja fuera la fila de «Añadir parada» */
  width: 2px;
  border-radius: 1px;
  background: linear-gradient(to bottom,
              var(--line, #1E3A5F) 0 6px,
              transparent 6px 10px) repeat-y;
  background-size: 2px 10px;    /* punteado: el trayecto no está calculado aún */
  opacity: .9;
  pointer-events: none;
}
html.ir-plan-v2 .ir-esp.ir-esp-sin-add::before { bottom: 28px; }

html.ir-plan-v2 .ir-esp-marca {
  position: relative;
  z-index: 1;
  flex: 0 0 24px;
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  /* Fondo del propio panel para que el raíl pase POR DETRÁS y no cruce el
     icono. Un raíl que atraviesa el pin es un raíl mal dibujado. */
  background: var(--surface-2, #10294A);
  border-radius: 50%;
  color: var(--text-muted, #9FB0C3);
}
html.ir-plan-v2 .ir-esp-origen .ir-esp-marca { color: var(--success, #10B981); }
html.ir-plan-v2 .ir-esp-destino .ir-esp-marca { color: var(--text, #F5F7FA); }

/* Los campos, sin borde ni fondo: el contorno es la tarjeta. */
html.ir-plan-v2 .ir-dir-field {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--ir-plan-fila);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text, #F5F7FA);
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -.01em;
}
html.ir-plan-v2 .ir-dir-field:focus { outline: none; }
html.ir-plan-v2 .ir-dir-field::placeholder {
  color: var(--text-muted, #9FB0C3);
  font-weight: 400;
  opacity: .85;
}
/* La fila entera se ilumina al enfocar, no solo el campo: el objetivo visual
   es la fila, que es lo que el dedo toca. */
html.ir-plan-v2 .ir-esp-fila:focus-within { background: rgba(127, 127, 127, .10); }

/* Intercambiar: flotante, centrado sobre el separador entre las dos filas.
   Ahí es donde actúa y ahí es donde se busca. */
html.ir-plan-v2 .ir-esp-swap {
  position: absolute;
  top: var(--ir-plan-fila);
  right: 12px;
  transform: translateY(-50%);
  z-index: 2;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--line, #1E3A5F);
  background: var(--surface, #0A1B33);
  color: var(--text-muted, #9FB0C3);
  cursor: pointer;
  transition: transform .18s cubic-bezier(.4,0,.2,1), color .15s;
}
html.ir-plan-v2 .ir-esp-swap:hover { color: var(--text, #F5F7FA); }
html.ir-plan-v2 .ir-esp-swap:active { transform: translateY(-50%) rotate(180deg); }

/* «Añadir parada» DENTRO de la tarjeta, con la misma sangría.
   Fuera y con borde punteado se leía como una zona de arrastre — que es lo que
   significa un borde punteado en todos los sistemas de diseño que existen. */
html.ir-plan-v2 .ir-esp-add {
  cursor: pointer;
  color: var(--text-muted, #9FB0C3);
  font-size: 16px;
  font-weight: 600;
  min-height: 52px;
}
html.ir-plan-v2 .ir-esp-add:hover { background: rgba(127,127,127,.10); color: var(--text, #F5F7FA); }
html.ir-plan-v2 .ir-esp-add .ir-esp-marca { background: transparent; }

html.ir-plan-v2 .ir-esp-paradas:empty { display: none; }
html.ir-plan-v2 .ir-esp-quitar {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--text-muted, #9FB0C3);
  cursor: pointer;
}
html.ir-plan-v2 .ir-esp-quitar:hover { background: rgba(239,68,68,.14); color: var(--error, #EF4444); }
html.ir-plan-v2 .ir-dir-stop-field {
  flex: 1 1 auto; min-width: 0; min-height: var(--ir-plan-fila);
  padding: 0; border: 0; background: transparent; color: inherit;
  font-family: 'DM Sans', system-ui, sans-serif; font-size: 18px; font-weight: 500;
}

/* ══════════════════════════════════════════════════════════════════════════
   8 · RECIENTES — filas con la misma rejilla que la espina

   Mismo ritmo: icono de 24 en una columna de 56, texto en dos líneas, y nada
   de bordes. Si las listas de una pantalla no comparten rejilla, la pantalla
   se lee como tres pantallas pegadas.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-recientes { margin-top: 20px; }
html.ir-plan-v2 .ir-dir-rec-tit {
  margin: 0 0 4px;
  padding-left: 4px;
  font-size: 12px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted, #9FB0C3);
}
html.ir-plan-v2 .ir-dir-rec-item {
  display: flex; align-items: center; gap: 16px;
  width: 100%; min-height: var(--ir-plan-fila);
  padding: 4px 12px 4px 4px;
  border: 0; border-radius: 12px;
  background: transparent; color: inherit;
  text-align: left; cursor: pointer; font-family: inherit;
}
html.ir-plan-v2 .ir-dir-rec-item:hover { background: rgba(127,127,127,.12); }
html.ir-plan-v2 .ir-dir-rec-ic {
  flex: 0 0 40px; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: rgba(127,127,127,.14);
  color: var(--text-muted, #9FB0C3);
}
html.ir-plan-v2 .ir-dir-rec-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
html.ir-plan-v2 .ir-dir-rec-n {
  font-size: 16px; font-weight: 600; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html.ir-plan-v2 .ir-dir-rec-d {
  font-size: 13px; color: var(--text-muted, #9FB0C3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html.ir-plan-v2 .ir-dir-rec-vacio {
  padding: 10px 4px; font-size: 13px; line-height: 1.5;
  color: var(--text-muted, #9FB0C3);
}

/* ══════════════════════════════════════════════════════════════════════════
   9 · LOS ICONOS, Y POR QUÉ NO SON EMOJI

   Un emoji lo dibuja el sistema operativo: el mismo 🚛 es un camión rojo en
   iOS, azul en Android y una caja vacía sin la fuente. No hereda el color, no
   tiene control de trazo, y un lector de pantalla lo lee («camión de reparto»
   donde debería decir «tipo de vehículo»).

   Y el problema visual que se veía sin saber nombrarlo: un emoji es un dibujo
   RELLENO, así que a 22 px pesa el doble que una línea de 22 px. Por eso los
   pesos de la pantalla no cuadraban con nada.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-ic,
.ir-camion-hoja .ir-ic { display: block; flex: 0 0 auto; }

html.ir-plan-v2 .ir-dir-close {
  width: 40px; height: 40px; min-width: 40px;
  border-radius: 50%;
  border: 0;
  background: rgba(127,127,127,.14);
  color: var(--text-muted, #9FB0C3);
  display: flex; align-items: center; justify-content: center;
}
html.ir-plan-v2 .ir-dir-close:hover { background: rgba(127,127,127,.24); color: var(--text, #F5F7FA); }

/* ══════════════════════════════════════════════════════════════════════════
   10 · EL AIRE Y EL TÍTULO

   La hoja tenía todo pegado al mismo ritmo, sin respiración, y el título a
   16 px competía con los campos a 20. Un título que pesa menos que su
   contenido no es un título.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-header { padding: 0 16px 14px; align-items: center; }
html.ir-plan-v2 .ir-dir-title {
  font-family: 'Syne', system-ui, sans-serif;
  font-size: 22px; font-weight: 700; letter-spacing: -.01em;
}
html.ir-plan-v2 .ir-dir-handle-bar {
  width: 40px; height: 4px; border-radius: 999px;
  background: var(--line, #1E3A5F);
}
html.ir-plan-v2 .ir-dir-chip { margin-top: 20px; }

/* ══════════════════════════════════════════════════════════════════════════
   11 · CORRECCIONES DE LA PRIMERA PASADA VISUAL

   Cosas que solo se ven mirando la pantalla, no midiéndola. Van aquí con lo
   que se vio, para que la próxima vez se busque antes.
   ══════════════════════════════════════════════════════════════════════════ */

/* «Cambiar ›» partía en dos líneas y el chevron caía solo debajo. Un rótulo de
   acción partido en dos deja de leerse como un botón. */
html.ir-plan-v2 .ir-dir-chip-mas {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  color: var(--text-muted, #9FB0C3);
}
html.ir-plan-v2 .ir-dir-chip-ic {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: rgba(127,127,127,.14);
  color: var(--text-muted, #9FB0C3);
  flex: 0 0 40px;
}
html.ir-plan-v2 .ir-dir-chip { gap: 14px; padding: 8px 14px; }
html.ir-plan-v2 .ir-dir-chip-val { font-size: 15px; letter-spacing: -.01em; }
html.ir-plan-v2 .ir-dir-chip-et { font-size: 12px; letter-spacing: .08em; }

/* EL RAÍL. En la primera pasada era un punteado tan tenue que no unía nada —
   y un raíl que no se ve no cumple su único trabajo, que es decir «esto es un
   trayecto» de un vistazo. Ahora: sólido entre origen y destino, y punteado
   solo por debajo, donde el viaje aún no está definido. */
html.ir-plan-v2 .ir-esp::before {
  left: 27px;
  top: 34px;
  bottom: auto;
  height: calc(var(--ir-plan-fila) - 12px);
  width: 2px;
  background: var(--line, #1E3A5F);
  background-size: auto;
  opacity: 1;
}
/* El tramo punteado hacia «Añadir parada»: lo que todavía no es viaje. */
html.ir-plan-v2 .ir-esp::after {
  content: '';
  position: absolute;
  left: 27px;
  top: calc(var(--ir-plan-fila) * 2 - 6px);
  height: 34px;
  width: 2px;
  background-image: linear-gradient(var(--line, #1E3A5F) 50%, transparent 50%);
  background-size: 2px 8px;
  opacity: .8;
  pointer-events: none;
}
html.ir-plan-v2 .ir-esp.ir-esp-sin-add::after { display: none; }

/* El icono de origen y el de destino, más presentes: son las dos anclas de la
   pantalla y estaban al mismo peso que el texto de relleno. */
html.ir-plan-v2 .ir-esp-origen .ir-esp-marca { color: var(--success, #10B981); }
html.ir-plan-v2 .ir-esp-destino .ir-esp-marca { color: var(--accent-dest, #F5F7FA); }

/* Y el botón principal en versalitas: es la única acción de la pantalla y
   tiene que leerse como tal a un metro, que es la distancia a la que se mira
   un teléfono en un soporte de parabrisas. */
html.ir-plan-v2 .ir-dir-btn-calc {
  text-transform: uppercase;
  font-size: 18px;
  letter-spacing: .04em;
}

/* ══════════════════════════════════════════════════════════════════════════
   12 · EL RAÍL, CON LAS COORDENADAS MEDIDAS

   La primera versión puso el raíl en `left: 27px` a ojo. Medido después:

       centro de las marcas   x = 45   (no 27)
       origen                 y = 29
       destino                y = 85
       «+» de añadir parada   x = 107  ← centrado, no alineado

   O sea que el raíl caía 18 px a la izquierda de los iconos y el «+» ni
   siquiera estaba en la columna. Se veía como tres cosas sueltas, que es
   exactamente lo que el raíl venía a evitar.

   Ahora va de centro a centro: **el raíl nace en el punto de origen y muere en
   el pin de destino**, y los círculos de las marcas lo tapan por encima, así
   que la línea entra y sale sin cortar el icono.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-esp::before {
  left: 44px;
  top: 29px;
  height: 56px;                    /* centro del origen → centro del destino */
  bottom: auto;
  width: 2px;
  border-radius: 1px;
  background: var(--line-fuerte, #35558A);
  opacity: 1;
}
html.ir-plan-v2 .ir-esp::after {
  left: 44px;
  top: 85px;                       /* del destino hacia «Añadir parada» */
  height: 52px;
  width: 2px;
  background-image: linear-gradient(var(--line, #1E3A5F) 50%, transparent 50%);
  background-size: 2px 8px;
  opacity: .9;
}

/* El «+» estaba centrado en la fila en vez de alineado al raíl: un botón
   dentro de una tarjeta hereda el centrado de su hoja de origen. */
html.ir-plan-v2 .ir-esp-add {
  justify-content: flex-start;
  text-align: left;
}

/* Y las marcas tapan el raíl por encima, para que la línea no cruce el icono. */
html.ir-plan-v2 .ir-esp-marca { box-shadow: 0 0 0 4px var(--surface-2, #10294A); }
html.ir-plan-v2 .ir-esp-add .ir-esp-marca { box-shadow: none; }

/* ══════════════════════════════════════════════════════════════════════════
   13 · UNA REGLA MÍA DE HACE DOS HORAS PELEANDO CON ESTA

   El «+» de añadir parada salía centrado en la fila en vez de alineado al
   raíl: medido, su marca en `x = 107` cuando la columna está en `x = 45`.

   La causa no estaba en este archivo. Estaba en `contraste-y-dedo.css`, en el
   arreglo de objetivos táctiles que escribí antes:

       #rp-share-btn, #voice-nav-mute-btn, #irDirClose, #irDirSwap, #irDirAddStop {
         min-width: 48px; min-height: 48px;
         display: inline-flex; justify-content: center;
       }

   Un selector de ID (1,0,0) gana a `html.ir-plan-v2 .ir-esp-add` (0,2,1). Y
   aquel `justify-content: center` era correcto cuando el botón era un «＋» de
   48×48; deja de serlo cuando el botón pasa a ser una fila con texto.

   Lección, y es la misma que ya aparece tres veces en esta base de código:
   **una regla escrita para una forma no sobrevive al cambio de forma.** Se
   corrige aquí con la misma especificidad, y se dice de dónde venía — porque
   dentro de un mes nadie va a adivinar por qué un ID manda sobre una clase.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 #irDirAddStop {
  display: flex;
  justify-content: flex-start;
  width: 100%;
  min-width: 0;
  min-height: 52px;
}
html.ir-plan-v2 #irDirSwap {
  min-width: 44px;
  min-height: 44px;
}
html.ir-plan-v2 #irDirClose {
  min-width: 40px;
  min-height: 40px;
}

/* ══════════════════════════════════════════════════════════════════════════
   14 · Y ME VOLVIÓ A PASAR: UN COLOR FIJO PARA UN SOLO TEMA

   El pin de destino desapareció en tema claro. La regla decía:

       .ir-esp-destino .ir-esp-marca { color: var(--accent-dest, #F5F7FA); }

   `--accent-dest` **no existe** — me lo inventé al escribirla—, así que
   siempre cae al respaldo `#F5F7FA`, que es casi blanco. Sobre la tarjeta
   oscura se veía perfecto; sobre la tarjeta clara del tema claro es invisible.

   Es exactamente el error que ya está documentado tres veces en
   `contraste-y-dedo.css`: **una tinta fija no sirve para un fondo variable.**
   Lo escribí yo mismo y lo volví a hacer treinta minutos después.

   `var(--text)` sí cambia con el tema —medido: `#F5F7FA` en oscuro, `#16233A`
   en claro— y el pin es legible en los dos.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-esp-destino .ir-esp-marca { color: var(--text, #F5F7FA); }

/* ══════════════════════════════════════════════════════════════════════════
   15 · EL ÁREA QUE TOCA EL DEDO NO ES EL CÍRCULO QUE SE VE

   En la pasada visual bajé `#irDirClose` a 40×40 y `#irDirSwap` a 44×44 porque
   dos círculos de 48 se comían la composición. La prueba lo cazó al instante:
   **por debajo del mínimo táctil de 48 px en teléfono.**

   Y era justo el intercambio que las cinco críticas dijeron que no se hiciera:
   «los objetivos de 48 no se tocan a la baja; los píxeles salen del camión
   duplicado, no de encoger dedos». Lo hice igual, por estética.

   La salida no es elegir entre las dos cosas: es separarlas, que es lo que
   hacen iOS y Material desde hace años. **El elemento mide 48 y es
   transparente; el círculo que se ve lo dibuja un `::before` de 40.** El dedo
   acierta un objetivo de 48 y el ojo ve un botón de 40.

   El `::before` va detrás del icono (`z-index: -1` sobre un contexto propio),
   no encima, o taparía el trazo.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 #irDirClose,
html.ir-plan-v2 #irDirSwap {
  position: relative;
  isolation: isolate;
  width: 48px; height: 48px;
  min-width: 48px; min-height: 48px;
  background: transparent;
  border: 0;
  display: flex; align-items: center; justify-content: center;
}
html.ir-plan-v2 #irDirClose::before,
html.ir-plan-v2 #irDirSwap::before {
  content: '';
  position: absolute;
  inset: 4px;                        /* 48 − 8 = 40 visibles */
  z-index: -1;
  border-radius: 50%;
  background: rgba(127, 127, 127, .14);
  transition: background .15s ease;
}
html.ir-plan-v2 #irDirSwap::before {
  inset: 2px;                        /* 48 − 4 = 44 visibles */
  background: var(--surface, #0A1B33);
  box-shadow: inset 0 0 0 1px var(--line, #1E3A5F);
}
html.ir-plan-v2 #irDirClose:hover::before { background: rgba(127,127,127,.26); }
html.ir-plan-v2 #irDirSwap { top: var(--ir-plan-fila); right: 10px; }

/* ══════════════════════════════════════════════════════════════════════════
   16 · Y LOS RÓTULOS VUELVEN A 13 px

   Puse «CAMIÓN» e «IR OTRA VEZ A» a 12 px porque un rótulo en versalitas con
   tracking se ve mejor pequeño. Es cierto y da igual: el suelo de esta hoja
   son 13 px, y lo escribí yo en la especificación seis horas antes.

   Un suelo que se baja «solo para los rótulos» deja de ser un suelo. Y estos
   rótulos son los que dicen QUÉ es cada bloque — el primero que se lee cuando
   no se conoce la pantalla, y el que peor se lee con el sol de frente.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .ir-dir-chip-et,
html.ir-plan-v2 .ir-dir-rec-tit { font-size: 13px; }

/* ══════════════════════════════════════════════════════════════════════════
   17 · PANTALLAS CORTAS (Android 360×640)

   Medido tras devolver los rótulos a 13 px: el contenido del estado vacío pasó
   a 410 px en una región de 384. Veintiséis de más.

   No se toca ni el suelo tipográfico ni un objetivo táctil — que son las dos
   cosas que llevo todo el día defendiendo y no voy a vender por 26 px. Se
   aprieta el AIRE, que es lo que sobra: los huecos entre bloques, no los
   bloques.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-height: 700px) {
  html.ir-plan-v2 .ir-dir-chip { margin-top: 12px; }
  html.ir-plan-v2 .ir-dir-recientes { margin-top: 12px; }
  html.ir-plan-v2 .ir-esp-add { min-height: 48px; }
  html.ir-plan-v2 .ir-dir-rec-vacio { padding: 6px 4px; }
  html.ir-plan-v2 .ir-dir-header { padding-bottom: 10px; }
  html.ir-plan-v2 .ir-esp::after { height: 48px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   18 · Y EL BOTÓN DE INTERCAMBIAR SE CAYÓ AL FONDO DE LA TARJETA

   La regla del bloque 15 puso `position: relative` a los dos botones para
   poder colgarles el `::before` del área táctil. A `#irDirClose` le da igual;
   a `#irDirSwap` lo sacó de su `position: absolute` y lo devolvió al flujo:
   apareció abajo a la izquierda, debajo de «Añadir parada».

   Un `position` compartido entre dos elementos que se posicionan distinto es
   una regla que no debió agruparlos. `absolute` YA crea contexto para el
   `::before`, así que el `relative` sobraba en su caso.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 #irDirSwap {
  position: absolute;
  top: var(--ir-plan-fila);
  right: 10px;
  transform: translateY(-50%);
  z-index: 3;
}
html.ir-plan-v2 #irDirSwap:active { transform: translateY(-50%) rotate(180deg); }

/* ══════════════════════════════════════════════════════════════════════════
   19 · EL ESTADO CON RUTAS — donde se decide el viaje

   Es la pantalla en la que Google y Uber ponen su mejor trabajo, y aquí era
   un carrusel horizontal de tres tarjetas de 200 px dentro de 390 de ancho.
   Se veían 1,8 tarjetas: la tercera ruta —que en la mitad de los casos gana—
   no coexistía JAMÁS con la primera. Y comparar exige simultaneidad; si hay
   que recordar «$192.60» mientras se desliza para leer «$214.30», eso ya no
   es comparar, es aritmética de memoria con el motor encendido.

   Cuatro críticas independientes (comparación · cabina · densidad · acceso) y
   una síntesis llegaron a la misma composición. El presupuesto, comprobado:

       8 padding + 84 banda + 88 fila + 8 + 88 fila + 8 + 88 fila = 372
       de los 390 px de zona desplazable → ASOMAN 18 px de la franja
       siguiente, y ese corte es lo que dice «hay más abajo» sin gastar una
       flecha ni un gesto.

   DOS CANALES QUE NO SE MEZCLAN:
     · identidad de la ruta = riel de 4 px, color Y PATRÓN (sólido / guiones /
       puntos), el mismo trazo que su polilínea en el mapa;
     · selección = borde + relleno + icono check + palabra ELEGIDA.
   Antes las dos peleaban por `border-color`, y como el color de ruta iba en
   línea ganaba por especificidad: el borde de selección no se pintaba NUNCA.

   Y una tinta fija sobre un papel variable ya rompió esta hoja una vez. Aquí
   cada pareja fondo/texto se declara junta y se mide en los dos temas.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 {
  --ir-fila-bg:      #10294A;
  --ir-fila-borde:   #2E4E7A;
  --ir-fila-bg-sel:  #273246;   /* 10 % de #F58220 sobre #10294A */
  --ir-rt-text:      #F5F7FA;   /* 13.61:1 sobre la fila  ✓ AAA */
  --ir-rt-muted:     #9FB0C3;   /*  6.59:1                ✓ AA  */
  --ir-ok:           #10B981;   /*  5.76:1                ✓ AA  */
  --ir-aviso:        #F5A623;   /*  7.20:1                ✓ AAA */
  --ir-ruta-1:       #3B82F6;
  --ir-ruta-2:       #22C55E;
  --ir-ruta-3:       #A855F7;
  --ir-pulsado:      #16345C;
  --ir-esqueleto:    #1E3A5F;
  --ir-naranja-estado: var(--ir-naranja, #F58220);   /* 6.65:1 sobre la hoja ✓ */
  --ir-foco-int:     #030D1C;
  --ir-foco-ext:     #F5F7FA;
}
/* El tema claro NO hereda ni una sola de estas tintas. #9FB0C3 sobre papel
   claro da 2.01:1, y #22C55E da 2.07:1: los dos ilegibles. Se eligen de nuevo,
   emparejados con su papel y medidos. */
html.ir-plan-v2[data-theme="light"] {
  --ir-fila-bg:      #F1F4F8;
  --ir-fila-borde:   #B4C4D6;
  --ir-fila-bg-sel:  #EAE3E0;   /* 10 % de #A8480B sobre #F1F4F8 */
  --ir-rt-text:      #0B1B2E;   /* 15.73:1  ✓ AAA */
  --ir-rt-muted:     #4A5C72;   /*  6.21:1  ✓ AA  */
  --ir-ok:           #065F46;   /*  6.97:1  ✓ AA  */
  --ir-aviso:        #8F4300;   /*  6.41:1  ✓ AA  */
  --ir-ruta-1:       #1D4ED8;
  --ir-ruta-2:       #047857;
  --ir-ruta-3:       #6D28D9;
  /* OJO: `--ir-naranja` NO se toca. Es el acento de marca del producto y es el
     mismo en los dos temas — sobre él va tinta oscura (#0B1F33 = 7.5:1), así
     que el botón principal se lee perfectamente en papel claro.

     Lo que sí cambia es el naranja cuando hace de INDICADOR DE ESTADO: un
     borde, una palabra, un icono. Ahí el color es el mensaje y necesita 3:1
     contra el papel — y #F58220 sobre #F1F4F8 da 2.35:1.

     Es la misma lección que el pendiente E, aplicada antes de que muerda: un
     token con nombre de PIGMENTO usado para dos ROLES distintos deja de ser
     cierto en cuanto hay dos papeles. Así que hay dos tokens, uno por rol.

     Y esto lo cazó una prueba vieja —`planificador.mjs` comprobando que el
     botón principal lleva el acento de marca— que se puso roja al redefinir el
     token entero. La prueba tenía razón y yo no. */
  --ir-naranja-estado: #A8480B;   /* 5.84:1 sobre papel claro ✓ */
  --ir-pulsado:      #E2E8F0;
  --ir-esqueleto:    #DDE4EC;
  --ir-foco-int:     #FFFFFF;
  --ir-foco-ext:     #030D1C;
}

html.ir-plan-v2 .ir-rutas { padding: 8px 0 0; }
/* El contenedor del carrusel sigue existiendo en el marcado; aquí se le quita
   todo lo que lo hacía carrusel. No queda un solo gesto horizontal en la hoja. */
html.ir-plan-v2 .ir-rutas-cuerpo {
  display: block;
  overflow: visible;
  scroll-snap-type: none;
  padding: 0;
  gap: 0;
}
/* SIN `html.ir-plan-v2` DELANTE, Y ESO ES A PROPÓSITO.

   Esta regla nació dentro del planificador y por eso llevaba el prefijo. Al
   usar la misma clase para el anuncio del panel de peajes, el prefijo la
   dejaba fuera: el texto «Peajes: $38.25 en 4 casetas» se habría PINTADO EN
   PANTALLA, debajo del desglose, como si fuera parte del diseño. Una clase
   que se llama «solo lector» y que a veces se ve es peor que no tenerla,
   porque quien la usa da por hecho lo contrario y no lo comprueba.

   Una utilidad no lleva el prefijo del sitio donde se escribió primero. */
.ir-solo-lector {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  /* Nunca `display:none` ni `visibility:hidden`: borrarían el nombre accesible
     de la fila, que es justamente lo que esto existe para dar. */
}

/* ── LA BANDA: la respuesta, antes que la evidencia ──────────────────────── */
html.ir-plan-v2 .ir-rutas-banda {
  position: relative;
  min-height: 84px;
  box-sizing: border-box;
  padding: 12px 12px 12px 16px;
  background: var(--ir-fila-bg);
  border-radius: 12px 12px 0 0;
  /* Pegada SIN HUECO a la fila que recomienda: la adyacencia física resuelve
     gratis el mapeo nombre→fila que antes costaba dos fijaciones oculares y
     un deslizamiento. */
  margin-bottom: 0;
}
html.ir-plan-v2 .ir-rutas-banda::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: -2px; width: 4px;
  border-radius: 2px 0 0 0; background: var(--ir-ruta-1);
}
html.ir-plan-v2 .ir-rutas-banda[data-patron="guiones"]::before { background: var(--ir-ruta-2); }
html.ir-plan-v2 .ir-rutas-banda[data-patron="puntos"]::before  { background: var(--ir-ruta-3); }
html.ir-plan-v2 .ir-ver-l1 {
  margin: 0; font-family: 'DM Sans', sans-serif; font-size: 16px; line-height: 20px;
  font-weight: 500; color: var(--ir-rt-text);
}
html.ir-plan-v2 .ir-ver-l1 b { font-weight: 700; }
html.ir-plan-v2 .ir-ver-l2 {
  margin: 4px 0 0; font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 16px;
  color: var(--ir-rt-muted); display: flex; align-items: center; gap: 4px;
}
html.ir-plan-v2 .ir-ver-l2--aviso { color: var(--ir-aviso); }
html.ir-plan-v2 .ir-ver-l3 {
  margin: 4px 0 0; font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 16px;
  color: var(--ir-rt-muted);
}

/* ── LAS FILAS ───────────────────────────────────────────────────────────── */
html.ir-plan-v2 .ir-rutas-grupo { display: block; }
html.ir-plan-v2 .ir-rt {
  position: relative;
  box-sizing: border-box;
  height: 88px;
  margin-top: 8px;
  background: var(--ir-fila-bg);
  /* El borde es SIEMPRE de 2 px y solo cambia de color. Si engordara al
     seleccionar, la fila crecería, las de abajo saltarían, y el dedo llegaría
     a un objetivo que se movió: con guantes eso es un doble toque garantizado. */
  border: 2px solid var(--ir-fila-borde);
  border-radius: 12px;
  cursor: pointer;
  touch-action: pan-y;          /* el gesto vertical sigue rodando la hoja */
  transition: background-color .14s ease-out, border-color .14s ease-out, transform .08s ease-out;
}
/* La primera fila va pegada a la banda y comparte con ella la esquina. */
html.ir-plan-v2 .ir-rutas-grupo > .ir-rt:first-child {
  margin-top: 0; border-top-left-radius: 0; border-top-right-radius: 0;
}
html.ir-plan-v2 .ir-rt-visual { display: flex; height: 100%; }
html.ir-plan-v2 .ir-rt-riel {
  flex: 0 0 4px; align-self: stretch; border-radius: 2px 0 0 2px;
  background: var(--ir-ruta-1);
}
/* El PATRÓN es el portador NO cromático de la identidad: para uno de cada doce
   hombres el verde y el morado son el mismo gris. Y es el mismo patrón con el
   que se dibuja su polilínea en el mapa. */
html.ir-plan-v2 .ir-rt[data-patron="guiones"] .ir-rt-riel {
  background: repeating-linear-gradient(to bottom, var(--ir-ruta-2) 0 6px, transparent 6px 10px);
}
html.ir-plan-v2 .ir-rt[data-patron="puntos"] .ir-rt-riel {
  background: repeating-linear-gradient(to bottom, var(--ir-ruta-3) 0 2px, transparent 2px 5px);
}
html.ir-plan-v2 .ir-rt-cuerpo {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; justify-content: center;
  padding: 8px 12px;
}
html.ir-plan-v2 .ir-rt-alto { display: flex; align-items: flex-start; gap: 8px; }
html.ir-plan-v2 .ir-rt-izq  { flex: 1 1 0; min-width: 0; }
/* La columna derecha se reserva desde el PRIMER pintado, aunque el peaje
   todavía no haya respondido: si se reservara al llegar la cifra, la fila
   entera se reajustaría bajo el dedo. */
html.ir-plan-v2 .ir-rt-der  { flex: 0 0 auto; min-width: 112px; text-align: right; }

html.ir-plan-v2 .ir-rt-nombre {
  height: 24px; display: flex; align-items: center; gap: 8px;
  font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: 16px; line-height: 24px;
  color: var(--ir-rt-text); white-space: nowrap; overflow: hidden;
}
html.ir-plan-v2 .ir-rt-marca { display: none; align-items: center; gap: 4px; color: var(--ir-naranja-estado); }
html.ir-plan-v2 .ir-rt.elegida .ir-rt-marca { display: inline-flex; }
html.ir-plan-v2 .ir-rt-elegida-txt {
  font-size: 13px; font-weight: 700; letter-spacing: .06em;
}
html.ir-plan-v2 .ir-rt-tiempo {
  height: 20px; margin-top: 4px; white-space: nowrap; overflow: hidden;
  font-size: 16px; line-height: 20px; color: var(--ir-rt-text);
}
html.ir-plan-v2 .ir-rt-delta { font-size: 13px; color: var(--ir-rt-muted); }

/* LA CIFRA REINA. Único elemento de 20 px de toda la hoja.
   Monoespaciada y tabular a propósito: en Syne el «1» mide ≈0.35em y el «0»
   ≈0.62em, así que dos precios en filas contiguas no alinean sus decimales y
   la columna deja de escanearse. Con JetBrains Mono tabular los tres puntos
   decimales caen en la misma abscisa por construcción, y el orden de precios
   se lee con una sacada vertical, sin restar. */
html.ir-plan-v2 .ir-num,
html.ir-plan-v2 .ir-rt-total,
html.ir-plan-v2 .ir-rt-llegada {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}
html.ir-plan-v2 .ir-rt-total {
  height: 24px; display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  font-weight: 700; font-size: 20px; line-height: 24px; letter-spacing: -.01em;
  color: var(--ir-rt-text); white-space: nowrap;
}
html.ir-plan-v2 .ir-rt-llegada {
  height: 20px; margin-top: 4px;
  font-weight: 500; font-size: 13px; line-height: 20px; color: var(--ir-rt-text);
}
html.ir-plan-v2 .ir-rt-detalle {
  margin-top: 4px; height: 16px;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 16px;
  color: var(--ir-rt-muted); white-space: nowrap; overflow: hidden;
}
html.ir-plan-v2 .ir-sep { margin: 0 6px; opacity: .7; }
html.ir-plan-v2 .ir-rt-ok     { color: var(--ir-ok); }
html.ir-plan-v2 .ir-rt-alerta { color: var(--ir-aviso); }
html.ir-plan-v2 .ir-rt-desde  { font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 500; color: var(--ir-aviso); }
html.ir-plan-v2 .ir-rt-cifra.atenuada { color: var(--ir-rt-muted); }
html.ir-plan-v2 .ir-rt.sin-peaje-dato .ir-rt-total svg { color: var(--ir-aviso); flex: 0 0 auto; }
html.ir-plan-v2 .ir-esqueleto {
  display: inline-block; border-radius: 4px; color: transparent;
  background: var(--ir-esqueleto);
  animation: ir-esq 1.2s ease-in-out infinite;
}
@keyframes ir-esq { 0%,100% { opacity: .5 } 50% { opacity: 1 } }

/* ── ESTADOS ─────────────────────────────────────────────────────────────── */
html.ir-plan-v2 .ir-rt.elegida {
  background: var(--ir-fila-bg-sel);
  border-color: var(--ir-naranja-estado);   /* 6.65:1 oscuro · 5.84:1 claro  ✓ */
}
html.ir-plan-v2 .ir-rt.pulsada { background: var(--ir-pulsado); transform: scale(.985); }
/* Doble aro: funciona sobre cualquier papel, y al no existir ya `overflow-x`
   ningún contenedor lo recorta. */
html.ir-plan-v2 .ir-rt:focus,
html.ir-plan-v2 .ir-rt:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--ir-foco-int), 0 0 0 6px var(--ir-foco-ext);
}

/* ── LO QUE MUERE ────────────────────────────────────────────────────────── */
html.ir-plan-v2 .ir-dir-route-card,
html.ir-plan-v2 .ir-dir-rc-badge,
html.ir-plan-v2 .ir-dir-rc-stats,
html.ir-plan-v2 .ir-dir-veredicto { all: unset; }

/* ── PANTALLA ESTRECHA Y PANTALLA CORTA ──────────────────────────────────── */
/* No encoge nada: ni la letra, ni el objetivo táctil, ni los 88 px de fila.
   Se paga viendo menos, no viendo más pequeño. Bajar tamaños en la pantalla
   pequeña es exactamente el fallo que ya se corrigió con el suelo de 13 px. */
@media (max-width: 379px) {
  html.ir-plan-v2 .ir-opt { display: none; }
}
@media (max-height: 700px) {
  html.ir-plan-v2 .ir-ver-l3 { display: none; }   /* la mediana baja del pliegue */
  html.ir-plan-v2 .ir-rutas-banda { min-height: 64px; }
}
@media (prefers-reduced-motion: reduce) {
  html.ir-plan-v2 .ir-rt,
  html.ir-plan-v2 .ir-esqueleto {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  /* El CAMBIO DE ESTADO sobrevive: se desactiva la transición, jamás el
     resultado. Y el acuse al dedo pierde la escala, no el cambio de fondo. */
  html.ir-plan-v2 .ir-rt.pulsada { transform: none; }
}

/* ── EL PIE, con el nombre de lo que se va a navegar ─────────────────────── */
html.ir-plan-v2 .ir-dir-actions .ir-dir-btn-primary.ir-pie-doble {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; min-height: 56px; padding: 8px 12px; line-height: 1;
}
html.ir-plan-v2 .ir-pie-l1 {
  font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: 15px; line-height: 18px;
  letter-spacing: .02em; white-space: nowrap;
}
html.ir-plan-v2 .ir-pie-l2 {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-weight: 500; font-size: 13px; line-height: 16px; white-space: nowrap; opacity: .85;
}
/* El secundario baja a su icono: dos etiquetas largas no caben en 358 px, y la
   que tiene que ganar es la que dice qué se va a navegar. El área táctil sigue
   siendo de 56 px de alto y 56 de ancho — se reduce la tinta, no el objetivo. */
html.ir-plan-v2 .ir-dir-actions .ir-pie-icono {
  flex: 0 0 56px; min-width: 56px; min-height: 56px;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
html.ir-plan-v2 .ir-dir-actions .ir-dir-btn-primary { flex: 1 1 auto; }

/* ── LA ENTRADA PLEGADA ──────────────────────────────────────────────────── */
/* Con rutas calculadas la pantalla dejaba de necesitar el formulario y seguía
   enseñándolo: 256 px de los 588 de zona desplazable para unos campos ya
   contestados, mientras la tercera ruta caía bajo el pliegue. Se pliega a una
   línea con el trayecto escrito, que se toca entera para volver a abrirla. */
html.ir-plan-v2 .ir-esp-resumen {
  display: flex; align-items: center; gap: 10px;
  width: 100%; box-sizing: border-box;
  min-height: 56px; padding: 8px 12px; margin: 0 0 8px;
  background: var(--surface-2, #10294A);
  border: 1px solid var(--line, #1E3A5F);
  border-radius: 12px;
  font-family: 'DM Sans', sans-serif; font-size: 16px; line-height: 20px;
  color: var(--text, #F5F7FA); text-align: left; cursor: pointer;
}
html.ir-plan-v2 .ir-esp-resumen-ic { flex: 0 0 auto; color: var(--ir-naranja-estado, #F58220); display: flex; }
html.ir-plan-v2 .ir-esp-resumen-tx {
  flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
html.ir-plan-v2 .ir-esp-resumen-ed {
  flex: 0 0 auto; font-size: 13px; font-weight: 700; color: var(--ir-naranja-estado, #F58220);
}
html.ir-plan-v2 .ir-esp-resumen:focus-visible {
  outline: none; box-shadow: 0 0 0 3px var(--ir-foco-int), 0 0 0 6px var(--ir-foco-ext);
}
html.ir-plan-v2 .ir-dir-restrict-ic { display: flex; flex: 0 0 auto; color: var(--ir-rt-muted, #9FB0C3); }
html.ir-plan-v2 .ir-dir-restrict-title,
html.ir-plan-v2 .ir-dir-turns-title { font-size: 13px; letter-spacing: .04em; text-transform: uppercase; color: var(--ir-rt-muted, #9FB0C3); }
html.ir-plan-v2 .ir-dir-nb-tab { display: inline-flex; align-items: center; gap: 6px; min-height: 48px; font-size: 13px; }
html.ir-plan-v2 .ir-dir-nb-icon { display: flex; color: var(--ir-rt-muted, #9FB0C3); }
html.ir-plan-v2 .ir-dir-nb-item.selected .ir-dir-nb-icon,
html.ir-plan-v2 .ir-dir-nb-tab.active .ir-ic { color: var(--ir-naranja-estado, #F58220); }
html.ir-plan-v2 .ir-dir-nb-name { font-size: 13px; }
html.ir-plan-v2 .ir-dir-nb-addr { font-size: 13px; }
html.ir-plan-v2 .ir-dir-nb-dist { font-size: 13px; }
.ir-nb-marca { display: flex; align-items: center; justify-content: center; color: #F58220; filter: drop-shadow(0 1px 2px rgba(0,0,0,.7)); }
html.ir-plan-v2 .ir-dir-turn-icon { display: flex; flex: 0 0 auto; color: var(--ir-naranja-estado, #F58220); }
html.ir-plan-v2 .ir-dir-turn-instr { font-size: 13px; }
html.ir-plan-v2 .ir-dir-turn-dist  { font-size: 13px; }

/* ══════════════════════════════════════════════════════════════════════════
   20 · EL PANEL DE PEAJES

   Este panel enseñaba tres columnas —Cash, E-ZPass y transpondedor— con tres
   cifras que salían de multiplicar el MISMO número inventado por 1.4, por 1 y
   por 0.85, repartido entre tres casetas con nombre real. Ahora enseña una
   cifra, la del proveedor, o dice que no la tiene.

   Los tres estados necesitan verse distintos de un vistazo, así que cada uno
   tiene su forma, no solo su color.
   ══════════════════════════════════════════════════════════════════════════ */
html.ir-plan-v2 .toll-vacio,
.toll-vacio {
  padding: 20px 16px;
  text-align: center;
}
.toll-vacio-t {
  margin: 0 0 6px;
  font-family: 'Syne', sans-serif; font-weight: 700;
  font-size: 20px; line-height: 24px; color: var(--ir-rt-text, #F5F7FA);
}
.toll-vacio-s {
  margin: 0 auto 16px; max-width: 34ch;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 18px;
  color: var(--ir-rt-muted, #9FB0C3);
}
.toll-btn {
  min-height: 48px; padding: 0 18px;
  border-radius: 12px; border: 1px solid var(--ir-fila-borde, #2E4E7A);
  background: var(--ir-fila-bg, #10294A); color: var(--ir-rt-text, #F5F7FA);
  font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: 15px;
  cursor: pointer;
}
.toll-btn-primario {
  background: var(--ir-naranja, #F58220);
  border-color: var(--ir-naranja, #F58220);
  color: #0B1F33;                     /* tinta oscura sobre naranja: 7.5:1 */
}
.toll-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--ir-foco-int, #030D1C), 0 0 0 6px var(--ir-foco-ext, #F5F7FA);
}

/* El estado que antes no existía: «se preguntó y no se sabe». */
.toll-aviso {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 12px 16px; padding: 14px;
  border-radius: 12px;
  background: var(--ir-fila-bg, #10294A);
  border: 2px solid var(--ir-aviso, #F5A623);
  color: var(--ir-aviso, #F5A623);
}
.toll-aviso-cuerpo { flex: 1 1 auto; min-width: 0; }
.toll-aviso-t {
  margin: 0 0 4px; font-family: 'DM Sans', sans-serif; font-weight: 700;
  font-size: 16px; line-height: 20px; color: var(--ir-aviso, #F5A623);
}
.toll-aviso-s {
  margin: 0; font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 18px;
  color: var(--ir-rt-muted, #9FB0C3);
}

.toll-tarjeta {
  margin: 12px 16px; padding: 16px;
  border-radius: 12px;
  background: var(--ir-fila-bg, #10294A);
  border: 2px solid var(--ir-fila-borde, #2E4E7A);
}
.toll-tarjeta-cab { margin-bottom: 4px; }
.toll-ruta-nombre {
  font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: 16px;
  color: var(--ir-rt-text, #F5F7FA);
}
/* La cifra reina: mismo tamaño y misma familia que la de la comparación de
   rutas, para que las dos pantallas se lean como una sola. */
.toll-cifra {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 32px; line-height: 38px; letter-spacing: -.01em;
  color: var(--ir-rt-text, #F5F7FA);
}
/* «Sin peajes» es una PALABRA, no una cifra: en monoespaciada tabular se lee
   como un dato numérico mal formateado. La familia sigue al contenido. */
.toll-cifra.toll-cero {
  font-family: 'Syne', sans-serif; font-weight: 800;
  font-size: 25px; line-height: 30px; letter-spacing: 0;
  color: var(--ir-ok, #10B981);
}
.toll-sub, .toll-nota {
  margin-top: 4px;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 18px;
  color: var(--ir-rt-muted, #9FB0C3);
}
.toll-nota { margin-top: 10px; }
.toll-desglose { margin-top: 14px; border-top: 1px solid var(--ir-fila-borde, #2E4E7A); padding-top: 10px; }
.toll-desglose h4 {
  margin: 0 0 8px; font-family: 'DM Sans', sans-serif; font-weight: 700;
  font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ir-rt-muted, #9FB0C3);
}
.toll-fila {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; min-height: 32px; padding: 4px 0;
}
.toll-fila-izq { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.toll-caseta {
  font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--ir-rt-text, #F5F7FA);
}
.toll-via, .toll-estado {
  font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--ir-rt-muted, #9FB0C3);
}
/* Los precios de las casetas forman su propia columna alineada: si no, no se
   puede ver de un vistazo cuál es la cara. */
.toll-precio {
  flex: 0 0 auto;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 16px; color: var(--ir-rt-text, #F5F7FA);
  /* SIN ESTO EL RELLENO NO SIRVE DE NADA. El espacio de cifra (U+2007) que
     alinea los decimales va DELANTE de la cifra, y el espacio inicial de una
     caja en línea lo descarta el navegador antes de pintar. Se midió: los
     puntos seguían desalineados con el relleno ya puesto. */
  white-space: pre;
}
.toll-actions { display: flex; gap: 8px; padding: 0 16px 16px; }
.toll-history-title {
  margin: 16px 16px 8px; font-family: 'Syne', sans-serif; font-weight: 700;
  font-size: 16px; color: var(--ir-rt-text, #F5F7FA);
}
.toll-month-card {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin: 0 16px 6px; padding: 10px 12px; min-height: 48px;
  border-radius: 10px; background: var(--ir-fila-bg, #10294A);
  font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--ir-rt-muted, #9FB0C3);
}
.toll-month-card .tmc-total {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums;
  font-size: 16px; font-weight: 700; color: var(--ir-rt-text, #F5F7FA);
}
#toll-history-chart { display: block; margin: 0 16px 12px; max-width: calc(100% - 32px); }

/* El combustible, con la misma regla: sin precio publicado se dice. */
.fuel-vacio {
  padding: 20px 16px; text-align: center;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 18px;
  color: var(--ir-rt-muted, #9FB0C3);
}
.fsc-sin-precio {
  font-family: 'DM Sans', sans-serif; font-size: 13px;
  color: var(--ir-rt-muted, #9FB0C3); font-style: italic;
}
.fuel-optimal-base {
  display: block; margin-top: 4px;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 17px;
  color: var(--ir-rt-muted, #9FB0C3);
}

/* ══════════════════════════════════════════════════════════════════════════
   21 · EL MOVIMIENTO

   La síntesis del 3-ago lo dejó especificado y sin implementar: la hoja
   aparecía en vez de llegar, y las filas solo cambiaban de fondo al pulsarlas.

   DOS REGLAS, y las dos por el mismo motivo — esto se mira con el motor
   encendido, en un teléfono limitado térmicamente:

     · Solo se anima `transform` y `opacity`. Nunca `height`, `top` ni `width`:
       eso obliga al navegador a recalcular la composición, y un reflujo bajo
       el dedo es un objetivo que se mueve mientras lo tocas.
     · Se anima UNA cosa por interacción. Tres cosas moviéndose a la vez no se
       leen como respuesta, se leen como que la pantalla se desarmó.

   Y las filas NO entran escalonadas. El argumento entero de esta pantalla es
   que las tres se ven a la vez para poder compararlas; hacerlas llegar de una
   en una contradice justo eso.
   ══════════════════════════════════════════════════════════════════════════ */
@keyframes ir-hoja-llega {
  from { transform: translateY(24px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes ir-entra {
  from { transform: scale(.8); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}

/* La hoja llega, no aparece. 240 ms con salida rápida: el 80 % del recorrido
   ocurre en el primer tercio del tiempo, así que se percibe inmediata y aun
   así se ve de dónde vino. */
html.ir-plan-v2 .ir-dir-sheet.show {
  animation: ir-hoja-llega .24s cubic-bezier(.2, .8, .2, 1) both;
}

/* El bloque de rutas entero, de una vez. */
html.ir-plan-v2 .ir-rutas-banda,
html.ir-plan-v2 .ir-rutas-grupo {
  animation: ir-hoja-llega .24s cubic-bezier(.2, .8, .2, 1) both;
}

/* El check de «elegida» entra; no parpadea a existir. */
html.ir-plan-v2 .ir-rt.elegida .ir-rt-marca {
  animation: ir-entra .12s ease-out both;
}

/* El riel de la fila elegida crece desde su centro: es la única señal que se
   mueve al cambiar de opción, y sale del sitio exacto donde está el dedo. */
html.ir-plan-v2 .ir-rt-riel {
  transform-origin: center;
  transition: transform .14s ease-out;
}
html.ir-plan-v2 .ir-rt.elegida .ir-rt-riel { transform: scaleY(1); }
html.ir-plan-v2 .ir-rt:not(.elegida) .ir-rt-riel { transform: scaleY(.72); }

@media (prefers-reduced-motion: reduce) {
  /* EL CAMBIO DE ESTADO SOBREVIVE. Se desactiva la transición, jamás el
     resultado: quien pide menos movimiento no está pidiendo que el riel deje
     de marcar cuál es su ruta. */
  html.ir-plan-v2 .ir-dir-sheet.show,
  html.ir-plan-v2 .ir-rutas-banda,
  html.ir-plan-v2 .ir-rutas-grupo,
  html.ir-plan-v2 .ir-rt.elegida .ir-rt-marca {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  html.ir-plan-v2 .ir-rt-riel { transition-duration: .01ms !important; }
}

/* La hoja animaba `height` durante 300 ms cada vez que cambia de tamaño
   —y cambia justo cuando llegan las rutas, que es cuando el conductor va a
   poner el dedo—. Animar `height` obliga al navegador a recomponer el árbol
   entero de la hoja en cada fotograma: en un teléfono limitado térmicamente
   eso es un objetivo que se mueve mientras lo tocas.

   El alto pasa de golpe; lo que llega con movimiento es el contenido, y eso ya
   va con `transform` y `opacity`. Nadie percibe el salto del contenedor cuando
   lo que hay dentro entra deslizándose. */
html.ir-plan-v2 .ir-dir-sheet {
  transition: transform .35s cubic-bezier(.4, 0, .2, 1);
}
