@page "/"
@rendermode InteractiveServer

@using System.Collections.Concurrent
@using System.Globalization
@using System.Text.Json
@using LeafletForBlazor
@using RutasDBUS.Modelos.Planificacion
@using RutasDBUS.Modelos.RedBus
@using RutasDBUS.Servicios
@using RutasDBUS.Servicios.RedBus
@using RutasDBUS.Servicios.Caminata
@using RutasDBUS.Servicios.Planificacion
@using System.Text.RegularExpressions;
@using System.Text
@using RutasDBUS.Servicios.Horarios





<div class="full-page">
    <!-- HEADER SUPERIOR -->
    <div class="rutas-header rutas-header-linea">

        <!-- IZQUIERDA -->
        <div class="header-left">
            <h3 class="titulo-app">
                Planificador de rutas en Dbus
                <span class="app-version-inline">@_versionApp</span>
            </h3>
            <small>
                Haz doble clic en el mapa para marcar origen y destino
            </small>
        </div>

        <!-- CENTRO: ITINERARIOS -->
        <div class="header-center">
            <label class="nowrap">Itinerarios:</label>

<input type="search"
       class="config-input header-center-input"
       placeholder="Filtrar (línea, iti, nombre)..."
       @bind="ItFiltro"
       @bind:event="oninput"/>




<select class="config-input header-center-input"
        @key="_selectItKey"
        @bind="_itSeleccionadoId">
                @foreach (var it in _itItemsFiltrados)
                {
                    <option value="@it.Id">@it.Text</option>
                }
            </select>

            <button class="btn-ghost" @onclick="PintarItSeleccionado">Ver</button>
                        <button class="btn-ghost" @onclick="QuitarItSeleccionado">Ocultar</button>
            <button class="btn-ghost" @onclick="PintarItFiltro">Ver filtro</button>

            <button class="btn-ghost" @onclick="QuitarTodosItinerarios">Ocultar Todos</button>

            <label class="line-filter__toggle nowrap"
                   style="display:flex; align-items:center; gap:.3rem; margin-left:.25rem; margin-bottom:0;">
                <input type="checkbox"
                       checked="@_usarColorRealLineaEnItinerarios"
                       @onchange="OnCambioModoColorItinerarios" />
                <span style="font-size:.9rem;">Color línea</span>
            </label>
        </div>

        <!-- DERECHA -->
        <div class="header-right">
            <div class="pill-live pill-ok" title="Hora de Referencia">
    🕒 @_horaAhoraTxt
</div>
<button type="button"
        class="btn-ghost btn-icon search-toggle"
        title="@(_mostrarBuscadorMapa ? "Ocultar buscador" : "Mostrar buscador")"
        @onclick="ToggleBuscadorMapa">
    <span class="search-icon @(_mostrarBuscadorMapa ? "off" : "")">🔎</span>
</button>
            @if (_inspectorActivo)
            {
                <div class="pill-live pill-warn">
                    <span class="pill-dot"></span>
                    Punto (Z)
                </div>
            }
            <button type="button"
                    class="pill-live pill-clickable @( _mostrarParadas ? "pill-ok" : "pill-bad")"
                    title="@(_mostrarParadas ? "Ocultar paradas" : "Mostrar paradas")"
                    @onclick="ToggleParadasAsync">
                <span class="pill-dot"></span>
                @(_mostrarParadas ? "Paradas visibles" : "Paradas ocultas")
            </button>


            <button class="btn-ghost" title="limpiar rutas en pantalla" @onclick="ReiniciarSeleccion">
                Reiniciar
            </button>

            <button type="button" class="btn-ghost btn-icon" title="Historial de rutas" @onclick="ToggleHistorialPanel">
                <span class="history-open-icon" aria-hidden="true">H</span>
            </button>

            <button class="btn-ghost" title="Configuración" @onclick="ToggleConfigPanel">
                ⚙
            </button>
        </div>

    </div>

    <!-- CONTENEDOR DEL MAPA -->
    <div class="map-container opacidad-@_nivelBrilloMapa">
        <RealTimeMap @ref="_mapa"
                     Parameters="_parametrosMapa"
                     height="100%"
                     width="100%"
                     OnClickMap="AlHacerClickEnMapa"
                     OnMouseMove="OnMouseMoveMapa" />

        <div class="coords-bar">
            @if (_coordsMouse is (double lat, double lon))
            {
                <span>Latitud: @lat.ToString("0.000000") · Longitud: @lon.ToString("0.000000")</span>
            }
        </div>

        <!-- BUSCADOR -->
        @if (_mostrarBuscadorMapa)
        {
            <div class="gm-search-panel">
                <div class="gm-search-row">
                    <div class="gm-search-inputs">
                        <div class="gm-input-group">
                            <label>Origen</label>
                            <input type="text"
                                   placeholder="Calle, direccion, lugar o parada"
                                   autocomplete="off"
                                   @bind="_textoBusquedaOrigen"
                                   @bind:event="oninput"
                                   @bind:after="ActualizarSugerenciasOrigenAsync"
                                   @onfocus="MostrarSugerenciasOrigenAsync" />
                            @if (SugerenciasOrigenVisibles.Count > 0)
                            {
                                <div class="gm-suggestions">
                                    @foreach (var sugerencia in SugerenciasOrigenVisibles)
                                    {
                                        <button type="button"
                                                class="gm-suggestion"
                                                @onclick="() => SeleccionarSugerenciaBusquedaAsync(CampoBusquedaMapa.Origen, sugerencia)">
                                            <span class="gm-suggestion__type">@sugerencia.Tipo</span>
                                            <span class="gm-suggestion__text">
                                                <span class="gm-suggestion__title">@sugerencia.Titulo</span>
                                                <span class="gm-suggestion__subtitle">@sugerencia.Subtitulo</span>
                                            </span>
                                        </button>
                                    }
                                </div>
                            }
                        </div>

                        <button type="button"
                                class="gm-swap-btn"
                                title="Intercambiar origen/destino"
                                @onclick="IntercambiarOrigenDestino">
                            ⇅
                        </button>

                        <div class="gm-input-group">
                            <label>Destino</label>
                            <input type="text"
                                   placeholder="Calle, direccion, lugar o parada"
                                   autocomplete="off"
                                   @bind="_textoBusquedaDestino"
                                   @bind:event="oninput"
                                   @bind:after="ActualizarSugerenciasDestinoAsync"
                                   @onfocus="MostrarSugerenciasDestinoAsync" />
                            @if (SugerenciasDestinoVisibles.Count > 0)
                            {
                                <div class="gm-suggestions">
                                    @foreach (var sugerencia in SugerenciasDestinoVisibles)
                                    {
                                        <button type="button"
                                                class="gm-suggestion"
                                                @onclick="() => SeleccionarSugerenciaBusquedaAsync(CampoBusquedaMapa.Destino, sugerencia)">
                                            <span class="gm-suggestion__type">@sugerencia.Tipo</span>
                                            <span class="gm-suggestion__text">
                                                <span class="gm-suggestion__title">@sugerencia.Titulo</span>
                                                <span class="gm-suggestion__subtitle">@sugerencia.Subtitulo</span>
                                            </span>
                                        </button>
                                    }
                                </div>
                            }
                        </div>
                    </div>

                    <div class="gm-search-actions">
                        <button class="gm-search-button" @onclick="BuscarRutaDesdeBuscador">
                            Buscar ruta
                        </button>

                        <button type="button"
                                class="btn-ghost gm-search-hide-btn"
                                title="Ocultar buscador"
                                @onclick="ToggleBuscadorMapa">
                            ✕
                        </button>
                    </div>
                </div>

            </div>
        }
    </div>
    @* STACK DE POPUPS (izquierda) *@
    @if (_paradaClicada is not null || _itinerarioClicado is not null || _popupInspectorVisible)
    {
        <div class="popup-stack-left">

            <!-- POPUP PARADA -->
            @if (_paradaClicada is not null)
            {
                <div class="popup-parada popup-slot draggable-popup" data-drag-key="popup-parada">
                    <div class="popup-parada-header draggable-popup-handle">
                        @_paradaClicada.Nombre
                    </div>

                    <div class="popup-parada-body">
                        <div><b>Código:</b> @CodigoParadaFormateado(_paradaClicada.Codigo)</div>

                        @if (!string.IsNullOrWhiteSpace(_paradaClicada.Abreviatura))
                        {
                            <div><b>Abrev.:</b> @_paradaClicada.Abreviatura</div>
                        }
                        @if (_paradaClicada.Altura > 0)
                        {
                            <div><b>Altitud (J):</b> @_paradaClicada.Altura.ToString("0") m</div>
                        }
                        @if (_paradaElevG is not null)
                        {
                            <div><b>Altitud (G):</b> @_paradaElevG.Value.ToString("0.00", CultureInfo.InvariantCulture) m</div>
                        }

                        @if (_usarHorariosTeoricos)
                        {
                            <hr style="margin:.6rem 0; opacity:.35" />

                            @if (!_horariosOk)
                            {
                                <div class="muted" style="font-size:.85rem;">
                                    @(!string.IsNullOrWhiteSpace(_horariosError) ? _horariosError : "Cargando horarios…")
                                </div>
                            }
                            else if (_nextDeps.Count == 0)
                            {
                                <div class="muted" style="font-size:.85rem;">
                                    No hay salidas próximas para esta parada.
                                </div>
                            }
                            else
                            {
                                <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:.25rem;">
                                    <div style="font-weight:600;">
                                        Horarios (@_nextDeps.Count)
                                    </div>

                                    <button type="button"
                                            class="btn-ghost"
                                            title="@HorarioOrdenTooltip"
                                            style="padding:.1rem .45rem; min-width:auto; line-height:1.1;"
                                            @onclick="ToggleOrdenHorarios">
                                        @HorarioOrdenIcono
                                    </button>
                                </div>

                                <div style="max-height: 220px; overflow-y: auto; border: 1px solid rgba(255,255,255,.12); border-radius: 6px; padding: .35rem .5rem; scroll-behavior: smooth;">
                                    <ul style="margin:0; padding-left:1.1rem;">
                                        @foreach (var x in NextDepsOrdenados)
                                        {
                                            <li id="@x.AnchorId"
                                                style="margin:.15rem 0; @(x.EsProximo ? "background: rgba(255,255,255,.12); border-radius:6px; padding:2px 6px;" : "")">
                                                <b>@x.Hora</b> - @x.LineaTxt
                                            </li>
                                        }
                                    </ul>
                                </div>
                            }
                        }

                    </div>

                    <button class="popup-parada-cerrar" @onclick="() => { _paradaClicada = null; _paradaElevG = null; }">
                        ×
                    </button>
                </div>
            }

            <!-- POPUP ITINERARIO -->
            @if (_itinerarioClicado is not null)
            {
                var vReal = GetVarianteRealClicada();

                <div class="popup-parada popup-slot popup-itinerario draggable-popup" data-drag-key="popup-itinerario">
                    <div class="popup-parada-header draggable-popup-handle">
                        @GetTextoItinerarioClicado()
                    </div>
                    <div class="popup-parada-body popup-itinerario-body">
                        @if (vReal is not null)
                        {
                            <div style="margin-top:.25rem;">
                                <div><b>Paradas:</b> @(vReal.CodigosParadas?.Count ?? 0)</div>
                                <div><b>Trayecto:</b> @ConstruirTextoRecorridoVariante(vReal)</div>
                                <div><b>Recorrido:</b> @FormatearDistanciaVariante(vReal)</div>
                            </div>
                        }
                    </div>

                    <button class="popup-parada-cerrar" @onclick="() => { _itinerarioClicado = null; _itinerarioClicadoSubId = null; }">
                        ×
                    </button>
                </div>
            }

            <!-- POPUP INSPECTOR -->
            @if (_popupInspectorVisible)
            {
                <div class="popup-parada popup-slot popup-inspector draggable-popup" data-drag-key="popup-inspector">
                    <div class="popup-parada-header draggable-popup-handle">
                        Punto (Z)
                    </div>

                    <div class="popup-parada-body">
                        <div><b>Latitud:</b> @_inspectorLat.ToString("0.000000")</div>
                        <div><b>Longitud:</b> @_inspectorLon.ToString("0.000000")</div>

                        <div>
                            <b>Altitud (O):</b>
                            @(_inspectorElev is null
                                                ? "-"
                                                : _inspectorElev.Value.ToString("0.00", CultureInfo.InvariantCulture) + " m")
                                                                                                                         </div>

                        <div>
                            <b>Altitud (G):</b>
                            @(_inspectorElevIdee is null
                                                ? "-"
                                                : _inspectorElevIdee.Value.ToString("0.00", CultureInfo.InvariantCulture) + " m")
                </div>
            </div>

                    <button class="popup-parada-cerrar" @onclick="() => _popupInspectorVisible = false">×</button>
                </div>
                }

        </div>
    }




   @if (_tramoElevDetalle is not null)
{
    @* ====== MODO MINIMIZADO: burbuja ====== *@
    if (_elevPopupMinimizado)
    {
        <button type="button"
                class="elev-bubble"
                title="Abrir puntos de elevación"
                @onclick="() => _elevPopupMinimizado = false">
            ⛰️ Puntos · @_tramoElevDetalle.Tipo
        </button>
    }
    else
    {
        @* ====== MODO NORMAL: popup grande ====== *@
            <div class="popup-parada popup-elev popup-elev-topright draggable-popup" data-drag-key="popup-elevacion">

                <div class="popup-parada-header popup-elev-header draggable-popup-handle">
    <span class="popup-elev-title">
        Puntos de elevación · @_tramoElevDetalle.Tipo
    </span>

    <div class="popup-elev-actions">
        <button type="button"
                class="btn-ghost btn-elev-min"
                title="Minimizar"
                @onclick="() => _elevPopupMinimizado = true">
            —
        </button>

        <button type="button"
                class="btn-ghost btn-elev-close"
                title="Cerrar"
                @onclick="CerrarPopupElevAsync">
            ×
        </button>
    </div>
</div>


            <div class="popup-parada-body popup-elev-table-wrap">
                @* ===== tu contenido actual tal cual ===== *@

                @if (_tramoElevDetalle.ElevacionCargando)
                {
                    <div class="muted">Cargando puntos…</div>
                }
                else if (_tramoElevDetalle.MuestrasElevacion is null || _tramoElevDetalle.MuestrasElevacion.Count == 0)
                {
                    <div class="muted">No hay puntos para mostrar.</div>
                }
                else
                {
                        <table class="popup-elev-table" style="
                width:100%;
                font-size:0.8rem;
                border-collapse: collapse;
                table-layout: fixed;
                box-sizing: border-box;
                white-space: nowrap;
            ">
                            <colgroup>
                                <col style="width:34px;" />
                                <col style="width:76px;" />
                                <col style="width:62px;" />
                                <col style="width:80px;" />
                                <col style="width:78px;" />
                                <col style="width:66px;" />
                            </colgroup>
                            <thead>
                                <tr>
                                    <th style="padding:4px 4px;">#</th>

                                    <th style="padding:4px 5px; text-align:right;">Alt (G)</th>
                                    <th style="padding:4px 5px; text-align:right;">dAlt</th>
                                    <th style="padding:4px 5px; text-align:right;">Pend (G)</th>
                                    <th style="padding:4px 5px; text-align:right;">Dist (m)</th>
                                    <th style="padding:4px 5px; text-align:right;">Esf.</th>
                                </tr>
                            </thead>

                            <tbody>
                                @for (int i = 0; i < _tramoElevDetalle.MuestrasElevacion.Count; i++)
                                {
                                    var p = _tramoElevDetalle.MuestrasElevacion[i];

                                    double? distPrev = null;
                                    double? deltaAlturaI = null;
                                    double? pendienteI = null;

                                    if (i > 0)
                                    {
                                        var prev = _tramoElevDetalle.MuestrasElevacion[i - 1];

                                        distPrev = CalcularDistanciaMetros(prev.Latitud, prev.Longitud, p.Latitud, p.Longitud);

                                        if (prev.ElevacionIdee is not null && p.ElevacionIdee is not null)
                                        {
                                            deltaAlturaI = p.ElevacionIdee.Value - prev.ElevacionIdee.Value;

                                            if (distPrev > 0)
                                                pendienteI = deltaAlturaI.Value / distPrev.Value * 100.0;
                                        }
                                    }

                                    string deltaAlturaTxt = deltaAlturaI is null
                                        ? "-"
                                        : deltaAlturaI.Value.ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture);

                                    string distTxt = distPrev is null ? "-" : distPrev.Value.ToString("0.00", CultureInfo.InvariantCulture);

                                    string pendITxt = "-";
                                    if (pendienteI is not null)
                                        pendITxt = pendienteI.Value.ToString("+0.0;-0.0;0.0", CultureInfo.InvariantCulture) + " %";

                                    var esfuerzoTxt = FormatearEsfuerzoElevacion(distPrev, pendienteI);

                                    <tr>
                                        <td style="padding:3px 4px;">
                                            @(i == 0 ? "Ini" :
                                                                        i == _tramoElevDetalle.MuestrasElevacion.Count - 1 ? "Fin" :
                                          p.Indice.ToString())
                        </td>

                                        <td style="padding:3px 5px; text-align:right;">
                                            @(p.ElevacionIdee is null ? "-" : p.ElevacionIdee.Value.ToString("0.00", CultureInfo.InvariantCulture) + " m")
                                        </td>

                                        <td style="padding:3px 5px; text-align:right;">
                                            @deltaAlturaTxt
                                        </td>

                                        <td style="padding:3px 5px; text-align:right;">
                                            @pendITxt
                                        </td>

                                        <td style="padding:3px 5px; text-align:right;">
                                            @distTxt
                                        </td>

                                        <td style="padding:3px 5px; text-align:right;">
                                            @esfuerzoTxt
                                        </td>
                                    </tr>
                                        }
                            </tbody>
                        </table>

                    @if (_tramoElevDetalle is not null)
                    {
                        var s = _tramoElevDetalle.MuestrasElevacion ?? new List<MuestraElevacion>();

                        // --- resumen altitudes ---
                        double? OIni = s.Count > 0 ? s[0].Elevacion : null;
                        double? OFin = s.Count > 0 ? s[^1].Elevacion : null;
                        double? OMin = s.Where(x => x.Elevacion is not null).Select(x => x.Elevacion!.Value).DefaultIfEmpty().Min();
                        double? OMax = s.Where(x => x.Elevacion is not null).Select(x => x.Elevacion!.Value).DefaultIfEmpty().Max();
                        if (!s.Any(x => x.Elevacion is not null)) { OMin = null; OMax = null; }

                        double? GIni = s.Count > 0 ? s[0].ElevacionIdee : null;
                        double? GFin = s.Count > 0 ? s[^1].ElevacionIdee : null;
                        double? GMin = s.Where(x => x.ElevacionIdee is not null).Select(x => x.ElevacionIdee!.Value).DefaultIfEmpty().Min();
                        double? GMax = s.Where(x => x.ElevacionIdee is not null).Select(x => x.ElevacionIdee!.Value).DefaultIfEmpty().Max();
                        if (!s.Any(x => x.ElevacionIdee is not null)) { GMin = null; GMax = null; }

                        string F(double? v) => v is null ? "-" : v.Value.ToString("0.00", CultureInfo.InvariantCulture) + " m";

                        // --- suma distancias entre puntos ---
                        double totalDist = 0;
                        double totalEsfuerzoPositivo = 0;
                        double totalEsfuerzo = 0;
                        double totalDistPendPositiva = 0;
                        double totalAlturaPendPositiva = 0;
                        var hayEsfuerzoPositivo = false;
                        var hayEsfuerzo = false;
                        for (int i = 1; i < s.Count; i++)
                        {
                            var anterior = s[i - 1];
                            var actual = s[i];
                            var distancia = CalcularDistanciaMetros(anterior.Latitud, anterior.Longitud, actual.Latitud, actual.Longitud);
                            totalDist += distancia;

                            double? pendiente = null;
                            if (distancia > 0 && anterior.ElevacionIdee is not null && actual.ElevacionIdee is not null)
                            {
                                pendiente = (actual.ElevacionIdee.Value - anterior.ElevacionIdee.Value) / distancia * 100.0;

                                if (pendiente > 0)
                                {
                                    totalDistPendPositiva += distancia;
                                    totalAlturaPendPositiva += Math.Max(0, actual.ElevacionIdee.Value - anterior.ElevacionIdee.Value);
                                }
                            }

                            var esfuerzo = CalcularEsfuerzoElevacion(distancia, pendiente);
                            if (esfuerzo is not null)
                            {
                                totalEsfuerzo += esfuerzo.Value;
                                hayEsfuerzo = true;

                                if (pendiente > 0)
                                {
                                    totalEsfuerzoPositivo += esfuerzo.Value;
                                    hayEsfuerzoPositivo = true;
                                }
                            }
                        }

                        string FDist(double d)
                        {
                            if (d <= 0) return "-";
                            if (d < 950)
                                return $"{d:0.00} m";
                            return $"{(d / 1000.0):0.000} km";
                        }


                        <div class="muted" style="font-size:0.78rem; margin-top:.5rem;">
                            <div><b>O:</b> (ini→fin) = @F(OIni) → @F(OFin) · (min/max) = @F(OMin) / @F(OMax)</div>
                            <div><b>G:</b> (ini→fin) = @F(GIni) → @F(GFin) · (min/max) = @F(GMin) / @F(GMax)</div>
                            <div style="margin-top:.25rem;">
                                <b>Suma distancia de puntos:</b> @FDist(totalDist)
                            </div>
                            <div>
                                <b>Suma dist pend positiva:</b> @FDist(totalDistPendPositiva)
                            </div>
                            <div>
                                <b>Suma alturas pend positiva:</b> @(totalAlturaPendPositiva > 0
                                    ? totalAlturaPendPositiva.ToString("0.00", CultureInfo.InvariantCulture) + " m (" + (totalAlturaPendPositiva / 3.0).ToString("0.0", CultureInfo.InvariantCulture) + " pisos)"
                                    : "-")
                            </div>
                            <div>
                                <b>Suma de esfuerzos positivos:</b> @(hayEsfuerzoPositivo ? totalEsfuerzoPositivo.ToString("0.00", CultureInfo.InvariantCulture) : "-")
                                <span style="margin-left:.5rem;"><b>total:</b> @(hayEsfuerzo ? totalEsfuerzo.ToString("0.00", CultureInfo.InvariantCulture) : "-")</span>
                            </div>
                        </div>
                    }


                }
            </div>

        </div>
    }
    }



    <!-- PANEL DERECHO: RUTAS -->
    <div class="route-panel-overlay draggable-popup" data-drag-key="panel-rutas">
        @if (!string.IsNullOrEmpty(_mensajeRuta) || _opcionesRuta.Count > 0)
        {
            <div class="route-panel">
                <div class="route-panel-header">
                    <h5 class="route-panel-title draggable-popup-handle">Rutas sugeridas</h5>
                    <div class="route-priority-switch" role="group" aria-label="Criterio prioritario de rutas">
                        <button type="button"
                                class="route-priority-option @(CriterioPrioritarioAndarActivo ? "route-priority-option-active" : "")"
                                title="Priorizar rutas con menor distancia a pie"
                                @onclick="@(() => CambiarCriterioPrioritarioRutasAsync(CriterioRutaAndar))">
                            Andar
                        </button>
                        <button type="button"
                                class="route-priority-option @(CriterioPrioritarioEquilibradoActivo ? "route-priority-option-active" : "")"
                                title="Mantener el criterio equilibrado actual"
                                @onclick="@(() => CambiarCriterioPrioritarioRutasAsync(CriterioRutaEquilibrado))">
                            Equilibrado*
                        </button>
                        <button type="button"
                                class="route-priority-option @(CriterioPrioritarioTiempoActivo ? "route-priority-option-active" : "")"
                                title="Priorizar rutas con menor tiempo total"
                                @onclick="@(() => CambiarCriterioPrioritarioRutasAsync(CriterioRutaTiempo))">
                            Tiempo
                        </button>
                    </div>
                </div>

                @if (_opcionesRuta.Count > 0)
                {
                    <div class="route-alt-list">
                        @for (int i = 0; i < _opcionesRuta.Count; i++)
                        {
                            var alt = _opcionesRuta[i];
                            bool seleccionada = i == _indiceAlternativaSeleccionada;
                            var index = i;

                            <button type="button"
                                    class="route-alt-card @(seleccionada ? "route-alt-card-selected" : "")"
                                    @onclick="@(() => CambiarAlternativaAbsoluta(index))">
                                <div class="route-alt-main">
                                    <span class="route-alt-time">
                                        @FormatearDuracion(alt.DuracionTotalAproxSegundos)
                                    </span>

                                    <span class="route-alt-label">
                                        @FormatearEtiquetaAlternativaTarjeta(alt, i)
                        </span>

                        @if (!alt.EsSoloAPie)
                                    {
                                        var lineas = LineasDeAlternativa(alt); // ✅ ya devuelve todas
                                        if (!string.IsNullOrWhiteSpace(lineas))
                                        {
                                            <span class="muted" style="margin-left:6px;">
                                                · @lineas
                                            </span>
                                        }
                                    
                                    }
                                    </div>


                                <div class="route-alt-sub">
                        @if (alt.EsSoloAPie)
                                    {
                                        <span>@FormatearDistanciaTarjeta(alt.DistanciaSoloAPie) a pie</span>
                                        <span class="muted"> · @alt.ProveedorRuta</span>
                                    }
                                    else
                                    {
                                        <span>@FormatearDistanciaTarjeta(alt.AlternativaBus!.DistanciaTotalBus) en bus</span>
                                        <span> · @alt.NumeroTransbordosReales Transbordos</span>
                                        <span class="route-alt-walk @(CriterioPrioritarioAndarActivo ? "route-alt-walk-emphasis" : "")">
                                            · @FormatearDistanciaTarjeta(alt.DistanciaPieTotalAprox) a pie aprox.
                                        </span>
                                        @if (CriterioPrioritarioEquilibradoActivo)
                                        {
                                            var balanceEquilibrado = FormatearBalanceEquilibradoAlternativa(alt);
                                            if (!string.IsNullOrWhiteSpace(balanceEquilibrado))
                                            {
                                                <span class="route-alt-balance"
                                                      title="Comparacion dentro de esta lista: cercania a la solucion mas rapida frente a la que menos camina">
                                                    - Eq. @balanceEquilibrado
                                                </span>
                                            }
                                        }
                                    }
                                </div>


                            </button>
                        }
                    </div>
                }

                <hr class="route-panel-divider" />

                <div class="route-panel-body">
                    @if (_hayRutaValida)
                    {
                        @if (_hayRutaValida)
                        {
                            @if (_opcionesRuta.Count > 0 && _indiceAlternativaSeleccionada >= 0 && _indiceAlternativaSeleccionada < _opcionesRuta.Count)
                            {
                                var alt = _opcionesRuta[_indiceAlternativaSeleccionada];

                                @* ========= RESUMEN BONITO ARRIBA (único) ========= *@
                                <p class="route-main-text">
                                    @if (alt.EsSoloAPie)
                                    {
                                        <span>Ruta </span>
                                        <span class="highlight">solo a pie</span>
                                        <span>: </span>
                                        <span class="highlight">@FormatearDistancia(alt.DistanciaSoloAPie)</span>
                                        <span> aprox.</span>
                                    }
                                    else
                                    {
                                        var tramosBus = alt.AlternativaBus?.Tramos ?? new List<TramoBus>();
                                        var trans = alt.NumeroTransbordosReales;

                                        string txtLineas = TextoLineasDeTramos(tramosBus);
                                        if (string.IsNullOrWhiteSpace(txtLineas))
                                            txtLineas = "-";

                                        var tiempoBusTotal = FormatearDuracionBloqueBusResumen(_tramosRuta);

                                        <span>Camina </span>
                                        <span class="highlight">@FormatearDistanciaDetalleRuta(alt.DistanciaPieInicioAprox)</span>
                                        <span> . Viaja en BUS </span>
                                        <span class="highlight">@FormatearDistanciaDetalleRuta(alt.AlternativaBus!.DistanciaTotalBus)</span>
                                        <span> en </span>
                                        <span class="highlight">@tramosBus.Count</span>
                                        <span> tramo(s) con </span>
                                        <span class="highlight">@trans</span>
                                        <span> transbordo(s), Total: </span>
                                        <span class="highlight">@tiempoBusTotal</span>
                                        <span>, </span>
                                        <span>Líneas: </span>
                                        <span class="highlight">@txtLineas</span>
                                        <span> . Finalmente camina </span>
                                        <span class="highlight">@FormatearDistanciaDetalleRuta(alt.DistanciaPieFinAprox)</span>
                                        <span> .</span>
                                    }
                                </p>
                            }

                        }


                        <div class="chips-row">
                            <div class="chip">
                                <span class="chip-dot chip-dot-walk"></span>
                                A pie: @FormatearDistanciaDetalleRuta(_distanciaAPieInicio)
                            </div>
                            <div class="chip">
                                <span class="chip-dot chip-dot-line"></span>
                                BUS: @FormatearDuracionBloqueBusDetalle(_tramosRuta)
                            </div>
                            <div class="chip">
                                <span class="chip-dot chip-dot-walk"></span>
                                A pie: @FormatearDistanciaDetalleRuta(_distanciaAPieFin)
                            </div>
                            <div class="chip">
                                <span class="chip-dot chip-dot-start"></span>
                                Origen: @_paradaOrigenSeleccionada?.Nombre
                            </div>
                            @if (_numeroTransbordos > 0)
                            {
                                <div class="chip">
                                    <span class="chip-dot chip-dot-line"></span>
                                    Transbordos: @_numeroTransbordos
                                </div>
                            }
                            <div class="chip">
                                <span class="chip-dot chip-dot-end"></span>
                                Destino: @_paradaDestinoSeleccionada?.Nombre
                            </div>
                        </div>

                        @if (_tramosRuta.Any())
                        {
                            <p class="route-main-text mt-2">Detalle de tramos:</p>
                            <ul class="lista-tramos-ruta">
                                @for (var i = 0; i < _tramosRuta.Count; i++)
                                {
                                    var tramo = _tramosRuta[i];
                                    var tipoVisible = ObtenerTipoVisibleDetalleTramo(_tramosRuta, i);

                                    <li>
                                        <span class="indice-tramo-ruta">@(i + 1)</span>
                                        <div class="detalle-tramo-ruta-contenido d-flex align-items-start justify-content-between gap-2">

                                            <!-- COLUMNA IZQUIERDA: TEXTO -->
                                            <div>
                                                <strong><span aria-hidden="true">@IconoTramoRuta(tramo.Tipo)</span> @tipoVisible: </strong>

                                                @{
                                                    var partes = (tramo.Descripcion ?? "").Split("<br />", StringSplitOptions.None);
                                                    var principal = partes.Length > 0 ? partes[0] : "";
                                                    var extra = partes.Length > 1 ? string.Join("<br />", partes.Skip(1)) : "";
                                                }

                                                @((MarkupString)principal)
                                                <span class="muted"> - </span>@FormatearDistanciaDetalleRuta(tramo.DistanciaMetros)

                                                @if (tramo.DuracionSegundos is double s && s > 0)
                                                {
                                                    <span class="muted"> (@FormatearDuracion(s))</span>
                                                }

                                                @if (!string.IsNullOrWhiteSpace(extra))
                                                {
                                                    <div class="muted mt-1" style="padding-left:1rem">
                                                        @((MarkupString)extra)
                                                    </div>
                                                }
                                            </div>

                                            <!-- COLUMNA DERECHA: BOTONES -->
                                            <div class="d-flex flex-column gap-1 align-items-end">

                                                @if (tramo.Tipo.Equals("Bus", StringComparison.OrdinalIgnoreCase) && tramo.VarianteBus is not null)
                                                {
                                                    var id = $"full_{tramo.VarianteBus.Linea.Codigo}_{tramo.VarianteBus.CodigoItinerario}_{tramo.VarianteBus.Sentido?.Codigo}_{tramo.VarianteBus.Variante.Codigo}";

                                                    <button type="button"
                                                            class="btn-ghost"
                                                            style="padding:.25rem .5rem; white-space:nowrap;"
                                                            @onclick="async () => await ToggleLineaCompletaAsync(tramo)">
                                                        @(EstaPreviewActiva(id) ? "- itin" : "+ itin")
                                                    </button>
                                                }

                                                @if (tramo.Linea is not null && tramo.Linea.GetLength(0) > 1
                                                                                && tramo.Tipo.StartsWith("A pie", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    <button type="button"
                                                            class="btn-ghost"
                                                            style="padding:.25rem .5rem; white-space:nowrap;"
                                                            @onclick="async () => await TogglePuntosAsync(tramo)">
                                                        @(EstaPopupPuntosAbierto(tramo)
                                                                                            ? "- info"
                                                                                            : (tramo.ElevacionCargando ? "Cargando…" : "+ info"))
                                </button>

                                                }

                                            </div>
                                        </div>
                                    </li>


                                }
                            </ul>
                        }


                        @if (_opcionesRuta.Count > 0 && _indiceAlternativaSeleccionada >= 0 && _indiceAlternativaSeleccionada < _opcionesRuta.Count)
                        {
                            var altSeleccionada = _opcionesRuta[_indiceAlternativaSeleccionada];
                            var duracionVisible = altSeleccionada.DuracionTotalAproxSegundos > 0
                                ? altSeleccionada.DuracionTotalAproxSegundos
                                : _duracionTotalSegundos;
                            var dRecta = DistanciaLineaRectaOrigenDestino();
                            var dCorregida = CalcularDistanciaCorregidaAlternativa(altSeleccionada);
                            var xyzOrigen = FormatearResumenXYZOrigen();
                            var xyzDestino = FormatearResumenXYZDestino();
                            var tiempoCalculo = FormatearTiempoCalculoRuta();
                            var balanceEquilibradoSeleccionado = CriterioPrioritarioEquilibradoActivo
                                ? FormatearBalanceEquilibradoAlternativa(altSeleccionada)
                                : string.Empty;
                            // var costePenalizado = ObtenerCostePenalizadoAlternativa(altSeleccionada);
                            // var incrementoPenalizacion = Math.Max(0, costePenalizado - Math.Max(0, duracionVisible));

                            if (duracionVisible > 0)
                            {
                                <p class="route-main-text mt-1">
                                    Tiempo total estimado del trayecto:
                                    <span class="highlight">@FormatearDuracion(duracionVisible)</span>.
                                    <span class="muted"></span>
                                </p>
                            }

                            @if (dRecta > 0 || dCorregida > 0)
                            {
                                <div class="muted" style="font-size:0.75rem;margin-top:4px;">
                                    @if (dRecta > 0)
                                    {
                                        <div>d.Recta O-D: @($"{Math.Round(dRecta):0} m")</div>
                                    }
                                    @if (dCorregida > 0)
                                    {
                                        <div>d.Corregida a pie: @FormatearDistanciaDetalleRuta(dCorregida)</div>
                                    }
                                    @if (!string.IsNullOrWhiteSpace(balanceEquilibradoSeleccionado))
                                    {
                                        <div>Balance equilibrado: @balanceEquilibradoSeleccionado</div>
                                    }
                                    @if (!string.IsNullOrWhiteSpace(xyzOrigen))
                                    {
                                        <div style="white-space: pre-wrap;">@xyzOrigen</div>
                                    }
                                    @if (!string.IsNullOrWhiteSpace(xyzDestino))
                                    {
                                        <div style="white-space: pre-wrap;">@xyzDestino</div>
                                    }
                                    @if (!string.IsNullOrWhiteSpace(tiempoCalculo))
                                    {
                                        <div>Tiempo de calculo: @tiempoCalculo</div>
                                    }
@*                                     @if (costePenalizado > 0)
                                    {
                                        <div>
                                            Coste penalizado: @FormatearDuracion(costePenalizado)
                                            @if (incrementoPenalizacion > 0)
                                            {
                                                <span> (+@FormatearDuracion(incrementoPenalizacion))</span>
                                            }
                                        </div>
                                    } *@
                                </div>
                            }
                        }

                        }
                    else
                    {
                        var mensajeSinRuta = !string.IsNullOrWhiteSpace(_mensajeRuta)
                            ? _mensajeRuta
                            : "No hay rutas disponibles para esta combinacion.";
                        var dRectaSinRuta = DistanciaLineaRectaOrigenDestino();
                        var xyzOrigenSinRuta = FormatearResumenXYZOrigen();
                        var xyzDestinoSinRuta = FormatearResumenXYZDestino();
                        var tiempoCalculoSinRuta = FormatearTiempoCalculoRuta();

                        <p class="route-main-text">@mensajeSinRuta</p>

                        @if (dRectaSinRuta > 0
                                                    || !string.IsNullOrWhiteSpace(xyzOrigenSinRuta)
                                                    || !string.IsNullOrWhiteSpace(xyzDestinoSinRuta))
                        {
                            <div class="muted" style="font-size:0.75rem;margin-top:4px;">
                                @if (dRectaSinRuta > 0)
                                {
                                    <div>d.Recta O-D: @($"{Math.Round(dRectaSinRuta):0} m")</div>
                                }
                                @if (!string.IsNullOrWhiteSpace(xyzOrigenSinRuta))
                                {
                                    <div style="white-space: pre-wrap;">@xyzOrigenSinRuta</div>
                                }
                                @if (!string.IsNullOrWhiteSpace(xyzDestinoSinRuta))
                                {
                                    <div style="white-space: pre-wrap;">@xyzDestinoSinRuta</div>
                                }
                                @if (!string.IsNullOrWhiteSpace(tiempoCalculoSinRuta))
                                {
                                    <div>Tiempo de calculo: @tiempoCalculoSinRuta</div>
                                }
                            </div>
                        }
                    }
                </div>
            </div>
        }
    </div>

    @if (_mostrarHistorialRutas)
    {
        <div class="history-panel draggable-popup" data-drag-key="panel-historial">
            <div class="history-panel-header draggable-popup-handle">
                <h5>Historial de rutas</h5>
                <button type="button" class="config-close-btn" @onclick="ToggleHistorialPanel">&times;</button>
            </div>

            <div class="history-panel-body">
                <div class="history-section">
                    <label class="history-section-label">Personal:</label>
                    @if (_historialLocal.Count == 0)
                    {
                        <div class="history-empty">Sin historial.</div>
                    }
                    else
                    {
                        <div class="history-list">
                            @foreach (var item in _historialLocal)
                            {
                                <div class="history-item @(item.Id == _historialLocalSeleccionadoId ? "history-item--selected" : "")">
                                    <button type="button"
                                            class="history-item-main"
                                            @onclick="() => CargarHistorialLocalAsync(item.Id)">
                                        @TextoOpcionHistorial(item)
                                    </button>

                                    <button type="button"
                                            class="history-item-action"
                                            title="Compartir"
                                            @onclick="() => CompartirHistorialLocalAsync(item.Id)">
                                        &#8663;
                                    </button>

                                    <button type="button"
                                            class="history-item-delete"
                                            title="Eliminar"
                                            @onclick="() => EliminarHistorialLocalAsync(item.Id)">
                                        &times;
                                    </button>
                                </div>
                            }
                        </div>
                    }
                </div>

                <div class="history-section">
                    <label class="history-section-label">Compartido:</label>
                    @if (_historialCompartido.Count == 0)
                    {
                        <div class="history-empty">Sin compartidos.</div>
                    }
                    else
                    {
                        <div class="history-list">
                            @for (int i = 0; i < _historialCompartido.Count; i++)
                            {
                                var item = _historialCompartido[i];
                                var numeroCompartido = i + 1;

                                <div class="history-item @(item.Id == _historialCompartidoSeleccionadoId ? "history-item--selected" : "")">
                                    <button type="button"
                                            class="history-item-main history-item-main--numbered"
                                            @onclick="() => CargarHistorialCompartidoAsync(item.Id)">
                                        <span class="history-item-number">@numeroCompartido.</span>
                                        <span class="history-item-text">@TextoOpcionHistorial(item)</span>
                                    </button>

                                    <button type="button"
                                            class="history-item-delete"
                                            title="Eliminar"
                                            @onclick="() => PedirConfirmacionEliminarHistorialCompartido(item.Id)">
                                        &times;
                                    </button>
                                </div>
                            }
                        </div>
                    }
                </div>

                @if (!string.IsNullOrWhiteSpace(_mensajeHistorial))
                {
                    <div class="history-feedback @(_mensajeHistorialEsError ? "history-feedback--error" : "")">
                        @_mensajeHistorial
                    </div>
                }
            </div>
        </div>
    }

    @if (_historialCompartidoPendienteEliminarId is not null)
    {
        <div class="custom-modal-backdrop" @onclick="CancelarConfirmacionEliminarHistorialCompartido">
            <div class="custom-modal-card" @onclick:stopPropagation="true">
                <div class="custom-modal-title">Eliminar compartido</div>
                <div class="custom-modal-text">
                    Seguro que quieres eliminar esta solucion de compartidos?
                </div>

                <div class="custom-modal-actions">
                    <button class="btn-ghost btn-ghost--secondary" @onclick="CancelarConfirmacionEliminarHistorialCompartido">
                        Cancelar
                    </button>
                    <button class="btn-ghost" @onclick="ConfirmarEliminarHistorialCompartidoAsync">
                        Eliminar
                    </button>
                </div>
            </div>
        </div>
    }

    <!-- CONFIG -->
@*     <button class="config-toggle-btn" @onclick="ToggleConfigPanel">⚙</button>
 *@
    @if (_mostrarConfigAvanzada)
    {
        <div class="config-panel draggable-popup" data-drag-key="panel-configuracion">
            <div class="config-panel-header draggable-popup-handle">
                <h5>Configuración avanzada</h5>
                <button type="button" class="config-close-btn" @onclick="ToggleConfigPanel">×</button>
            </div>

@*             <div class="config-row config-row-full">
                <label>Selección de paradas (rápida):</label>

                <div class="line-filter">
                    <label class="line-filter__toggle">
                        <input type="checkbox" @bind="_usarOsrmParaRanking" @bind:after="PersistirConfiguracionAsync" />
                        <span>Usar v1 para rankear candidatas (más preciso, más lento)</span>
                    </label>

                    <div class="line-filter__range">
                        <span class="muted">Radio</span>
                        <input type="number" class="config-input" min="150" step="50"
                               @bind="_radioCandidatasMetros" @bind:event="oninput" />
                        <span class="muted">m · Máx paradas</span>
                        <input type="number" class="config-input" min="3" max="20" step="1"
                               @bind="_maxCandidatasPorLado" @bind:event="oninput" />
                    </div>

                    <small class="muted">
                        En estricto, solo se consideran paradas que pertenezcan a itinerarios permitidos.
                    </small>
                </div>
            </div> *@
                    <div class="config-row config-row-full" style="margin-top:12px;">
                        <div class="line-filter">
                            <label class="line-filter__toggle">
                                <input type="checkbox"
                                       checked="@_usarHorariosTeoricos"
                                       @onchange="OnToggleHorariosTeoricos" />
                                <span>Usar horarios teoricos:&nbsp;</span>
                                @if (_usarHorariosTeoricos)
                                {
                                    if (_horariosOk)
                                    {
                                        <span class="muted">OK</span>
                                    }
                                    else if (!string.IsNullOrWhiteSpace(_horariosError))
                                    {
                                        <span class="muted">@_horariosError</span>
                                    }
                                    else
                                    {
                                        <span class="muted">cargando...</span>
                                    }
                                }
                                else
                                {
                                    <span class="muted">desactivados</span>
                                }
                            </label>

                            <div class="line-filter__range line-filter__range--segundos-parada">
                                <span class="muted">Segundos por parada:&nbsp;</span>
                                <div class="num-inline">
                                    @if (_usarHorariosTeoricos)
                                    {
                                        <input type="number" class="config-input" step="1" min="0" value="0" disabled readonly />
                                        <button type="button" class="step-btn" disabled>▲</button>
                                        <button type="button" class="step-btn" disabled>▼</button>
                                    }
                                    else
                                    {
                                        <input type="number" class="config-input" step="1" min="0"
                                               @bind="_segundosPorParadaBus" @bind:event="oninput" @bind:after="OnSegundosPorParadaBusChanged" />
                                        <button type="button" class="step-btn" @onclick="async () => { _segundosPorParadaBus = _segundosPorParadaBus + 1; await OnSegundosPorParadaBusChanged(); }">▲</button>
                                        <button type="button" class="step-btn" @onclick="async () => { _segundosPorParadaBus = Math.Max(0, _segundosPorParadaBus - 1); await OnSegundosPorParadaBusChanged(); }">▼</button>
                                    }
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="config-row config-row-full">
                        <div class="modelos-horarios">
                            <button type="button"
                                    class="modelos-horarios__toggle"
                                    @onclick="AbrirModelosHorariosPanel">
                                <span class="modelos-horarios__toggle-label">Modelo DBUS</span>
                                <span class="modelos-horarios__activo">
                                    @(ModeloHorarioActivo?.NombreArchivo ?? "Sin modelo cargado")
                                </span>
                                <span class="modelos-horarios__toggle-action">
                                    Gestionar
                                </span>
                            </button>
                        </div>
                    </div>

     @* =========================
   RANGO DE LÍNEAS
   ========================= *@
<div class="config-row config-row-full">
    <div class="line-filter">
        <label class="line-filter__toggle">
            <input type="checkbox" @bind="_activarRangoLineas" @bind:after="PersistirConfiguracionAsync" />
            <span>Aplicar lineas utilizables:</span>
        </label>

        @if (_activarRangoLineas)
        {
            <details class="line-filter__dropdown">
                <summary class="line-filter__summary">
                    <span>@TextoResumenLineasPermitidas()</span>
                </summary>

                <div class="line-filter__dropdown-panel">
                    <div class="line-filter__selector-head">
                        <span class="muted">Lineas:</span>
                        <button type="button" class="config-mini-button" @onclick="ToggleTodasLineasPermitidasAsync">
                            @TextoBotonTodasLineasPermitidas()
                        </button>
                    </div>

                    <div class="line-filter__list">
                        @foreach (var linea in LineasFiltroDisponibles())
                        {
                            <label class="line-option @(LineaFiltroSeleccionada(linea) ? "line-option--active" : "")">
                                <input type="checkbox"
                                       checked="@LineaFiltroSeleccionada(linea)"
                                       @onchange="args => ToggleLineaFiltroAsync(linea, args)" />
                                <span>@linea</span>
                            </label>
                        }
                    </div>
                </div>
            </details>
        }
        else
        {
            <div class="line-filter__summary line-filter__summary--readonly">Todas las lineas (@LineasFiltroDisponibles().Count)</div>
        }
    </div>
</div>

@* =========================
   RANGO DE ITINERARIOS
   ========================= *@
<div class="config-row config-row-full">
    <div class="line-filter">
        <label class="line-filter__toggle">
            <input type="checkbox" @bind="_activarRangoItinerarios" @bind:after="PersistirConfiguracionAsync" />
            <span>Aplicar rango de itinerarios utilizables:</span>
        </label>

        <div class="line-filter__range">
            <span class="muted">Rango:</span>

            <select class="config-input"
                    style="width:90px"
                    @bind="_itinerarioMin"
                    @bind:event="onchange"
                    @bind:after="PersistirConfiguracionAsync">
                @foreach (var n in Range(1, 150, 1))
                {
                    <option value="@n">@n</option>
                }
            </select>

            <span class="muted">a</span>

            <select class="config-input"
                    style="width:90px"
                    @bind="_itinerarioMax"
                    @bind:event="onchange"
                    @bind:after="PersistirConfiguracionAsync">
                @foreach (var n in Range(1, 150, 1))
                {
                    <option value="@n">@n</option>
                }
            </select>
        </div>
    </div>
</div>

@* =========================
   RANGO DE TRANSBORDOS
   ========================= *@
<div class="config-row config-row-full">
    <div class="line-filter">
        <label class="line-filter__toggle">
            <input type="checkbox" @bind="_activarRangoTransbordos" @bind:after="PersistirConfiguracionAsync" />
            <span>Aplicar rango de transbordos:</span>
        </label>

        <div class="line-filter__range">
            <span class="muted">Rango:</span>

            <select class="config-input"
                    style="width:90px"
                    @bind="_minTransbordosPermitidos"
                    @bind:event="onchange"
                    @bind:after="PersistirConfiguracionAsync">
                @foreach (var n in Range(0, 10, 1))
                {
                    <option value="@n">@n</option>
                }
            </select>

            <span class="muted">a</span>

            <select class="config-input"
                    style="width:90px"
                    @bind="_maxTransbordosPermitidos"
                    @bind:event="onchange"
                    @bind:after="PersistirConfiguracionAsync">
                @foreach (var n in Range(0, 10, 1))
                {
                    <option value="@n">@n</option>
                }
            </select>
        </div>
    </div>
</div>


                    <div class="config-row config-row-full" style="margin-top:14px;">
                        <div class="line-filter">
                            <label class="line-filter__toggle">
                                <input type="checkbox"
                                       checked="@_usarHoraSimulada"
                                       @onchange="OnToggleHoraSimulada" />
                                <span>Usar fecha y hora simulada:</span>
                            </label>

                                <div class="line-filter__range line-filter__range--fecha" style="margin-top:.5rem;">
                                    <input type="date"
                                           class="config-input config-input-date"
                                           value="@_fechaSimulada.ToString("yyyy-MM-dd")"
                                           @onchange="OnChangeFechaSimulada" />

                                    <input type="time"
                                           class="config-input config-input-time"
                                           value="@_horaSimulada.ToString("HH\\:mm")"
                                           @onchange="OnChangeHoraSimulada" />

                                    <button type="button"
                                            class="btn-ghost btn-ghost--tiny"
                                            @onclick="IrAAhoraSimuladoAsync">
                                        Ahora
                                    </button>
                                </div>
                            
                        </div>
                    </div>

            <div class="config-row">
                <label>Coef. / Param.(m) andando:</label>
                <div class="config-dual-inline config-dual-inline--bare">
                    <input type="number" class="config-input" step="any"
                           placeholder="Coef."
                           title="Coeficiente de penalizacion"
                           @bind="FactorPenalizacionDistanciaPieTexto" @bind:event="oninput"
                           @onblur="OnBlurFactorPenalizacionDistanciaPie" />
                    <input type="number" class="config-input" step="any"
                           placeholder="Param."
                           title="Parametro base en metros"
                           @bind="ParametroPenalizacionDistanciaPieTexto" @bind:event="oninput"
                           @onblur="OnBlurParametroPenalizacionDistanciaPie" />
                </div>
            </div>

            <div class="config-row">
                <label>Transbordo:</label>
                <div class="config-dual-labeled">
                    <label class="config-dual-labeled__field">
                        <span>Peso rank.</span>
                        <input type="text" class="config-input"
                               placeholder="4,0"
                               title="Penalizacion interna por cada transbordo real en minutos decimales"
                               @bind="PesoTransbordoRankingTexto" @bind:event="oninput"
                               @onblur="OnBlurPesoTransbordoRanking" />
                    </label>
                    <label class="config-dual-labeled__field">
                        <span>Margen (s)</span>
                        <input type="number" class="config-input" step="5" min="0" max="1800"
                               title="Margen minimo entre buses para aceptar un transbordo"
                               @bind="_margenTransbordoSegundos" @bind:event="oninput" @bind:after="PersistirConfiguracionAsync" />
                    </label>
                </div>
            </div>

            <div class="config-row">
                <label>Vel. Andando/Bus (km/h):</label>
                <div class="config-dual-inline config-dual-inline--bare">
                    <input type="number" class="config-input" step="0.1"
                           placeholder="Andar"
                           title="Velocidad andando (km/h)"
                           @bind="_velocidadPieKmH" @bind:event="oninput" @bind:after="PersistirConfiguracionAsync" />
                    <input type="number" class="config-input" step="0.1"
                           placeholder="Bus"
                           title="Velocidad bus (km/h)"
                           @bind="_velocidadBusKmH" @bind:event="oninput" @bind:after="PersistirConfiguracionAsync" />
                </div>
            </div>

            <div class="config-row">
                <label>Altitud: Max Puntos / Coef</label>
                <div class="config-dual-inline config-dual-inline--bare">
                    <input type="number" class="config-input" min="2" max="999" step="1"
                           placeholder="Puntos"
                           title="Máximo de puntos de altitud por tramo"
                           @bind="_elevMaxPuntosPorTramo" @bind:event="oninput" @bind:after="PersistirConfiguracionAsync" />
                    <input type="number" class="config-input" step="any"
                           placeholder="Coef."
                           title="Coeficiente de esfuerzo por altura"
                           @bind="CoeficienteEsfuerzoAlturaTexto" @bind:event="oninput"
                           @onblur="OnBlurCoeficienteEsfuerzoAltura" />
                </div>
            </div>


            <div class="config-row">
    <label>Radio paradas candidatas (m):</label>
    <div class="num-inline">
        <input type="number" class="config-input" min="200" max="3500" step="50"
               @bind="_radioCandidatasMetros" @bind:event="oninput" @bind:after="PersistirConfiguracionAsync" />
        <button type="button" class="step-btn"
                @onclick="async () => { _radioCandidatasMetros = Math.Min(3500, _radioCandidatasMetros + 50); await PersistirConfiguracionAsync(); }">▲</button>
        <button type="button" class="step-btn"
                @onclick="async () => { _radioCandidatasMetros = Math.Max(200, _radioCandidatasMetros - 50); await PersistirConfiguracionAsync(); }">▼</button>
    </div>
</div>

@*             <div class="config-row">
                <label>Minutos por Transbordo:</label>
                <div class="num-inline">
                    <input type="number" class="config-input" step="1" @bind="_minutosTransbordo" @bind:event="oninput" />
                    <button type="button" class="step-btn" @onclick="() => _minutosTransbordo = _minutosTransbordo + 1">▲</button>
                    <button type="button" class="step-btn" @onclick="() => _minutosTransbordo = Math.Max(0, _minutosTransbordo - 1)">▼</button>
                </div>
            </div> *@
                    <div class="config-row">
                        <label>Método cálculo andando:</label>

                        <div class="num-inline">
                            <select class="config-input"
                                    style="width:100%; min-width:0;"
                                    @bind="_walkProvider" @bind:after="PersistirConfiguracionAsync">
                                <option value="@ProveedorCaminata.Osrm">v1</option>
                                <option value="@ProveedorCaminata.Valhalla">v2</option>
                            </select>
                        </div>
                    </div>

            <div class="config-actions-row">
                <button class="btn-ghost" @onclick="RecalcularConParametros">
                    Recalcular
                </button>

                <button class="btn-ghost btn-ghost--secondary" @onclick="PedirConfirmacionRestablecer">
                    Rest. valores
                </button>
            </div>

                    <div class="config-row config-row-map-opacity">
                        <label>Opacidad mapa:</label>

                        <div style="display:flex; align-items:center; gap:.6rem; width:100%;">
                            <input type="range"
                                   class="config-range"
                                   min="0" max="4" step="1"
                                   @bind="_nivelBrilloMapa"
                                   @bind:event="oninput"
                                   @bind:after="PersistirConfiguracionAsync" />

                            <span style="min-width:3.2rem; text-align:right;">
                                @OpacidadMapaPorcentaje%
                            </span>
                        </div>
                    </div>
        </div>
    }
</div>

@if (_mostrarModelosHorariosPanel)
{
    <div class="custom-modal-backdrop modelos-horarios-modal-backdrop" @onclick="CerrarModelosHorariosPanel">
        <div class="custom-modal-card modelos-horarios-modal" @onclick:stopPropagation="true">
            <div class="modelos-horarios-modal__header">
                <div>
                    <div class="custom-modal-title">Modelos DBUS</div>
                    <div class="modelos-horarios-modal__activo">
                        @(ModeloHorarioActivo?.NombreArchivo ?? "Sin modelo cargado")
                    </div>
                </div>
                <button type="button"
                        class="config-close-btn modelos-horarios-modal__close"
                        @onclick="CerrarModelosHorariosPanel">
                    ×
                </button>
            </div>

            <div class="modelos-horarios__panel modelos-horarios__panel--modal">
                <label class="modelos-horarios__field">
                    <span>ZIP activo/disponible</span>
                    <select class="config-input modelos-horarios__select"
                            @bind="_modeloHorarioSeleccionadoId"
                            disabled="@_modelosHorariosCargando">
                        @if (_modelosHorarios.Count == 0)
                        {
                            <option value="">Sin ZIPs disponibles</option>
                        }
                        else
                        {
                            @foreach (var modelo in _modelosHorarios)
                            {
                                <option value="@modelo.Id">
                                    @modelo.NombreArchivo (@modelo.Origen, @FormatearTamanoModelo(modelo.TamanoBytes))
                                </option>
                            }
                        }
                    </select>
                </label>

                <div class="modelos-horarios__actions">
                    <button type="button"
                            class="modelos-horarios__button modelos-horarios__button--primary"
                            disabled="@(_modelosHorariosCargando || string.IsNullOrWhiteSpace(_modeloHorarioSeleccionadoId))"
                            @onclick="SeleccionarModeloHorarioAsync">
                        Cargar
                    </button>
                    <button type="button"
                            class="modelos-horarios__button"
                            disabled="@_modelosHorariosCargando"
                            @onclick="ActualizarModelosHorariosAsync">
                        Actualizar
                    </button>
                </div>

                <label class="modelos-horarios__upload">
                    <span>Subir ZIP</span>
                    <InputFile OnChange="SubirModeloHorarioAsync"
                               accept=".zip"
                               disabled="@_modelosHorariosCargando" />
                </label>

                <div class="modelos-horarios__maintenance">
                    <button type="button"
                            class="modelos-horarios__button modelos-horarios__button--danger"
                            disabled="@_modelosHorariosCargando"
                            @onclick="LimpiarDatosLocalesAsync">
                        Limpiar datos locales
                    </button>
                </div>

                @if (_modelosHorarios.Count > 0)
                {
                    <details class="modelos-horarios__details" open>
                        <summary>ZIPs disponibles (@_modelosHorarios.Count)</summary>
                        <div class="modelos-horarios__meta modelos-horarios__meta--modal">
                            @foreach (var modelo in _modelosHorarios)
                            {
                                <div class="modelos-horarios__item @(modelo.Activo ? "modelos-horarios__item--activo" : "")">
                                    <span>@modelo.NombreArchivo</span>
                                    <span>@modelo.Origen - @FormatearFechaModelo(modelo.FechaUtc)</span>
                                </div>
                            }
                        </div>
                    </details>
                }

                @if (_modelosHorariosCargando)
                {
                    <div class="modelos-horarios__mensaje">Trabajando...</div>
                }
                else if (!string.IsNullOrWhiteSpace(_mensajeModelosHorarios))
                {
                    <div class="modelos-horarios__mensaje">@_mensajeModelosHorarios</div>
                }
            </div>
        </div>
    </div>
}

@if (_mostrarConfirmacionRestablecer)
{
    <div class="custom-modal-backdrop" @onclick="CancelarConfirmacionRestablecer">
        <div class="custom-modal-card" @onclick:stopPropagation="true">
            <div class="custom-modal-title">Restablecer configuración</div>
            <div class="custom-modal-text">
                ¿Seguro que quieres volver a los valores por defecto de la configuración avanzada?
            </div>

            <div class="custom-modal-actions">
                <button class="btn-ghost btn-ghost--secondary" @onclick="CancelarConfirmacionRestablecer">
                    Cancelar
                </button>
                <button class="btn-ghost" @onclick="ConfirmarRestablecerConfiguracionAsync">
                    Restablecer
                </button>
            </div>
        </div>
    </div>
}

