/* --- PALETA ---
   Naranja de marca sobre blanco. Un único color de acento para toda la
   interfaz, y neutros para el resto: así los colores que SÍ significan algo
   (el rojo de la Línea 2, el verde del interurbano, el azul de la EMT) no
   compiten con los botones.

   Los dos naranjas no son un capricho. #F5A623 sobre blanco da 2:1 de
   contraste, muy por debajo del 4.5:1 que hace falta para leer texto, así
   que se reparten el trabajo: el naranja de marca solo se usa como RELLENO
   o como aro, siempre con texto oscuro encima (10:1), y para texto naranja
   sobre blanco va la variante oscura (5.5:1). */
:root {
  --acento: #f5a623;
  --acento-texto: #9a5b00;
  --acento-suave: #fdf1dd; /* relleno de hover y de fila seleccionada */
  --texto-sobre-acento: #121212;

  --superficie: #ffffff; /* tarjetas y cabecera */
  --fondo: #faf9f7; /* el panel, un blanco apenas cálido para que las tarjetas se despeguen */
  --borde: #e6e3de;

  --texto: #121212;
  --texto-suave: #767068;

  /* --- COLORES CON SIGNIFICADO ---
     Del manual de marca, que los toma de los colores de sistema de iOS. Se
     reservan para estado (una incidencia, un retraso, una confirmación) y
     nunca para decorar: si se usan porque sí, dejan de querer decir nada.

     OJO con dos del manual que NO se copian tal cual, por contraste medido
     sobre blanco:
       - su gris de textos #8E8E93 da 3,26:1, por debajo del 4,5:1 de AA.
         Para texto secundario se sigue usando --texto-suave (4,90:1); este
         queda solo para bordes y elementos desactivados, que no son texto.
       - los botones del manual llevan texto BLANCO sobre el naranja de
         marca: 2,03:1, ilegible. Ver la nota de arriba sobre los dos
         naranjas; encima del relleno naranja va --texto-sobre-acento. */
  --verde: #34c759;
  --azul: #007aff;
  --rojo: #ff3b30;
  --gris-desactivado: #8e8e93;

  /* Dos grises de la interfaz que estaban escritos a pelo en sus reglas.
     El de la estrella es más cálido que el gris de sistema, para no
     desentonar con el fondo hueso del panel. */
  --estrella-apagada: #b8b2a8;
  --borde-fuerte: #ded8ce;
  /* Papel cálido, no gris frío. Era #f2f2f2 y estaba en cuatro superficies
     seguidas de la parte alta del panel —buscador, bandeja de filtros, hueco
     del icono de red y botón de planos—, enfriando justo la franja donde se
     lee la marca en un sistema cuyo norte es el papel cálido.
     Y además fallaba WCAG: --texto-suave sobre #f2f2f2 daba 4,37, por debajo
     del 4,5 de AA, en las etiquetas de los filtros inactivos. Sobre este
     valor da 4,54, con un poco de margen sobre el límite. */
  --gris-superficie: #f8f6f3;

  /* --- PROFUNDIDAD ---
     Sombras en dos capas en vez de bordes de 1px. La capa corta define el
     canto del elemento y la larga y muy tenue lo despega del fondo; juntas
     dan volumen sin que se vea una línea, que es de lo que va el soft UI.
     Un borde sólido, por claro que sea, siempre lee como una raya. */
  --sombra-sutil: 0 1px 2px rgba(18, 18, 18, 0.04),
    0 4px 12px rgba(18, 18, 18, 0.04);
  --sombra-media: 0 1px 2px rgba(18, 18, 18, 0.05),
    0 8px 24px rgba(18, 18, 18, 0.07);
  --sombra-flotante: 0 2px 6px rgba(18, 18, 18, 0.08),
    0 12px 32px rgba(18, 18, 18, 0.1);

  /* Separador de grosor real de un píxel físico: en pantallas de retina
     0.5px es una línea de verdad, no una gris difuminada. */
  --separador: rgba(18, 18, 18, 0.08);

  /* Radios. Generosos y proporcionales al tamaño del elemento, como en
     iOS, donde una tarjeta grande curva más que un chip pequeño. */
  /* Curva de salida fuerte para la interfaz. Las easings del navegador son
     demasiado planas para una animación deliberada: esta arranca rápido, que
     es el momento en el que se está mirando. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);

  /* Triángulo de aviso, incrustado como máscara para que herede el color del
     elemento en vez de traer el suyo. */
  --icono-aviso: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
  --icono-plano: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3.5L3 6v14.5l6-2.5 6 2.5 6-2.5V3.5l-6 2.5-6-2.5z'/%3E%3Cpath d='M9 3.5v14.5'/%3E%3Cpath d='M15 6v14.5'/%3E%3C/svg%3E");

  --radio-grande: 22px;
  --radio-medio: 16px;
  --radio-pequeno: 12px;
}

* {
  box-sizing: border-box;
}

body {
  /* Ancho del panel izquierdo. Es una variable y no un valor fijo porque
     se puede arrastrar el divisor para ensanchar o estrechar el panel; el
     JS solo cambia esta propiedad y el grid se recoloca solo. */
  --ancho-panel: 380px;

  margin: 0;
  /* Inter es la tipografía de la identidad. Se sirve desde este mismo
     dominio (ver tipografia.css); la pila del sistema queda detrás para el
     rato que tarda en cargar: la interfaz se ve peor, pero se ve. */
  font-family: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  background: var(--fondo);

  /* Sin esto, en macOS los trazos de Inter salen más gruesos de lo que la
     tipografía pide y la interfaz pierde la ligereza que busca. */
  -webkit-font-smoothing: antialiased;

  /* Los títulos de iOS van con el interletrado ligeramente cerrado; a
     tamaños grandes el espaciado por defecto se ve suelto. */
  letter-spacing: -0.01em;

  /* --- LAYOUT PRINCIPAL ---
     Tres columnas: el panel, el divisor que se arrastra y el mapa.
     height: 100vh hace que el grid ocupe toda la altura de la ventana, y
     el padding deja ver el fondo alrededor, que es lo que permite que
     panel y mapa se vean como dos bloques redondeados y separados. */
  display: grid;
  grid-template-columns: var(--ancho-panel) 14px 1fr;
  height: 100vh;
  padding: 10px;
}

#mapa {
  height: 100%;
  width: 100%;
  border-radius: var(--radio-grande);
  /* Sin esto los tiles cuadrados de Leaflet asoman por las esquinas. */
  overflow: hidden;
}

/* --- PANEL IZQUIERDO ---
   Ya no flota sobre el mapa: ahora es una columna real del grid,
   con su propio fondo y scroll independiente si la lista es larga. */
#panel {
  background: var(--superficie);
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  border-radius: var(--radio-grande);
  box-shadow: var(--sombra-sutil);
}

/* --- DIVISOR ARRASTRABLE ---
   Ocupa la columna del medio del grid. La barrita no es el elemento
   entero: el elemento es ancho para que sea fácil de agarrar con el ratón,
   y dentro se dibuja un tirador estrecho y redondeado. */
#divisor {
  /* Contexto de posicionamiento para el tirador, que va absoluto. */
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: col-resize;
  /* Evita que en pantalla táctil el arrastre haga desplazar la página. */
  touch-action: none;
}

#divisor::before {
  content: "";
  width: 4px;
  height: 44px;
  border-radius: 999px;
  background: var(--borde-fuerte);

  /* Crece con scaleY y no con height: animar height dispara maquetación y
     pintado en cada pointermove sobre el divisor, mientras que el transform
     lo mueve el compositor.

     El primer intento con scaleY se descartó porque escalar una píldora
     convierte sus tapas semicirculares en elipses. La solución está en el
     SENTIDO: el reposo se queda en su altura real, con las tapas redondas, y
     el 1,727 se aplica solo al señalarlo. Así lo exacto es lo que se ve el
     99% del tiempo, y la deformación vive en un estado momentáneo de 120 ms.
     Escalando al revés —desde la altura grande hacia abajo— la tapa deformada
     habría sido justo la del reposo. */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: background 0.12s var(--ease-out), transform 0.12s var(--ease-out);
}

#divisor:hover::before,
#divisor:focus-visible::before,
#divisor.arrastrando::before {
  background: var(--acento);
  /* 76/44, la misma altura de antes pero por escala. */
  transform: translate(-50%, -50%) scaleY(1.727);
}

#divisor:focus {
  outline: none; /* el tirador ya se resalta solo al recibir el foco */
}

/* Cabecera del panel: una banda del naranja de marca, con el logo centrado.
   Es el único bloque de color de toda la interfaz; de aquí para abajo todo
   es blanco. */
#panel-header {
  padding: 18px 16px;
  background: var(--acento);
  display: flex;
  justify-content: center;
}

/* El h1 ya no lleva texto, solo el logo: se queda como contenedor para no
   perder el encabezado de la página. */
#panel-header h1 {
  margin: 0;
  line-height: 0; /* si no, el hueco de la línea de texto añade espacio bajo la imagen */
}

/* El SVG es solo el nombre, en blanco y recortado a su caja: no arrastra el
   cuadrado naranja del archivo original, así que el color del fondo lo pone
   la banda de arriba y no hay dos naranjas que puedan no coincidir.
   La altura se deja en auto para respetar su proporción (985x312). */
#logo {
  display: block;
  width: 128px;
  height: auto;
}

/* Texto de contexto de la vista actual ("Busca una parada o una línea",
   "Próximas llegadas"...). Va ya en la zona blanca, debajo de la banda. */
#subtitulo-header {
  margin: 0;
  padding: 12px 16px 0 16px;
  font-size: 12px;
  color: var(--texto-suave);
}

/* Campo de búsqueda al modo de iOS: un relleno gris sin borde, con la lupa
   dentro. El icono va como background-image en data URI y no como <img> en
   el HTML porque así el campo sigue siendo un único elemento: no hay que
   envolverlo en un contenedor ni posicionar nada encima. */
/* La fila del buscador. Antes el padding iba en un style= en línea. */
.fila-buscador {
  position: relative;
  padding: 12px 16px 0;
}

#input-buscar {
  width: 100%;
  /* 44px es la Regla del Pulgar de DESIGN.md, y este campo medía 40: el
     control principal del panel era más pequeño que el botón secundario que
     tenía al lado. */
  min-height: 44px;
  box-sizing: border-box;
  padding: 11px 12px 11px 38px;
  font-size: 15px;
  border: none;
  border-radius: var(--radio-pequeno);
  background-color: var(--gris-superficie);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 12px center;
  background-size: 16px 16px;
  color: var(--texto);
  transition: background-color 0.15s var(--ease-out),
    box-shadow 0.15s var(--ease-out);
}

#input-buscar::placeholder {
  /* Texto, no adorno: es la única etiqueta visible del campo. Con
     --gris-desactivado daba 2,91 sobre el fondo del propio campo. */
  color: var(--texto-suave);
}

/* Al enfocar, el campo pasa a blanco y se levanta con un aro del color de
   marca. Se cambia el fondo en vez de añadir un borde: mantiene la caja
   del mismo tamaño y no descoloca lo que hay debajo. */
#input-buscar:focus {
  outline: none;
  background-color: var(--superficie);
  box-shadow: 0 0 0 3px var(--acento-suave), var(--sombra-sutil);
}

/* --- FILTRO DE FUENTE (Todos / Urbano / Interurbano / Metro) ---
   Montado como el control segmentado de iOS: una bandeja gris hundida y,
   dentro, la opción activa levantada en blanco. La jerarquía la da la
   elevación y no el color, así que los colores de cada modo (azul EMT,
   verde interurbano) siguen queriendo decir lo que decían. */
#filtros-fuente {
  display: flex;
  gap: 2px;
  margin: 12px 16px 0 16px;
  padding: 3px;
  background: var(--gris-superficie);
  border-radius: 14px;
}

/* Cada filtro es el icono de su modo con la etiqueta debajo. El icono va
   dentro de un cuadro fijo con object-fit porque los PNG tienen
   proporciones muy distintas entre sí (el bus es vertical, el rombo del
   metro es apaisado) y estirarlos los deformaría. */
.filtro-boton {
  flex: 1;
  min-width: 0; /* deja que "Interurbano" trunque en vez de ensanchar el botón */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 7px 2px 6px;
  border: none;
  background: none;
  border-radius: 11px;
  color: var(--texto-suave);
  font-size: 11px;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.18s var(--ease-out), box-shadow 0.18s var(--ease-out),
    color 0.18s var(--ease-out);
}

/* El icono ya no necesita su propio cuadro de color: dentro de la bandeja
   segmentada, ese segundo fondo era una caja dentro de otra caja. */
.filtro-icono {
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  box-sizing: border-box;
}

.filtro-icono img,
.filtro-icono svg {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}

.filtro-etiqueta {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Fondo pastel propio de cada modo, tomado de su color corporativo: azul
   de la EMT, verde del interurbano, y neutro para Metro, cuyo rombo ya
   lleva rojo y azul y se ensucia sobre un fondo de color. */
.filtro-boton:hover:not(.activo) {
  background: rgba(255, 255, 255, 0.5);
  color: var(--texto);
}

/* Activo: la pastilla blanca se levanta sobre la bandeja gris, que es como
   marca la selección un control segmentado. El aro naranja de antes sobra
   aquí — sumado a la elevación serían dos señales para lo mismo. La
   etiqueta va en la variante oscura del naranja, la única legible a 11px. */
.filtro-boton.activo {
  background: var(--superficie);
  color: var(--acento-texto);
  font-weight: 600;
  box-shadow: var(--sombra-sutil);
}

/* --- VISTA: LISTA DE RESULTADOS DE BÚSQUEDA --- */
/* Los resultados son fichas redondeadas separadas entre sí, no filas
   pegadas con una raya debajo: la lista se lee igual y encaja con el resto
   de la interfaz, donde no hay ninguna esquina en pico. */
#lista-resultados {
  list-style: none;
  margin: 0;
  /* 12px arriba, como todos los bordes del panel. Estaba en 6 y era el único
     salto a media altura de la pila, así que la primera ficha se leía pegada
     a lo que tuviera encima. */
  padding: 12px 12px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

#lista-resultados li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  cursor: pointer;
  border-radius: var(--radio-medio);
  font-size: 15px;
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
  /* Asimétrico a propósito: soltar puede permitirse 0.16s, pero la respuesta
     al dedo tiene que chasquear (ver :active). */
  transition: transform 0.16s var(--ease-out), box-shadow 0.16s var(--ease-out),
    background 0.16s var(--ease-out);
}

/* Al pasar por encima la ficha se levanta un poco en vez de teñirse: el
   movimiento comunica que es pulsable sin gastar color, y así el naranja
   se reserva para lo que está seleccionado de verdad. */
#lista-resultados li:hover {
  background: var(--superficie);
  box-shadow: var(--sombra-media);
  transform: translateY(-1px);
}

/* Al pulsar se hunde. Es el gesto táctil de iOS: la respuesta ocurre
   mientras el dedo sigue abajo, no al soltar. */
#lista-resultados li:active {
  /* La pulsación va más rápida que el soltado: el dedo espera respuesta
     inmediata, la vuelta al reposo no. */
  transition-duration: 0.1s;
  transform: scale(0.985);
  box-shadow: var(--sombra-sutil);
}

/* El buscador mezcla líneas y paradas, así que cada bloque lleva su
   encabezado. No es clicable, de ahí que anule el cursor y el hover que
   heredaría del "li" de arriba. */
#lista-resultados li.grupo-resultados {
  padding: 10px 6px 2px 6px;
  background: none;
  cursor: default;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--texto-suave);
}

#lista-resultados li.grupo-resultados:hover {
  background: none;
}

/* Explica de dónde salen los favoritos cuando todavía no hay ninguno. Solo
   aparece con el buscador vacío, que es donde iría la lista. */
#lista-resultados li.pista-favoritos {
  display: block;
  padding: 16px;
  background: var(--fondo);
  cursor: default;
  font-size: 13px;
  line-height: 1.45;
  color: var(--texto-suave);
}

#lista-resultados li.pista-favoritos:hover {
  background: var(--fondo);
}

/* El texto de cada resultado ocupa el hueco que deja el distintivo (o el
   icono) a la izquierda y la estrella a la derecha, y trunca si no cabe. */
#lista-resultados .texto {
  flex: 1;
  min-width: 0;
}

/* En una parada el texto es una sola línea, así que trunca aquí mismo. En
   una línea el truncado va en .titulo, porque debajo lleva el subtítulo. */
#lista-resultados li:not(.resultado-linea) .texto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.resultado-linea .tarjeta-linea {
  width: 34px;
  height: 34px;
  font-size: 12px;
}

.resultado-linea .titulo {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.resultado-linea .subtitulo {
  font-size: 12px;
  color: var(--texto-suave);
}

/* --- VISTA: LLEGADAS A LA PARADA SELECCIONADA --- */
#vista-llegadas {
  display: none; /* oculta hasta que se seleccione una parada */
  flex-direction: column;
}

#cabecera-llegadas {
  padding: 12px 16px 0 16px;
}

.boton-volver {
  background: none;
  border: none;
  color: var(--acento-texto);
  font-size: 14px;
  cursor: pointer;
  padding: 0;
  margin-bottom: 10px;
  text-align: left;
}

.boton-volver:hover {
  text-decoration: underline;
}

/* --- VISTA: RECORRIDO DE UNA LÍNEA --- */
#vista-linea {
  display: none; /* oculta hasta que se elija una línea */
  flex-direction: column;
}

#cabecera-linea {
  padding: 12px 16px 0 16px;
}

#tarjeta-linea {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--superficie);
  border-radius: 16px;
  padding: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

#nombre-linea {
  font-weight: bold;
  font-size: 14px;
  color: var(--texto);
  line-height: 1.25;
}

#fuente-linea {
  font-size: 12px;
  color: var(--texto-suave);
  margin-top: 1px;
}

/* Un botón por sentido. Son dos casi siempre, así que se reparten el ancho.
   El destino puede ser largo, de ahí el truncado. */
#sentidos-linea {
  display: flex;
  gap: 6px;
  margin-top: 10px;
}

.boton-sentido {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  font-size: 12.5px;
  font-family: inherit;
  border: none;
  border-radius: 999px; /* pastilla completa, como los controles de iOS */
  background: var(--gris-superficie);
  color: var(--texto-suave);
  cursor: pointer;
  transition: background 0.15s var(--ease-out), color 0.15s var(--ease-out),
    box-shadow 0.15s var(--ease-out);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.boton-sentido:hover {
  background: var(--acento-suave);
}

/* Relleno naranja con texto oscuro, no blanco: sobre este naranja el blanco
   se queda en 2:1 y el texto casi desaparece. */
.boton-sentido.activo {
  background: var(--acento);
  color: var(--texto-sobre-acento); /* oscuro sobre naranja: 9,24:1 */
  font-weight: 600;
  box-shadow: var(--sombra-sutil);
}

#titulo-recorrido {
  padding: 16px 16px 0 16px;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--texto-suave);
}

#lista-recorrido {
  list-style: none;
  margin: 0;
  padding: 8px 12px 12px 12px;
}

/* Cada parada del recorrido. El número de orden va en una columna fija
   para que los nombres queden alineados aunque haya paradas de dos y de
   tres cifras. */
.parada-recorrido {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 12px;
  cursor: pointer;
  font-size: 13px;
  color: #333;
}

.parada-recorrido:hover {
  background: var(--acento-suave);
}

.parada-recorrido .orden {
  flex-shrink: 0;
  width: 22px;
  text-align: right;
  color: #9a9aa0;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.parada-recorrido .nombre {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Tarjeta de identidad de la parada: icono del modo a la izquierda,
   nombre + código + líneas a la derecha. */
#tarjeta-parada {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--superficie);
  border-radius: 12px;
  padding: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

/* El icono conserva su proporción real (los PNG de bus y de metro tienen
   relaciones de aspecto muy distintas), centrado dentro de un cuadro fijo
   para que el texto de al lado quede siempre alineado sea cual sea el modo. */
#icono-parada-actual {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  object-fit: contain;
  background: #f0f1f3;
  border-radius: 12px;
  padding: 7px;
}

#datos-parada {
  min-width: 0; /* deja que el nombre largo trunque en vez de desbordar */
}

#nombre-parada-actual {
  font-weight: bold;
  font-size: 15px;
  color: var(--texto);
  line-height: 1.25;
}

#codigo-parada-actual {
  font-size: 12px;
  color: var(--texto-suave);
  margin-top: 1px;
}

#codigo-parada-actual:empty {
  display: none;
}

/* Título de sección sobre la lista de llegadas ("Tiempos reales"). */
#titulo-seccion {
  padding: 16px 16px 0 16px;
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--texto-suave);
}

#titulo-seccion:empty {
  display: none;
}

/* Distintivos de línea de la cabecera. El contenedor se oculta cuando está
   vacío (paradas de bus, o antes de que lleguen los datos) para no dejar un
   hueco bajo el nombre. */
#chips-lineas {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
}

#chips-lineas:empty {
  display: none;
}

/* Forma compartida por el distintivo pequeño de la cabecera y el grande de
   cada tarjeta de llegada: cuadrado de esquinas redondeadas, como en la app
   oficial. Solo cambian el tamaño y la tipografía, que van en cada clase.

   Los colores se aplican inline desde app.js porque salen del GTFS y no
   queremos una regla CSS por línea. El borde sí vive aquí y es
   imprescindible: la Línea R (Ramal) es oficialmente blanca, así que sin él
   su distintivo sería invisible sobre el fondo blanco de la tarjeta. Neutro
   y translúcido para que apenas se note en las demás. */
.chip-linea,
.tarjeta-linea {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: 10px;
  border: 1px solid rgba(0, 0, 0, 0.12);
  font-weight: bold;
  line-height: 1;
}

.chip-linea {
  min-width: 24px;
  height: 24px;
  padding: 0 5px;
  font-size: 12px;
}

#lista-llegadas {
  list-style: none;
  margin: 0;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Cada llegada es una tarjeta: distintivo de línea a la izquierda y, a su
   derecha, el destino con el tiempo debajo en grande. Se usa igual para
   autobuses y para trenes. */
.tarjeta-bus {
  display: flex;
  align-items: flex-start; /* el distintivo se alinea con el destino, no al centro */
  background: var(--superficie);
  border-radius: var(--radio-grande);
  padding: 14px;
  box-shadow: var(--sombra-sutil);
  gap: 12px;
}

/* La forma la comparte con .chip-linea, arriba. Aquí solo el tamaño y el
   color por defecto: el azul corporativo de la EMT, que es el que trae su
   routes.txt para las 236 líneas. Las de Metro lo sobrescriben inline. */
.tarjeta-linea {
  width: 40px;
  height: 40px;
  background-color: #0178bc;
  color: white;
  font-size: 14px;
}

.tarjeta-info {
  flex: 1;
  min-width: 0; /* permite que el texto largo trunque en vez de desbordar */
}

/* --- LA ESCALA DE LA TARJETA DE LLEGADA ---
   Tres niveles y tres papeles distintos, que antes no se distinguían:

     destino    14px / 600 / tinta        cuál de las tarjetas es la tuya
     tiempo     26px / 700 / tinta        el dato por el que se abre esto
     siguiente  12px / 400 / tinta suave  detalle de apoyo

   El fallo anterior era que destino (14) y siguiente (12) se diferenciaban
   solo en 2px, así que leían como el mismo nivel y la tarjeta parecía tener
   dos títulos. Ahora se separan por tamaño, peso Y color a la vez. */
.tarjeta-destino {
  font-size: 14px;
  font-weight: 600;
  color: var(--texto);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis; /* "Plaza de Castilla..." si no cabe */
}

/* El tiempo más próximo es el dato principal de la tarjeta: va debajo del
   destino y en grande, como en la app oficial. */
.tiempo-proximo {
  font-size: 26px;
  font-weight: 700;
  color: var(--texto);
  margin-top: 3px;

  /* Cifras de ancho fijo: sin esto, al refrescar cada 10s el número baila
     de anchura ("11 min" ocupa menos que "44 min") y la tarjeta entera da
     un salto lateral. Es el detalle que separa un contador que se
     actualiza de uno que parpadea. */
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.tiempo-proximo .unidad {
  font-size: 13px;
  margin-left: 2px;
}

/* "En camino" en vez de un número. Ver el comentario de app.js: dos palabras
   al cuerpo de un dígito se comen la tarjeta. */
.tiempo-proximo.es-texto {
  font-size: 18px;
}

/* Avisa de que esa hora sale de la tabla de horarios y no de un seguimiento
   en vivo. Solo aparece en interurbano, que es donde conviven ambas cosas:
   en Metro y EMT todas las llegadas son en tiempo real. Discreta a
   propósito — informa sin competir con el número. */
.tiempo-proximo .etiqueta-horario {
  display: inline-block;
  vertical-align: middle;
  margin-left: 8px;
  padding: 2px 6px;
  border-radius: 8px;
  background: #eceef1;
  color: #6b7280;
  font-size: 10px;
  font-weight: bold;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Los tiempos siguientes, en pequeño y en gris bajo el principal. */
.tarjeta-tiempos {
  font-size: 12px;
  color: var(--texto-suave);
  margin-top: 3px;
}

/* Aviso de fallo de red. Deliberadamente discreto y no rojo: mientras se
   ve, el panel sigue enseñando los últimos datos buenos, así que esto no
   es un error que rompa nada, es una advertencia de que lo que hay debajo
   puede estar envejeciendo. El ámbar de marca no llega a 4,5:1 sobre
   blanco, así que el texto usa --acento-texto y el naranja se queda en el
   fondo y el borde. */
#aviso-conexion {
  /* Mismo caso que el botón de avisos: sin margen superior se pegaba a la
     banda naranja de la cabecera. */
  margin: 12px 16px 0;
  padding: 10px 13px;
  /* El borde sólido se cambia por un aro interior traslúcido: marca el
     canto sin dibujar una raya, igual que el resto de superficies. */
  box-shadow: inset 0 0 0 1px rgba(245, 166, 35, 0.35);
  border-radius: var(--radio-pequeno);
  background: var(--acento-suave);
  color: var(--acento-texto);
  font-size: 13px;
  line-height: 1.35;
}

/* El atributo hidden lo pisaría el display de cualquier regla posterior;
   con esto el ocultado sigue funcionando pase lo que pase. */
#aviso-conexion[hidden] {
  display: none;
}

/* Explicación que ocupa el lugar del recorrido en las líneas que el GTFS
   no detalla. Sin viñeta ni cursor de clic: no es una parada más. */
.recorrido-no-disponible {
  list-style: none;
  padding: 14px 16px;
  color: var(--texto-suave);
  font-size: 13px;
  line-height: 1.45;
}

#mensaje-vacio {
  padding: 20px 16px;
  color: var(--texto-suave);
  font-size: 13px;
  text-align: center;
}

/* Quitamos el fondo blanco que Leaflet pone por defecto a los divIcon */
.icono-bus {
  background: transparent;
  border: none;
}

/* El círculo azul con el número de línea dentro, sobre el mapa */
.circulo-bus {
  width: 30px;
  height: 30px;
  background-color: #0178bc;
  color: white;
  border-radius: 50%;
  border: 2px solid white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: bold;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* Círculo del tren de Metro: mismo patrón que .circulo-bus, pero sin
   background-color fijo — ese color lo decide la línea (rojo, amarillo,
   verde...) y se aplica inline desde JS, porque varía por cada tren. */
.circulo-tren {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: bold;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* --- BOTÓN "MI UBICACIÓN" ---
   position: fixed lo saca del flujo normal del documento, así que
   "flota" sobre el mapa en vez de ocupar espacio en el grid de
   #panel/#mapa. Lo posicionamos relativo a la ventana completa. */
#boton-ubicacion {
  position: fixed;
  bottom: 28px;
  right: 28px;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: none;

  /* Material translúcido sobre el mapa: el fondo se ve difuminado a través
     del botón, así que el control se siente apoyado encima del mapa en vez
     de pegado sobre él. Es lo que iOS llama material, y necesita las dos
     declaraciones: -webkit- para Safari, que es justo donde más se nota.
     El color de reserva es opaco, para navegadores sin backdrop-filter:
     translúcido sin desenfoque se leería como un botón medio borrado. */
  background: rgba(255, 255, 255, 0.98);
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  box-shadow: var(--sombra-flotante), inset 0 0 0 0.5px rgba(255, 255, 255, 0.6);
  font-size: 19px;
  cursor: pointer;
  transition: transform 0.14s var(--ease-out), box-shadow 0.14s var(--ease-out);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Leaflet usa z-index internamente para sus propias capas
     (tiles, controles, paneles de animación durante zoom/paneo).
     Sin esto, el botón queda tapado en ciertos momentos del zoom. */
  z-index: 1000;
}

#boton-ubicacion:hover {
  background: rgba(255, 255, 255, 0.88);
  transform: scale(1.04);
}

#boton-ubicacion:active {
  transform: scale(0.94);
  box-shadow: var(--sombra-media);
}

/* --- FAVORITOS ---
   La estrella aparece en tres sitios con el mismo aspecto: la cabecera de
   una parada, la de una línea y cada fila de resultados del buscador.

   Vacía es un contorno gris que no compite con el nombre; guardada se
   rellena del naranja de marca. Aquí el relleno no lleva texto encima, así
   que el naranja claro se puede usar tal cual. */
.boton-favorito {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--estrella-apagada);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.boton-favorito svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linejoin: round;
}

.boton-favorito:hover {
  background: var(--acento-suave);
  color: var(--acento-texto);
}

.boton-favorito.activo {
  color: var(--acento);
}

.boton-favorito.activo svg {
  fill: var(--acento);
}

/* En las cabeceras la estrella se va al extremo derecho de la tarjeta, para
   que no dependa de lo largo que sea el nombre de la parada. */
#tarjeta-parada .boton-favorito,
#tarjeta-linea .boton-favorito {
  margin-left: auto;
}

/* --- MARCADOR DE "MI UBICACIÓN" (punto azul tipo Google Maps) ---
   Dos capas: un halo translúcido grande (igual que Google Maps marca
   el margen de error del GPS) y un punto sólido pequeño encima,
   centrado con position:absolute + transform.

   Se queda azul a propósito, fuera de la paleta naranja: es la convención
   universal de "estás aquí" y, siendo un punto más sobre el mapa, conviene
   que no se confunda ni con una parada ni con un vehículo. */
.icono-ubicacion {
  background: transparent;
  border: none;
}

.halo-ubicacion {
  width: 36px;
  height: 36px;
  background: rgba(24, 144, 255, 0.25);
  border-radius: 50%;
  position: relative;
}

.punto-ubicacion {
  width: 14px;
  height: 14px;
  background: var(--azul);
  border: 2px solid white;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
}
/* ============================================================
   MÓVIL — HOJA INFERIOR DESLIZABLE
   ============================================================
   En pantalla estrecha el grid de tres columnas no vale: el panel quedaba
   en unos 100px. Aquí el mapa pasa a ocupar la pantalla entera y el panel
   se convierte en una hoja que sube desde abajo, como en Google Maps.

   El desplazamiento vertical vive en --hoja-y, que mueve la hoja con
   transform. Se anima transform y no height ni top a propósito: es lo
   único que el navegador puede componer sin recalcular la disposición,
   así que el arrastre va suave incluso con la lista de paradas llena.

   Igual que en escritorio, cambiar el tamaño del mapa obliga a llamar a
   mapa.invalidateSize() desde app.js, o Leaflet deja franjas sin tiles.

   La condición cubre también las tabletas EN VERTICAL, no solo los móviles.
   Medido: a 820px —iPad Air y iPad de 10ª en vertical— el grid de tres
   columnas dejaba el mapa en 406px, la mitad de la pantalla, porque el
   panel mide 380px pase lo que pase. En horizontal (1180px y más) el grid
   sí funciona y se conserva, que es donde una tableta se parece más a un
   escritorio.

   OJO: esta condición está DUPLICADA en app.js (CONSULTA_HOJA). Si se
   toca aquí, hay que tocarla allí o el arrastre dejará de responder
   justo en los tamaños que acaban de cambiar. */
@media (max-width: 768px), (max-width: 1024px) and (orientation: portrait) {
  body {
    /* Alto visible de la hoja cuando está recogida. Deja ver la cabecera,
       el buscador y las primeras fichas, que es lo que se usa de pie en
       una parada sin desplegar nada. */
    --hoja-recogida: 46vh;
    --hoja-alto: 88vh;

    /* Posición de reposo: recogida. app.js sobrescribe esta variable
       durante el arrastre y al soltar la fija en uno de los dos topes. */
    --hoja-y: calc(var(--hoja-alto) - var(--hoja-recogida));

    display: block;
    padding: 0;
    height: 100dvh; /* dvh y no vh: descuenta la barra del navegador móvil */
  }

  #mapa {
    position: fixed;
    inset: 0;
    height: 100dvh;
    width: 100%;
    border-radius: 0;
  }

  #panel {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--hoja-alto);
    transform: translateY(var(--hoja-y));
    border-radius: 26px 26px 0 0;
    /* Más difusa y menos oscura que una sombra normal: la hoja tiene que
       parecer apoyada sobre el mapa, no recortada encima de él. */
    box-shadow: 0 -1px 3px rgba(18, 18, 18, 0.05),
      0 -12px 40px rgba(18, 18, 18, 0.12);
    z-index: 1000; /* por encima de los controles de Leaflet */
    transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
  }

  /* Durante el arrastre la hoja debe seguir al dedo sin suavizado, o va
     siempre un cuarto de segundo por detrás y se siente rota. */
  #panel.arrastrando {
    transition: none;
  }

  /* El divisor es para redimensionar en horizontal; aquí no tiene sentido. */
  #divisor {
    display: none;
  }

  /* La banda naranja hace de tirador de la hoja: ya estaba arriba del todo
     y es la zona más fácil de acertar con el pulgar. */
  #panel-header {
    position: relative;
    padding: 15px 16px 16px;
    border-radius: 26px 26px 0 0;
    cursor: grab;
    touch-action: none; /* si no, el gesto lo captura el scroll de la página */
    flex-shrink: 0;
  }

  #panel-header::before {
    content: "";
    position: absolute;
    top: 7px;
    left: 50%;
    transform: translateX(-50%);
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: rgba(18, 18, 18, 0.28);
  }

  #panel.arrastrando #panel-header {
    cursor: grabbing;
  }

  /* El hueco de la barra de gestos del iPhone: sin esto, la última ficha
     de la lista queda debajo de ella y no se puede pulsar. */
  #panel {
    padding-bottom: env(safe-area-inset-bottom);
  }

  /* El botón de ubicación sube por encima de la hoja recogida en vez de
     quedarse detrás. */
  #boton-ubicacion {
    bottom: calc(var(--hoja-recogida) + 16px);
    right: 16px;
    z-index: 999;

    /* Sin transición sobre "bottom" a propósito. Es una propiedad de layout,
       y este botón arrastra un backdrop-filter de 20px: animarla obligaría a
       recomponer el desenfoque en cada fotograma. Y no se gana nada, porque
       "bottom" aquí solo cambia al cruzar el punto de ruptura o al girar el
       teléfono —no sigue a la hoja durante el arrastre—, que es un momento
       en el que la pantalla entera se recoloca de todas formas. */
  }

  /* Objetivos táctiles: en escritorio se pulsan con ratón, aquí con el
     pulgar. 44px es el mínimo recomendado para no fallar el toque. */
  .filtro-boton,
  .boton-favorito,
  .boton-volver {
    min-height: 44px;
  }

  /* 16px es el umbral por debajo del cual Safari en iOS hace zoom
     automático al enfocar un campo, descuadrando toda la página. */
  #input-buscar {
    font-size: 16px;
  }

  /* --- EL NÚMERO, EN LA CALLE ---
     Este es el dato por el que se ha abierto la aplicación, y aquí se lee de
     pie, a un brazo, con sol de frente y a menudo de reojo mientras se mira
     si viene el autobús.

     El contraste ya era el máximo posible (tinta sobre blanco, 17:1), así que
     lo que quedaba era el tamaño. De 24 a 34px, y de 600 a 700: con reflejos,
     el trazo más grueso se sostiene mejor que el fino. En escritorio se queda
     como estaba, porque allí se mira de cerca y en interior. */
  .tiempo-proximo {
    /* 30 y no 34. Con 34 el tiempo medía 2,4 veces el destino y la tarjeta se
       desequilibraba; 30 sigue leyéndose a un brazo y con sol, que era el
       motivo de agrandarlo, sin comerse el resto. */
    font-size: 30px;
  }

  /* En móvil el número sube a 34px, así que el texto tiene que subir también
     —si no, "En camino" se vería más pequeño que aquí en escritorio— pero sin
     acercarse al tamaño del dígito. */
  .tiempo-proximo.es-texto {
    font-size: 20px;
  }

  .tiempo-proximo .unidad {
    font-size: 15px;
  }
}

/* En una tableta vertical la pantalla es mucho más alta que un móvil, así
   que el mismo 46vh dejaba asomar más de 500px de hoja y se comía el mapa.
   Se declara en vh y no con min() a propósito: app.js lee esta variable y
   la convierte a píxeles, y solo sabe interpretar vh o px. */
@media (min-width: 769px) and (max-width: 1024px) and (orientation: portrait) {
  body {
    --hoja-recogida: 32vh;
  }
}

/* --- PANTALLAS TÁCTILES ---
   En un dispositivo sin ratón, :hover se activa al tocar y se queda pegado
   hasta que se toca otra cosa: una ficha levantada, un botón agrandado. El
   navegador lo declara en (hover: none), así que aquí se devuelven a su
   estado normal los efectos que se notan, que son los de movimiento.
   Los cambios de color se dejan estar: son sutiles y no descolocan nada. */
/* OJO AL AÑADIR UN :hover NUEVO CON MOVIMIENTO.
   
   Este bloque va al revés de lo habitual: en vez de encerrar cada efecto en
   @media (hover: hover), se deshacen aquí uno a uno. Funciona, pero tiene una
   consecuencia que hay que conocer: una regla :hover nueva nace SIN proteger
   hasta que alguien se acuerde de añadirla también aquí abajo. */
@media (hover: none) {
  #lista-resultados li:hover {
    box-shadow: var(--sombra-sutil);
    transform: none;
  }

  #boton-ubicacion:hover {
    background: rgba(255, 255, 255, 0.72);
    transform: none;
  }

  .filtro-boton:hover:not(.activo) {
    background: none;
    color: var(--texto-suave);
  }
}

/* --- DISTANCIA ANDANDO ---
   Va bajo el nombre de la parada, en tono secundario: informa de cuánto
   cuesta llegar sin competir con el nombre, que es lo que se busca al leer
   la lista. */
.distancia-andando {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--texto-suave);
  font-variant-numeric: tabular-nums;
}

/* El nombre de la parada trunca igual que el de las líneas. La regla que ya
   existía estaba acotada a .resultado-linea; ahora que las paradas también
   tienen dos líneas de texto, se aplica a las dos clases de resultado. */
#lista-resultados .titulo {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* En la ficha de la parada abierta va junto al código, separada por un
   punto, en vez de en su propia línea: ahí el espacio vertical es más caro
   porque debajo vienen ya los tiempos. */
#codigo-parada-actual .distancia-andando {
  display: inline;
  margin-top: 0;
}

#codigo-parada-actual .distancia-andando::before {
  content: " · ";
}

/* --- PIE LEGAL ---
   Un solo enlace, fuera de las tres vistas para que salga bajo cualquiera de
   ellas. Tamaño y color de texto secundario: tiene que estar, pero no compite
   con los tiempos de llegada, que es a lo que se viene.

   --acento-texto y no --acento: el naranja de marca sobre blanco da 2:1 de
   contraste y sería ilegible a este tamaño. */
#pie-legal {
  /* Anclado al fondo del panel, no al final del contenido.
     
     Estaba puesto detrás de las tres vistas, y medido salía por DEBAJO del
     borde de la pantalla en cuanto la lista de resultados crecía: en la hoja
     de móvil no se veía sin desplegarla y bajar del todo. Un enlace que hay
     que buscar así no cumple su función.

     sticky y no fixed: se queda pegado al fondo del panel mientras este se
     desplaza, sin salirse de él ni taparle nada al mapa.

     margin-top:auto lo empuja al fondo cuando el contenido es corto (el panel
     es un flex en columna); sin eso, con la lista vacía quedaría flotando a
     media altura. */
  margin: auto 0 0;
  position: sticky;
  bottom: 0;
  padding: 10px 16px 12px;
  font-size: 12px;
  text-align: center;
  /* Fondo opaco: si no, los resultados se leen por debajo al desplazarse. */
  background: var(--superficie);
  border-top: 1px solid var(--separador);
}

#pie-legal a,
#boton-informacion {
  color: var(--texto-suave);
  text-decoration: none;
}

/* "Planos y tarifas" bajó aquí desde la pila del panel, y con ello pierde el
   relleno: era una caja gris del mismo tamaño y color que el buscador, y el
   viajero tenía que leer las dos para saber cuál era el campo. Aquí es una
   fila de texto más, al lado del enlace legal, que es donde vive lo que se
   consulta de vez en cuando. */
#boton-informacion {
  min-height: 44px;
  padding: 0 8px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

#boton-informacion:hover,
#pie-legal a:hover {
  color: var(--acento-texto);
}

/* Un punto entre los dos, porque pegados se leen como una sola frase:
   "Planos y tarifas Privacidad y condiciones de uso". */
#boton-informacion::after {
  content: "·";
  margin-left: 8px;
  opacity: 0.5;
}

#pie-legal a:hover {
  color: var(--acento-texto);
  text-decoration: underline;
}

/* ==========================================================================
   ACCESIBILIDAD
   ========================================================================== */

/* --- LO PULSABLE DE UN RESULTADO ES UN BOTÓN ---
   Antes el <li> entero llevaba un listener de click, lo que lo dejaba fuera
   del alcance del teclado por completo. Ahora dentro hay un <button> real,
   hermano de la estrella de favorito. Estas reglas le quitan la apariencia
   de botón del navegador para que la ficha se vea exactamente igual que
   antes: el cambio es de semántica, no de diseño. */
.resultado-principal {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: inherit;
  /* Reset: un <button> trae fuente, fondo, borde, relleno y centrado
     propios del navegador, y ninguno vale aquí. */
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* En el recorrido de línea el botón ocupa la fila entera, porque ahí no hay
   estrella al lado con la que repartirse el espacio. */
.parada-recorrido .resultado-principal {
  gap: 10px;
  width: 100%;
}

/* --- FOCO VISIBLE ---
   No había ninguno salvo en el divisor. Sin esto, aunque ya se pueda
   tabular, no se ve dónde estás: navegar así es peor que no poder.

   :focus-visible y no :focus para que el aro salga con el teclado pero no
   al hacer clic con el ratón, que es cuando molesta y no aporta.

   El aro va en --acento-texto (el naranja oscuro, 5,5:1 sobre blanco) y no
   en el naranja de marca, que a 2:1 no se distinguiría del fondo. */
:focus-visible {
  outline: 2px solid var(--acento-texto);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Dentro de una ficha, el aro se separa un poco más para rodearla entera en
   vez de cortar el texto por dentro. */
#lista-resultados .resultado-principal:focus-visible,
.parada-recorrido .resultado-principal:focus-visible {
  outline-offset: 4px;
}

/* --- TEXTO SOLO PARA LECTORES DE PANTALLA ---
   El buscador solo tenía placeholder, que no es una etiqueta: desaparece al
   escribir y no da nombre accesible. Esta clase deja la etiqueta en el
   documento sin ocuparle sitio a nadie.

   No se usa display:none ni visibility:hidden a propósito: las dos ocultan
   el texto TAMBIÉN para el lector de pantalla, que es justo lo contrario de
   lo que se busca. */
.solo-lector {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- OBJETIVOS TÁCTILES ---
   La estrella mide 34px, por debajo de los 44px recomendados. En móvil ya se
   corregía dentro de su @media, pero una tableta en horizontal NO entra en
   modo hoja y se toca igual con el dedo.

   Se agranda el área sensible con un pseudo-elemento en vez de agrandar el
   botón: así el círculo se sigue viendo de 34px y no descoloca la ficha. */
.boton-favorito {
  position: relative;
}

.boton-favorito::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

/* --- SUPERFICIES DEL NAVEGADOR ---
   Selección, cursor de texto y barra de desplazamiento vienen con los
   colores por defecto del navegador, que no son de ninguna paleta. Son lo
   último que se mira y lo que delata que una interfaz está montada en vez
   de construida. */
::selection {
  background: var(--acento-suave);
  color: var(--texto);
}

#input-buscar {
  caret-color: var(--acento-texto);
}

#panel {
  scrollbar-width: thin;
  scrollbar-color: var(--borde) transparent;
}

/* --- MOVIMIENTO REDUCIDO ---
   La hoja inferior recorre casi toda la altura de la pantalla. Para quien
   tiene un trastorno vestibular, ese desplazamiento provoca mareo real.

   No se matan las transiciones con 0.01ms: eso destruye la respuesta al
   tacto y deja la interfaz saltando entre estados sin explicar nada. Se
   acortan mucho y se conserva el cambio de estado, que es lo que informa. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  /* El desplazamiento de la hoja es lo que de verdad marea: se reduce a un
     cambio casi instantáneo, pero sigue habiendo transición para que el
     cambio de posición no parezca un salto de la pantalla entera. */
  #panel,
  #boton-ubicacion {
    transition-duration: 0.08s !important;
  }

  /* El resto de efectos son de hover y de pulsación: no desplazan la vista,
     así que se quedan, pero sin el movimiento. */
  #lista-resultados li:hover,
  #lista-resultados li:active,
  #boton-ubicacion:hover,
  #boton-ubicacion:active {
    transform: none;
  }
}

/* --- HORARIOS DE PASO ---
   Plegado por defecto con <details>, que trae el comportamiento de abrir y
   cerrar sin JavaScript y es accesible con teclado de serie. */
#horarios-linea {
  margin: 4px 12px 8px;
  border-radius: var(--radio-medio);
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
  overflow: hidden;
}

#horarios-linea summary {
  padding: 12px 14px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  /* El triángulo por defecto de Safari se sale del sistema visual; se quita
     y se dibuja el estado con el propio bloque. */
  list-style: none;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

#horarios-linea summary::-webkit-details-marker {
  display: none;
}

#horarios-linea summary::after {
  content: "▾";
  color: var(--texto-suave);
  transition: transform 0.16s var(--ease-out);
}

#horarios-linea[open] summary::after {
  transform: rotate(180deg);
}

#contenido-horarios {
  padding: 0 14px 14px;
}

/* El aviso de que el volcado no distingue tipos de día. Va en ámbar lavado
   porque informa, no alarma: no es un error, es una limitación del origen. */
.horarios-aviso {
  margin: 0 0 12px;
  padding: 10px 12px;
  border-radius: var(--radio-pequeno);
  background: var(--acento-suave);
  color: var(--acento-texto);
  font-size: 12px;
  line-height: 1.45;
}

.horarios-vacio {
  margin: 0;
  color: var(--texto-suave);
  font-size: 13px;
}

.horario-destino {
  margin: 14px 0 8px;
  font-size: 13px;
  font-weight: 600;
}

.horario-dias {
  margin: 10px 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--texto-suave);
}

/* Las salidas en rejilla y no en lista: son decenas de horas y en columna
   obligarían a desplazarse por toda la tabla para ver la que interesa.
   auto-fill deja que quepan las que quepan según el ancho del panel. */
.horario-salidas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(52px, 1fr));
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.horario-salidas li {
  padding: 5px 0;
  border-radius: 8px;
  background: var(--fondo);
  text-align: center;
  font-size: 13px;
  /* Cifras de ancho fijo: en una rejilla de horas, si no, las columnas
     bailan y la tabla se lee peor. */
  font-variant-numeric: tabular-nums;
}

/* Las frecuencias son pocas filas y llevan dos datos, así que van en lista. */
.horario-franjas {
  margin: 0;
  padding: 0;
  list-style: none;
}

.horario-franjas li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--separador);
  font-size: 13px;
}

.horario-franjas li:last-child {
  border-bottom: none;
}

.franja-horas {
  font-variant-numeric: tabular-nums;
}

.franja-cada {
  color: var(--texto-suave);
  white-space: nowrap;
}

/* --- HOJA OFICIAL DE HORARIOS ---
   Las dos imágenes que publica el Consorcio, una por sentido. */
.selector-sentido-horario {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 10px;
  border-radius: 14px;
  background: var(--fondo);
}

.boton-sentido-horario {
  flex: 1;
  min-height: 44px;
  padding: 8px 10px;
  border: 0;
  border-radius: 12px;
  background: none;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--texto-suave);
  cursor: pointer;
  transition: background 0.16s var(--ease-out), color 0.16s var(--ease-out);
}

.boton-sentido-horario.activo {
  background: var(--superficie);
  color: var(--acento-texto);
  font-weight: 600;
  box-shadow: var(--sombra-sutil);
}

/* La hoja es alta y estrecha (1040x2708 en la 103), así que se acota su alto
   y se desplaza por dentro: si no, empuja el recorrido de la línea tan abajo
   que hay que hacer scroll durante un rato para volver a encontrarlo. */
.marco-horario {
  max-height: 60vh;
  overflow: auto;
  border-radius: var(--radio-pequeno);
  background: var(--fondo);
  /* Desplazamiento con inercia en iOS dentro del marco. */
  -webkit-overflow-scrolling: touch;
}

.imagen-horario {
  display: block;
  width: 100%;
  height: auto;
}

.enlace-horario {
  display: inline-block;
  margin-top: 10px;
  font-size: 12px;
  color: var(--acento-texto);
}

/* --- ACCESIBILIDAD DE LA ESTACIÓN ---
   Solo se pinta cuando se sabe. Ver el comentario de app.js sobre por qué los
   tres grados no se pueden fundir en uno. */
.accesibilidad {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.3;
}

/* Verde de sistema: aquí el color SÍ significa algo —se puede entrar en
   silla— que es la única condición bajo la que este proyecto usa color. */
.accesibilidad-universal {
  background: rgba(52, 199, 89, 0.14);
  color: #1c7a35; /* el --verde puro sobre su propio fondo no llega a 4,5:1 */
}

/* Ascensor sí, medidas complementarias no: se puede entrar, pero no es lo
   mismo. Neutro a propósito, para no prometer de más. */
.accesibilidad-solo_ascensor {
  background: var(--gris-superficie);
  color: var(--texto-suave);
}

/* Sin ascensor ni rampa. NO lleva icono de silla: sería el error que más daño
   hace de todos los posibles aquí. */
.accesibilidad-solo_medidas {
  background: var(--acento-suave);
  color: var(--acento-texto);
}

/* El icono de red de cada resultado de parada. Ocupa el mismo hueco de 34px
   que el número de las líneas, para que las dos clases de resultado queden
   alineadas en la misma lista.

   object-fit: contain y no un tamaño fijo porque los tres PNG tienen
   proporciones muy distintas —el autobús es vertical y el rombo del Metro
   apaisado— y estirarlos los deforma. Es la misma razón que en los filtros. */
.resultado-icono {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  object-fit: contain;
  padding: 5px;
  background: var(--gris-superficie);
  border-radius: 10px;
  box-sizing: border-box;
}

/* La versión de una pieza, para los resultados del buscador. Va pegada al
   borde derecho con margin-left auto, antes de la estrella: así no compite
   con el nombre por el ancho ni rompe su truncado. */
.accesibilidad-compacta {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: auto;
  padding: 4px;
  border-radius: 999px;
}

/* --- AVISOS DE SERVICIO ---
   El botón solo existe cuando hay algo en curso, así que puede permitirse
   llamar la atención: si está, importa. */
#boton-incidencias {
  display: flex;
  align-items: center;
  gap: 8px;
  width: calc(100% - 32px);
  /* 12px arriba como el resto de bloques del panel. Nació pegado bajo la
     cabecera, donde el margen superior sobraba; al bajarlo detrás de los
     filtros se quedó sin separación. */
  margin: 12px 16px 0;
  min-height: 44px;
  padding: 10px 14px;
  border: 0;
  border-radius: var(--radio-pequeno);
  background: var(--acento-suave);
  color: var(--acento-texto);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background 0.16s var(--ease-out);
}

/* El triángulo de aviso, dibujado. A este tamaño un emoji se ve distinto en
   cada sistema y no hereda el color. */
/* Sin esto el botón se ve SIEMPRE, aunque app.js le ponga hidden.
   La regla de arriba selecciona por id, y eso pesa más que el
   [hidden] { display: none } que trae el navegador de fábrica, así que gana
   display: flex y el atributo no hace nada.

   Llegó a producción: con cero avisos en curso quedaba una caja naranja
   vacía, con su triángulo y su flecha, que llevaba a una lista de avisos ya
   terminados. El test que debía cazarlo comprobaba b.hidden, o sea la
   propiedad que app.js acababa de escribir, y no si el botón se veía. */
#boton-incidencias[hidden] {
  display: none;
}

#boton-incidencias::before {
  content: "";
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  background: currentColor;
  -webkit-mask: var(--icono-aviso) center / contain no-repeat;
  mask: var(--icono-aviso) center / contain no-repeat;
}

#boton-incidencias::after {
  content: "›";
  margin-left: auto;
  font-size: 17px;
  opacity: 0.6;
}

#boton-incidencias:hover {
  background: #fbe7c8;
}

#vista-incidencias {
  display: none;
  flex-direction: column;
  padding: 12px 16px 16px;
}

#titulo-incidencias {
  margin: 8px 0 12px;
  font-size: 15px;
  font-weight: 600;
}

#lista-incidencias {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.incidencia {
  padding: 12px 14px;
  border-radius: var(--radio-medio);
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
}

/* Las que ya pasaron se atenúan en vez de esconderse: saber que el desvío de
   tu línea YA TERMINÓ también informa, y explica por qué el autobús venía
   raro esta mañana. Pero no puede pesar lo mismo que lo que está pasando. */
.incidencia-terminada {
  opacity: 0.62;
}

.incidencia-cabecera {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}

.incidencia-estado {
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  background: var(--gris-superficie);
  color: var(--texto-suave);
}

/* Rojo solo para lo que está ocurriendo ahora. Es el único sitio de toda la
   aplicación donde se usa, y por eso significa algo. */
.incidencia-en-curso .incidencia-estado {
  background: rgba(255, 59, 48, 0.12);
  color: #b3261e; /* el --rojo puro sobre su fondo no llega a 4,5:1 */
}

.incidencia-programada .incidencia-estado {
  background: var(--acento-suave);
  color: var(--acento-texto);
}

.incidencia-fechas {
  font-size: 11px;
  color: var(--texto-suave);
  font-variant-numeric: tabular-nums;
}

.incidencia-titulo {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
}

.incidencia-descripcion {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--texto-suave);
}

.incidencia-enlace {
  display: inline-block;
  margin-top: 8px;
  font-size: 12px;
  color: var(--acento-texto);
}

/* --- PLANOS Y TARIFAS ---
   El botón vive en el pie (ver #boton-informacion, más arriba). Lo que queda
   aquí es la vista. */
#vista-informacion {
  display: none;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  padding: 0 16px 16px;
}

.informacion-titulo {
  margin: 14px 0 2px;
  font-size: 17px;
  font-weight: 700;
  color: var(--texto);
}

/* La fecha va pegada al título y no al pie: un precio de hace dos años sin
   fecha delante es una mentira, y al pie no lo lee nadie. */
.informacion-vigencia {
  margin: 2px 0 10px;
  font-size: 12px;
  color: var(--texto-suave);
}

.lista-fichas {
  list-style: none;
  margin: 10px 0 4px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ficha-enlace a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 11px 14px;
  border-radius: var(--radio-pequeno);
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
  color: inherit;
  text-decoration: none;
}

.ficha-enlace a:hover {
  background: #fafafa;
}

.ficha-texto {
  flex: 1;
  min-width: 0;
}

.ficha-titulo {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--texto);
}

.ficha-detalle {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--texto-suave);
}

/* El peso, bien visible: seis megas con datos móviles en la calle es la
   diferencia entre abrirlo y arrepentirse. */
.ficha-peso {
  flex-shrink: 0;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--gris-superficie);
  color: var(--texto-suave);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.tarifa-grupo {
  margin: 16px 0 6px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--texto-suave);
}

.lista-tarifas {
  list-style: none;
  margin: 0;
  padding: 0;
  border-radius: var(--radio-pequeno);
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
  overflow: hidden;
}

.tarifa {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 10px 14px;
}

.tarifa + .tarifa {
  border-top: 1px solid var(--gris-superficie);
}

.tarifa-que {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  color: var(--texto);
}

.tarifa-nota {
  display: block;
  margin-top: 1px;
  font-size: 12px;
  color: var(--texto-suave);
}

/* Tabular para que las comas de los precios queden en columna. */
.tarifa-precio {
  flex-shrink: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--texto);
  font-variant-numeric: tabular-nums;
}

/* --- INTERRUPTOR DE ACCESIBILIDAD ---
   Comparte fila con el grupo de modos en vez de ocupar una propia: al sacarlo
   del grupo excluyente había ganado una fila de 52px, y eso se comía justo lo
   que se acababa de recuperar quitando "Planos y tarifas" de la pila.

   Fuera del grupo a propósito: no es una red de transporte sino una propiedad,
   y como quinta píldora excluyente hacía desaparecer la EMT y el CRTM enteros
   al pulsarla. */
.fila-filtros {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 16px 0;
}

.fila-filtros #filtros-fuente {
  flex: 1;
  min-width: 0;
  margin: 0;
}

/* Solo el símbolo, sin etiqueta: es el internacional de accesibilidad, de los
   pocos que se entienden sin leer, y la etiqueta va en aria-label y en title.
   Con texto no cabía sin estrechar "Interurbano" hasta truncarlo. */
#filtro-accesibles {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--texto-suave);
  cursor: pointer;
  transition: background 0.18s var(--ease-out), color 0.18s var(--ease-out);
}

#filtro-accesibles:hover {
  color: var(--texto);
}

/* Encendido: el mismo verde que el distintivo de las estaciones accesibles,
   para que se lea como "estoy viendo esas" y no como un botón cualquiera. El
   color aquí significa algo, que es la única condición para usarlo. */
#filtro-accesibles.activo {
  background: rgba(52, 199, 89, 0.14);
  color: #1c7a35;
}

/* La nota que explica el alcance del filtro de accesibilidad. Aparece solo
   con el filtro puesto: es cuando desaparecen los autobuses de la lista y hay
   que decir por qué, para que la ausencia no se lea como "no son accesibles".

   [hidden] con el id delante, porque una regla de id gana al [hidden] que
   trae el navegador y el atributo se quedaría sin efecto. Ha pasado ya. */
#nota-accesibles {
  margin: 12px 16px 0;
  padding: 10px 12px;
  border-radius: var(--radio-pequeno);
  background: var(--gris-superficie);
  color: var(--texto-suave);
  font-size: 12px;
  line-height: 1.4;
}

#nota-accesibles[hidden] {
  display: none;
}

#nota-accesibles strong {
  color: var(--texto);
  font-weight: 600;
}


/* El bloque de accesibilidad de la vista de consulta. Es prosa y no fichas
   porque lo que hay que transmitir es un matiz —qué se sabe y qué no—, y una
   ficha con un distintivo lo aplanaría justo en el sitio donde aplanarlo
   sería mentir. */
.bloque-accesibilidad {
  margin: 10px 0 4px;
  padding: 12px 14px;
  border-radius: var(--radio-pequeno);
  background: var(--superficie);
  box-shadow: var(--sombra-sutil);
  font-size: 13px;
  line-height: 1.5;
  color: var(--texto-suave);
}

.bloque-accesibilidad p {
  margin: 0 0 8px;
}

.bloque-accesibilidad ul {
  margin: 0;
  padding-left: 18px;
}

.bloque-accesibilidad li + li {
  margin-top: 6px;
}

.bloque-accesibilidad strong {
  color: var(--texto);
  font-weight: 600;
}
