// A VeszprémBusz oldal aktuális nyelve — a lazy térképi popupok (stopPopupContent) olvassák
window.currentLang = () => localStorage.getItem("lang") || "hu";

// ── CityRouteCard ────────────────────────────────────────────────────
// Kiválasztja a helyes GTFS shape-et és kiszeli a fromStop–toStop szakaszt
// A szelet elejére/végére a tényleges megálló koordinátát illeszti (nincs túllövés)
function getShapeSegment(bus, fromStopName, toStopName) {
  const shapes = (window.CITY_SHAPES || {})[bus.id];
  if (!shapes) return null;

  const fromStop = bus.stops.find(s => s.name === fromStopName);
  const toStop   = bus.stops.find(s => s.name === toStopName);
  if (!fromStop?.lat || !toStop?.lat) return null;

  const best = window.BUS_UTILS.bestShape(shapes, fromStop.lat, fromStop.lon, toStop.lat, toStop.lon);
  if (!best) return null;

  // Szelet: megálló koordináta + belső pontok + megálló koordináta
  const inner = best.s.slice(best.fi + 1, best.ti);
  return [
    [fromStop.lat, fromStop.lon],
    ...inner,
    [toStop.lat, toStop.lon],
  ];
}

function CityRouteMap({ route, fromStop, toStop, lang }) {
  const t = (window.I18N && window.I18N[lang || "hu"]) || window.I18N?.hu || {};
  const mapRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const instanceRef = React.useRef(null);
  const fitCoordsRef = React.useRef(null);
  const timeLabelMarkersRef = React.useRef([]);
  const [showTimeLabels, setShowTimeLabels] = React.useState(true);
  const routeKey = `${route.type}-${route.bus1?.id}-${route.boardAt}-${fromStop}-${toStop}`;

  React.useEffect(() => {
    timeLabelMarkersRef.current.forEach(m => m.setOpacity(showTimeLabels ? 1 : 0));
  }, [showTimeLabels, routeKey]);

  React.useEffect(() => {
    if (!mapRef.current) return;
    if (instanceRef.current) { instanceRef.current.remove(); instanceRef.current = null; }

    const map = L.map(mapRef.current, { zoomControl: true });
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap'
    }).addTo(map);

    const allCoords = [];
    timeLabelMarkersRef.current = [];
    const fmt = m => window.BUS_UTILS.fmtTime(m);

    function drawSegment(bus, from, to, color) {
      const seg = getShapeSegment(bus, from, to);
      if (seg && seg.length >= 2) {
        L.polyline(seg, { color, weight: 5, opacity: 0.9 }).addTo(map);
        allCoords.push(...seg);
      } else {
        const stops = bus.stops;
        const fi = stops.findIndex(s => s.name === from);
        const ti = stops.findIndex(s => s.name === to);
        if (fi >= 0 && ti > fi) {
          const coords = stops.slice(fi, ti + 1).filter(s => s.lat).map(s => [s.lat, s.lon]);
          L.polyline(coords, { color, weight: 4, opacity: 0.7, dashArray: '6,4' }).addTo(map);
          allCoords.push(...coords);
        }
      }
    }

    function drawStops(bus, from, to, color, dep) {
      const stops = bus.stops;
      const fi = stops.findIndex(s => s.name === from);
      const ti = stops.findIndex(s => s.name === to);
      if (fi < 0 || ti < 0) return;
      const seg = stops.slice(fi, ti + 1).filter(s => s.lat && s.lon);
      const allPlatforms = (window._cityPlatforms && window._cityPlatforms()) || [];
      seg.forEach((stop, i) => {
        const isTerminal = i === 0 || i === seg.length - 1;
        const r = isTerminal ? 9 : 6;
        const time = dep !== null ? dep + stop.offset : null;
        const platform = allPlatforms.find(p => p.spId === stop.spId);
        L.circleMarker([stop.lat, stop.lon], {
          radius: r, color: 'white', weight: 2,
          fillColor: color, fillOpacity: 0.95,
        }).addTo(map).bindPopup(() => window.stopPopupContent(stop.name, time !== null ? fmt(time) : null, null, null, platform ? platform.label : null));
        if (time !== null) {
          const labelHtml = `<div style="position:absolute;left:${r + 5}px;top:-10px;background:white;border:1.5px solid ${color};border-radius:4px;padding:1px 6px;font-size:11px;font-weight:700;color:#222;white-space:nowrap;box-shadow:0 1px 3px rgba(0,0,0,0.15);">${fmt(time)}</div>`;
          const labelMarker = L.marker([stop.lat, stop.lon], {
            icon: L.divIcon({ className: '', html: labelHtml, iconSize: [0, 0], iconAnchor: [0, 0] }),
            interactive: false, zIndexOffset: 200, opacity: showTimeLabels ? 1 : 0,
          }).addTo(map);
          timeLabelMarkersRef.current.push(labelMarker);
        }
        if (!isTerminal && i > 0) {
          const prev = seg[i - 1], next = seg[i + 1] || stop;
          const dy = next.lat - prev.lat, dx = next.lon - prev.lon;
          const angle = Math.atan2(dx, dy) * 180 / Math.PI;
          const svg = `<svg xmlns="http://www.w3.org/2000/svg" style="position:absolute;left:-12px;top:-32px;transform-origin:12px 32px;transform:rotate(${angle}deg)" width="24" height="40"><polygon points="12,6 19,26 12,19 5,26" fill="black" stroke="white" stroke-width="2" stroke-linejoin="round"/></svg>`;
          L.marker([stop.lat, stop.lon], {
            icon: L.divIcon({ className: '', html: svg, iconSize: [0, 0], iconAnchor: [0, 0] }),
            interactive: false, zIndexOffset: 100,
          }).addTo(map);
        }
      });
    }

    if (route.type === 'direct') {
      drawSegment(route.bus1, fromStop, toStop, route.bus1.color);
      const fromOff = route.bus1.stops.find(s => s.name === fromStop)?.offset ?? 0;
      drawStops(route.bus1, fromStop, toStop, route.bus1.color, route.boardAt - fromOff);
    } else {
      const bus2DepStop = route.walkToStop || route.transferStopName;
      drawSegment(route.bus1, fromStop, route.transferStopName, route.bus1.color);
      drawSegment(route.bus2, bus2DepStop, toStop, route.bus2.color);
      if (route.walkTransfer) {
        const sA = route.bus1.stops.find(s => s.name === route.transferStopName);
        const sB = route.bus2.stops.find(s => s.name === bus2DepStop);
        if (sA?.lat && sB?.lat) {
          const walkLine = L.polyline([[sA.lat, sA.lon], [sB.lat, sB.lon]], { color: '#555', weight: 3, opacity: 0.7, dashArray: '6,5' }).addTo(map);
          allCoords.push([sA.lat, sA.lon], [sB.lat, sB.lon]);
          window.fetchWalkingRoute(sA.lat, sA.lon, sB.lat, sB.lon).then(coords => {
            if (!coords || !instanceRef.current) return;
            walkLine.remove();
            L.polyline(coords, { color: '#555', weight: 3, opacity: 0.7, dashArray: '6,5' }).addTo(map);
          });
        }
      }
      const fromOff1 = route.bus1.stops.find(s => s.name === fromStop)?.offset ?? 0;
      drawStops(route.bus1, fromStop, route.transferStopName, route.bus1.color, route.boardAt - fromOff1);
      const fromOff2 = route.bus2.stops.find(s => s.name === bus2DepStop)?.offset ?? 0;
      drawStops(route.bus2, bus2DepStop, toStop, route.bus2.color, route.boardAt2 - fromOff2);
    }

    if (allCoords.length >= 2) map.fitBounds(allCoords, { padding: [16, 16] });
    else if (allCoords.length === 1) map.setView(allCoords[0], 15);
    fitCoordsRef.current = allCoords.length >= 2 ? allCoords.slice() : null;

    instanceRef.current = map;
    return () => { map.remove(); instanceRef.current = null; };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [routeKey]);

  const [fsState, setFsState] = React.useState(false);
  React.useEffect(() => {
    const h = () => {
      setFsState(!!document.fullscreenElement);
      setTimeout(() => {
        instanceRef.current?.invalidateSize();
        if (fitCoordsRef.current) instanceRef.current?.fitBounds(fitCoordsRef.current, { padding: [16, 16] });
      }, 100);
    };
    document.addEventListener('fullscreenchange', h);
    return () => document.removeEventListener('fullscreenchange', h);
  }, []);
  React.useEffect(() => {
    const h = (e) => { if (e.key === 'Escape' && !window.__stopViewerOpen && Date.now() > (window.__escGuardUntil || 0) && document.fullscreenElement) document.exitFullscreen(); };
    document.addEventListener('keydown', h);
    return () => document.removeEventListener('keydown', h);
  }, []);

  function toggleFullscreen() {
    if (!document.fullscreenElement) containerRef.current?.requestFullscreen();
    else document.exitFullscreen();
  }

  return (
    <div ref={containerRef} style={{ position: 'relative', borderTop: '2px solid var(--line)' }}>
      <div ref={mapRef} style={{ height: fsState ? '100%' : 300, width: '100%' }} />
      <button onClick={() => setShowTimeLabels(v => !v)} title={showTimeLabels ? (t.hideTimeLabels || 'Időcímkék elrejtése') : (t.showTimeLabels || 'Időcímkék mutatása')} aria-label={showTimeLabels ? (t.hideTimeLabels || 'Időcímkék elrejtése') : (t.showTimeLabels || 'Időcímkék mutatása')} aria-pressed={showTimeLabels} style={{
        position: 'absolute', top: fsState ? 28 : 10, right: fsState ? 76 : 56, zIndex: 1000,
        background: showTimeLabels ? '#1a73e8' : 'white',
        border: '2px solid #1a73e8',
        borderRadius: 8, padding: '4px 8px', cursor: 'pointer',
        fontSize: 16, lineHeight: 1, boxShadow: '0 2px 6px rgba(0,0,0,0.25)',
        color: showTimeLabels ? 'white' : '#1a73e8',
        opacity: showTimeLabels ? 1 : 0.7,
      }}>🏷️</button>
      <button onClick={toggleFullscreen} title={fsState ? (t.exitFullscreen || 'Kilépés') : (t.fullscreen || 'Teljes képernyő')} aria-label={fsState ? (t.exitFullscreen || 'Kilépés') : (t.fullscreen || 'Teljes képernyő')} style={{
        position: 'absolute', top: fsState ? 28 : 10, right: fsState ? 28 : 10, zIndex: 1000,
        background: '#1a73e8',
        border: '2px solid #1a73e8',
        borderRadius: 8, padding: '4px 8px', cursor: 'pointer',
        fontSize: 16, lineHeight: 1, boxShadow: '0 2px 6px rgba(0,0,0,0.25)',
        color: 'white',
      }}>{fsState ? '✕' : '⛶'}</button>
    </div>
  );
}

function scrollCityCardBottom(cardEl) {
  if (!cardEl) return;
  const rect = cardEl.getBoundingClientRect();
  const extra = rect.bottom - window.innerHeight + 80;
  if (extra > 0) window.scrollTo({ top: window.pageYOffset + extra, behavior: 'smooth' });
}

function CityRouteCard({ route, index, isPrimary, fromStop, toStop, walkMin, isWeekend, nowMins, lang }) {
  const U = window.BUS_UTILS;
  const fmt = m => U.fmtTime(m);
  const t = (window.I18N && window.I18N[lang || "hu"]) || window.I18N?.hu || {};
  const [timetableInfo, setTimetableInfo] = React.useState(null);
  const [mapOpen, setMapOpen] = React.useState(false);
  const [expanded, setExpanded] = React.useState(false);
  const cardRef = React.useRef(null);
  React.useEffect(() => {
    if (!mapOpen) return;
    setTimeout(() => scrollCityCardBottom(cardRef.current), 50);
  }, [mapOpen]);
  const totalMin = route.totalDuration;
  const totalStr = totalMin >= 60
    ? `${Math.floor(totalMin / 60)} ${t.hour || "h"} ${totalMin % 60} ${t.min || "min"}`
    : `${totalMin} ${t.min || "min"}`;

  // A route.*SpId mezők (city-planner.js) a ténylegesen kiválasztott fizikai
  // platformot rögzítik -- ha ismertek, ezekkel keresünk (nem puszta névvel), mert
  // egy ambiguus névnek több előfordulása is lehet ugyanazon a buszon/megállólistán.
  const stops1 = route.bus1.stops;
  const boardIdx1 = route.fromSpId
    ? stops1.findIndex(s => s.spId === route.fromSpId)
    : stops1.findIndex(s => s.name === fromStop);
  const alightName1 = route.type === 'direct' ? toStop : route.transferStopName;
  const alightSpId1 = route.type === 'direct' ? route.toSpId : route.transferSpId;
  const alightIdx1 = alightSpId1
    ? stops1.findIndex(s => s.spId === alightSpId1)
    : stops1.findIndex(s => s.name === alightName1);
  const fromBoard1 = route.boardAt - (boardIdx1 >= 0 ? stops1[boardIdx1].offset : 0);
  const visibleStops1 = boardIdx1 >= 0 && alightIdx1 >= 0 ? stops1.slice(boardIdx1, alightIdx1 + 1) : [];

  let visibleStops2 = [], fromBoard2 = 0;
  if (route.type === 'transfer' && route.bus2) {
    const stops2 = route.bus2.stops;
    const boardName2 = route.walkToStop || route.transferStopName;
    const boardSpId2 = route.walkToSpId || route.transferSpId2;
    const boardIdx2 = boardSpId2
      ? stops2.findIndex(s => s.spId === boardSpId2)
      : stops2.findIndex(s => s.name === boardName2);
    const alightIdx2 = route.toSpId
      ? stops2.findIndex(s => s.spId === route.toSpId)
      : stops2.findIndex(s => s.name === toStop);
    fromBoard2 = route.boardAt2 - (boardIdx2 >= 0 ? stops2[boardIdx2].offset : 0);
    visibleStops2 = boardIdx2 >= 0 && alightIdx2 >= 0 ? stops2.slice(boardIdx2, alightIdx2 + 1) : [];
  }

  function openTimetable(bus, boardAtMins, boardStopName) {
    const boardOff = bus.stops.find(s => s.name === boardStopName)?.offset ?? 0;
    setTimetableInfo({ busId: bus.id, fromStop: bus.stops[0]?.name, initialDep: boardAtMins - boardOff });
  }

  const BusIcon = ({ bus, boardAt, boardStop }) => (
    <div
      className="city-bus-badge"
      role="button"
      tabIndex={0}
      style={{ background: bus.color, cursor: 'pointer' }}
      title={t.viewTimetable || "Menetrend megtekintése"}
      aria-label={`${bus.id} – ${t.viewTimetable || "Menetrend megtekintése"}`}
      onClick={() => openTimetable(bus, boardAt, boardStop)}
      onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openTimetable(bus, boardAt, boardStop); } }}
    >
      {bus.id}
    </div>
  );

  return (
    <div className={`route-card ${isPrimary ? "primary" : ""}`} ref={cardRef}>
      {timetableInfo && (
        <window.BusTimetableModal busId={timetableInfo.busId} fromStop={timetableInfo.fromStop} initialDep={timetableInfo.initialDep} onClose={() => setTimetableInfo(null)} isWeekend={isWeekend} nowMins={nowMins} lang={lang} />
      )}
      <div className="route-card-header">
        <span className="route-card-badge">
          {isPrimary ? `⭐ ${t.best || "Legjobb"}` : `${index}. ${t.altLabel || "alternatíva"}`}
        </span>
        <span className="route-card-total">
          📍 {fmt(route.arriveAt)} · {totalStr}
          <button
            onClick={() => setMapOpen(o => !o)}
            title={t.routeOnMap || "Útvonal a térképen"}
            aria-label={t.routeOnMap || "Útvonal a térképen"}
            aria-pressed={mapOpen}
            style={{
              marginLeft: 8, background: mapOpen ? 'var(--accent)' : 'var(--line)',
              border: 'none', borderRadius: 8, padding: '2px 8px',
              cursor: 'pointer', fontSize: 14, color: mapOpen ? 'white' : 'var(--ink)',
              fontFamily: 'inherit', fontWeight: 800, verticalAlign: 'middle',
            }}
          >🗺</button>
        </span>
      </div>

      <div className="route-steps">
        {walkMin > 0 && (
          <>
            <div className="route-step">
              <div className="step-time">{fmt(route.departLeaveOrigin)}</div>
              <div className="step-icon">🚶</div>
              <div className="step-body">
                <div className="step-title">{t.departLabel || "Indulj el"}</div>
                <div className="step-sub">{walkMin} {t.walkToStopLabel || "perc gyaloglás a megállóhoz"}</div>
              </div>
            </div>
            <div className="step-connector">
              <div className="connector-line" />
            </div>
          </>
        )}

        {/* Board bus1 */}
        <div className="route-step">
          <div className="step-time">{fmt(route.boardAt)}</div>
          <BusIcon bus={route.bus1} boardAt={route.boardAt} boardStop={fromStop} />
          <div className="step-body">
            <div className="step-title">
              {t.boardBus || "Szállj fel"} ·{" "}
              <span style={{ color: route.bus1.color, fontWeight: 800 }}>
                {window.busLabel(route.bus1, t)}
              </span>
            </div>
            <div className="step-sub">{window.cityPlatformLabel(route.fromSpId, fromStop)}</div>
          </div>
        </div>

        {route.type === "direct" ? (
          <>
            <div className="step-connector">
              <div className="connector-line" />
              <div className="connector-label">{route.arriveAt - route.boardAt} {t.min}</div>
            </div>
            <div className="route-step">
              <div className="step-time">{fmt(route.arriveAt)}</div>
              <div className="step-icon step-icon-home">📍</div>
              <div className="step-body">
                <div className="step-title">{t.arrivedLabel || "Megérkeztél"}</div>
                <div className="step-sub">{window.cityPlatformLabel(route.toSpId, toStop)}</div>
              </div>
            </div>
          </>
        ) : (
          <>
            <div className="step-connector">
              <div className="connector-line" />
              <div className="connector-label">{route.arriveAtTransfer - route.boardAt} {t.min}</div>
            </div>
            {route.walkTransfer ? (
              <div className="route-step">
                <div className="step-time">{fmt(route.arriveAtTransfer)}</div>
                <div className="step-icon">🚏</div>
                <div className="step-body">
                  <div className="step-title">{t.alightBus || "Szállj le"}</div>
                  <div className="step-sub">{window.cityPlatformLabel(route.transferSpId, route.transferStopName)}</div>
                </div>
              </div>
            ) : (
              <div className="route-step">
                <div className="step-time">{fmt(route.arriveAtTransfer)}</div>
                <div className="step-icon">🔄</div>
                <div className="step-body">
                  <div className="step-title">{t.transfer || "Átszállás"}</div>
                  <div className="step-sub">{window.cityPlatformLabel(route.transferSpId, route.transferStopName)}</div>
                  <div className="wait-pill">⏱ {route.waitAtTransfer} {t.waitLabel || "perc várakozás"}</div>
                </div>
              </div>
            )}
            <div className="step-connector">
              <div className="connector-line" />
              {route.walkTransfer && <div className="connector-label">{route.walkTransfer.walkMin} {t.walkMinLabel || "perc gyalog"} ({route.walkTransfer.distM} m)</div>}
            </div>
            <div className="route-step">
              <div className="step-time">{fmt(route.boardAt2)}</div>
              <BusIcon bus={route.bus2} boardAt={route.boardAt2} boardStop={route.walkToStop || route.transferStopName} />
              <div className="step-body">
                <div className="step-title">
                  {t.boardBus || "Szállj fel"} ·{" "}
                  <span style={{ color: route.bus2.color, fontWeight: 800 }}>
                    {window.busLabel(route.bus2, t)}
                  </span>
                </div>
                <div className="step-sub">{window.cityPlatformLabel(route.walkToSpId || route.transferSpId2, route.walkToStop || route.transferStopName)}</div>
                {route.walkTransfer && route.waitAtTransfer - route.walkTransfer.walkMin > 0 && (
                  <div className="wait-pill">⏱ {route.waitAtTransfer - route.walkTransfer.walkMin} {t.waitLabel || "perc várakozás"}</div>
                )}
              </div>
            </div>
            <div className="step-connector">
              <div className="connector-line" />
              <div className="connector-label">{route.arriveAt - route.boardAt2} {t.min}</div>
            </div>
            <div className="route-step">
              <div className="step-time">{fmt(route.arriveAt)}</div>
              <div className="step-icon step-icon-home">📍</div>
              <div className="step-body">
                <div className="step-title">{t.arrivedLabel || "Megérkeztél"}</div>
                <div className="step-sub">{window.cityPlatformLabel(route.toSpId, toStop)}</div>
              </div>
            </div>
          </>
        )}
      </div>
      <button
        className="route-expand-btn"
        onClick={() => setExpanded(!expanded)}
      >
        {expanded ? t.hideMoreStops : t.showMoreStops} ▾
      </button>

      {mapOpen && <CityRouteMap route={route} fromStop={fromStop} toStop={toStop} lang={lang} />}

      {expanded && (
        <div className="route-details">
          <div className="details-title">{window.busLabel(route.bus1, t)} {t.stopsOf || "megállói:"}</div>
          <div className="details-stops">
            {visibleStops1.map((s, i) => {
              const absTime = fromBoard1 + s.offset;
              return (
                <div key={i} className={`detail-stop${i === 0 ? " home" : ""}${i === visibleStops1.length - 1 ? " transfer" : ""}`}>
                  <span className="detail-stop-time">{fmt(absTime)}</span>
                  <span className="detail-stop-dot" style={{ background: route.bus1.color }} />
                  <span className="detail-stop-name">{s.name}</span>
                </div>
              );
            })}
          </div>
          {visibleStops2.length > 0 && (
            <>
              <div className="details-title" style={{ marginTop: 8 }}>{window.busLabel(route.bus2, t)} {t.stopsOf || "megállói:"}</div>
              <div className="details-stops">
                {visibleStops2.map((s, i) => {
                  const absTime = fromBoard2 + s.offset;
                  return (
                    <div key={i} className={`detail-stop${i === 0 ? " home" : ""}${i === visibleStops2.length - 1 ? " transfer" : ""}`}>
                      <span className="detail-stop-time">{fmt(absTime)}</span>
                      <span className="detail-stop-dot" style={{ background: route.bus2.color }} />
                      <span className="detail-stop-name">{s.name}</span>
                    </div>
                  );
                })}
              </div>
            </>
          )}
        </div>
      )}
    </div>
  );
}


// ── CityMobilePill ───────────────────────────────────────────────────
function CityMobilePill({ timeMode, setTimeMode, customTime, setCustomTime, dayOffset, setDayOffset, schoolHoliday, schoolHolidayMode, setSchoolHolidayMode, schoolHolidayRange, setSchoolHolidayRange, canPlan, plan, lang, onTimetable, onStopViewer, open, openSheet, onClose }) {
  const t = window.I18N[lang] || window.I18N.hu;
  const [collapsed, setCollapsed] = React.useState(false);
  const sheetRef = React.useRef(null);
  const closeButtonRef = React.useRef(null);
  const savedFocusRef = React.useRef(null);
  const dragStartY = React.useRef(null);
  const isDragging = React.useRef(false);
  const lastScrollY = React.useRef(0);

  function close() { setCollapsed(false); onClose(); }

  React.useEffect(() => {
    if (open) {
      savedFocusRef.current = document.activeElement;
      closeButtonRef.current?.focus();
    } else if (savedFocusRef.current) {
      savedFocusRef.current.focus();
      savedFocusRef.current = null;
    }
  }, [open]);

  React.useEffect(() => {
    function onScroll() {
      const y = window.scrollY;
      if (y - lastScrollY.current > 8) setCollapsed(true);
      lastScrollY.current = y;
    }
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  React.useEffect(() => {
    if (!open) return;
    function onKey(e) {
      if (e.key === 'Escape') close();
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);

  React.useEffect(() => {
    if (!open || !sheetRef.current) return;
    const sheet = sheetRef.current;
    function trap(e) {
      if (e.key !== 'Tab') return;
      const focusable = Array.from(sheet.querySelectorAll(
        'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
      ));
      if (focusable.length === 0) return;
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (e.shiftKey) {
        if (document.activeElement === first) { e.preventDefault(); last.focus(); }
      } else {
        if (document.activeElement === last) { e.preventDefault(); first.focus(); }
      }
    }
    sheet.addEventListener('keydown', trap);
    return () => sheet.removeEventListener('keydown', trap);
  }, [open]);

  function onTouchStart(e) {
    if ((sheetRef.current?.scrollTop || 0) > 0) return;
    dragStartY.current = e.touches[0].clientY;
    isDragging.current = false;
  }
  function onTouchMove(e) {
    if (dragStartY.current === null) return;
    const dy = e.touches[0].clientY - dragStartY.current;
    if (dy > 0 && sheetRef.current) {
      isDragging.current = true;
      sheetRef.current.style.transition = "none";
      sheetRef.current.style.transform = `translateY(${dy}px)`;
    }
  }
  function onTouchEnd(e) {
    if (!isDragging.current || dragStartY.current === null) { dragStartY.current = null; return; }
    const dy = e.changedTouches[0].clientY - dragStartY.current;
    dragStartY.current = null; isDragging.current = false;
    if (sheetRef.current) { sheetRef.current.style.transition = ""; sheetRef.current.style.transform = ""; }
    if (dy > 80) close();
  }

  const isNow = timeMode === "now";
  const timePresets = ["06:00","07:00","08:00","09:00","10:00","12:00","14:00","16:00","18:00","20:00"];
  const dayOptions = Array.from({length:7}, (_, i) => {
    const d = new Date(); d.setDate(d.getDate() + i);
    const locale = lang === "hu" ? "hu-HU" : "en-US";
    const full = d.toLocaleDateString(locale, { weekday: "long" });
    const short = i === 0 ? t.todayShort : i === 1 ? t.tomorrowShort : full.slice(0, 3);
    return { offset: i, label: i === 0 ? t.today : i === 1 ? t.tomorrow : full, short };
  });
  const activeDay = dayOptions[dayOffset] || dayOptions[0];

  function setTime(t) {
    setCustomTime(t); localStorage.setItem("city_customTime", t);
    setTimeMode("custom"); localStorage.setItem("city_timeMode", "custom");
    if (canPlan) plan({ timeMode: "custom", customTime: t });
  }
  function goNow() {
    setTimeMode("now"); localStorage.setItem("city_timeMode", "now");
    if (canPlan) plan({ timeMode: "now" });
  }
  return (
    <>
      <div className={"pill-container" + (collapsed ? " pill-collapsed" : "")}>
        <a href="index.html" className="fab-action"
          data-tooltip={lang === "hu" ? "HazaÚt" : "Home Planner"}
          data-tooltip-dir="left"
          aria-label={lang === "hu" ? "HazaÚt" : "Home Planner"}>🏠</a>
        {onTimetable && window.TimetableDropdown && (
          <div className="fab-timetable-wrap">
            <window.TimetableDropdown onSelect={onTimetable} upward fabStyle lang={lang} />
          </div>
        )}
        {onStopViewer && (
          <button className="fab-action" onClick={onStopViewer}
            data-tooltip={lang === "hu" ? "Megállók" : "Stops"}
            data-tooltip-dir="left"
            aria-label={lang === "hu" ? "Megállók" : "Stops"}>🚏</button>
        )}
        <div className="mobile-pill" role="button" tabIndex={0} onClick={openSheet} onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openSheet(); } }} style={{cursor:"pointer"}}>
          <span style={{fontSize:15, padding:"5px 9px", opacity:0.8}}>⚙️</span>
          <span className="pill-sep-mid" />
          <div className="pill-extras pill-zone-chips">
            <span className="pill-chip pill-hl">{isNow ? t.now : customTime}</span>
            {!isNow && <span className="pill-chip">{activeDay.short}</span>}
            {schoolHoliday && <span className="pill-chip">🏖️</span>}
          </div>
        </div>
      </div>

      <div className={"settings-scrim" + (open ? " open" : "")} onClick={close} />
      <div ref={sheetRef} className={"settings-sheet" + (open ? " open" : "")}
        onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd}>
        <div className="sheet-handle" />
        <div className="sheet-head">
          <span className="sheet-head-title">{t.cityPlanTitle}</span>
          <a href="help.html" aria-label={lang === "hu" ? "Súgó" : "Help"} style={{marginLeft:"auto",marginRight:8,fontSize:15,fontWeight:900,color:"var(--ink-soft)",textDecoration:"none",lineHeight:1,padding:"4px 8px",borderRadius:8,background:"var(--line)"}}>?</a>
          <button ref={closeButtonRef} className="sheet-close" aria-label={lang === "hu" ? "Bezárás" : "Close"} onClick={close}>✕</button>
        </div>

        <div className="sec-title">{t.departureTime}</div>
        <div style={{padding:"0 20px 14px"}}>
          <div style={{display:"flex", gap:5, flexWrap:"wrap", marginBottom:10}}>
            <button className={"sel-pill" + (isNow ? " on" : "")} onClick={goNow}>{t.nowBtn}</button>
            {timePresets.map(tp => (
              <button key={tp} className={"sel-pill" + (!isNow && customTime===tp ? " on" : "")}
                onClick={() => setTime(tp)}>{tp}</button>
            ))}
          </div>
          <input type="time" value={isNow ? "" : customTime}
            onChange={e => setTime(e.target.value)}
            placeholder={t.customPlaceholder}
            aria-label={t.departureTime || (lang==="hu" ? "Egyedi indulási idő" : "Custom departure time")}
            className="v1-time-input"
            style={{fontSize:14, padding:"6px 10px", borderRadius:10}} />
        </div>

        <div className="sec-title">{t.daySection}</div>
        <div className="day-chips-grid">
          {dayOptions.map(o => (
            <button key={o.offset}
              className={"day-pill" + (dayOffset===o.offset ? " on" : "") + (o.offset===0 ? " today" : "")}
              onClick={() => {
                setDayOffset(o.offset);
                const newMode = o.offset === 0 && isNow ? "now" : "custom";
                if (newMode !== timeMode) { setTimeMode(newMode); localStorage.setItem("city_timeMode", newMode); }
                if (canPlan) plan({ dayOffset: o.offset, timeMode: newMode });
              }}>
              {o.short}
            </button>
          ))}
        </div>

        <div className="sec-title">{t.filters}</div>
        <div className="sheet-row">
          <span className="row-icon">🏖️</span>
          <div className="row-label">
            <strong>{t.schoolHolidayLabel}</strong>
            <small>{t.schoolHolidaySub}</small>
          </div>
          <div className="tweaks-pill-group" role="radiogroup" aria-label={t.schoolHolidayLabel}>
            {[
              { v: "auto", hu: "Automatikus", en: "Automatic" },
              { v: "on", hu: "Mindig", en: "Always" },
              { v: "off", hu: "Soha", en: "Never" },
            ].map(opt => (
              <button key={opt.v} type="button" role="radio" aria-checked={schoolHolidayMode === opt.v}
                className={"tweaks-pill" + (schoolHolidayMode === opt.v ? " active" : "")}
                onClick={() => {
                  setSchoolHolidayMode(opt.v);
                  if (canPlan) plan({ schoolHoliday: window.SchoolHolidayUtil.resolve(opt.v, new Date(Date.now() + dayOffset * 86400000)) });
                }}>
                {lang==="hu" ? opt.hu : opt.en}
              </button>
            ))}
          </div>
        </div>
        {schoolHolidayMode === "auto" && (
          <div className="sheet-row">
            <span className="row-icon">📅</span>
            <div className="row-label" style={{display:"flex",alignItems:"center",gap:6,flexWrap:"wrap"}}>
              <input type="date" value={schoolHolidayRange.start}
                onChange={e => { setSchoolHolidayRange(e.target.value, schoolHolidayRange.end); if (canPlan) plan(); }}
                style={{fontSize:13,padding:"4px 6px",borderRadius:6,border:"1px solid var(--line)",fontFamily:"inherit"}} />
              <span>–</span>
              <input type="date" value={schoolHolidayRange.end}
                onChange={e => { setSchoolHolidayRange(schoolHolidayRange.start, e.target.value); if (canPlan) plan(); }}
                style={{fontSize:13,padding:"4px 6px",borderRadius:6,border:"1px solid var(--line)",fontFamily:"inherit"}} />
            </div>
          </div>
        )}
        <div style={{height:20}} />
      </div>
    </>
  );
}

// ── CityApp ──────────────────────────────────────────────────────────
function CityApp() {
  const U = window.BUS_UTILS;
  const [lang, setLang] = React.useState(() => localStorage.getItem("lang") || "hu");
  const t = window.I18N[lang] || window.I18N.hu;
  function switchLang(l) {
    setLang(l); localStorage.setItem("lang", l);
    window.dispatchEvent(new Event('gohome:langchange')); // nyitott térképi popupok élő frissítése
  }

  const [isMobile, setIsMobile] = React.useState(() => window.matchMedia("(max-width: 640px)").matches);
  React.useEffect(() => {
    const mq = window.matchMedia("(max-width: 640px)");
    const h = e => setIsMobile(e.matches);
    mq.addEventListener("change", h);
    return () => mq.removeEventListener("change", h);
  }, []);

  const [now, setNow] = React.useState(new Date());
  const [fromStop, setFromStop] = React.useState(() => localStorage.getItem("city_from") || "");
  const [toStop, setToStop] = React.useState(() => localStorage.getItem("city_to") || "");
  const [timeMode, setTimeMode] = React.useState(() => localStorage.getItem("city_timeMode") || "now");
  const [customTime, setCustomTime] = React.useState(() => {
    const saved = localStorage.getItem("city_customTime");
    if (saved) return saved;
    const d = new Date();
    return `${String(d.getHours()).padStart(2,"0")}:${String(d.getMinutes()).padStart(2,"0")}`;
  });
  const walkMin = 0;
  const [dayOffset, setDayOffset] = React.useState(0);
  const [schoolHolidayMode, setSchoolHolidayMode] = React.useState(() => localStorage.getItem("city.schoolholiday.mode") || "auto");
  const [schoolHolidayRange, setSchoolHolidayRangeState] = React.useState(() => window.SchoolHolidayUtil.getRange());
  function setSchoolHolidayRange(start, end) {
    window.SchoolHolidayUtil.setRange(start, end);
    setSchoolHolidayRangeState({ start, end });
  }
  React.useEffect(() => { localStorage.setItem("city.schoolholiday.mode", schoolHolidayMode); }, [schoolHolidayMode]);
  const [results, setResults] = React.useState(null);
  const [formCollapsed, setFormCollapsed] = React.useState(false);
  const [timetableBusId, setTimetableBusId] = React.useState(null);
  const [stopViewerOpen, setStopViewerOpen] = React.useState(false);
  const [stopViewerStop, setStopViewerStop] = React.useState(null);
  const [stopViewerMode, setStopViewerMode] = React.useState('city');
  const [gpsState, setGpsState] = React.useState('idle'); // 'idle' | 'loading' | 'error'

  // Minden fizikai megálló (spId szerint dedupelve) a GPS-alapú legközelebbi-megálló kereséshez
  const allPhysicalStops = React.useMemo(() => {
    const m = new Map();
    for (const bus of window.CITY_BUSES_FULL) {
      for (const s of bus.stops) if (s.lat && !m.has(s.spId)) m.set(s.spId, s);
    }
    return Array.from(m.values());
  }, []);

  // A Honnan/Hova mezőknek sima megállónevek kellenek (a planCityRoutes ezekkel
  // egyezteti a bus.stops[].name mezőt) -- NEM a getCityStops() platform-címkéi
  // (pl. "Bakony Művek (Házgyár felé)"), amik a megálló-nézőnek valók, és amikkel
  // a tervező soha nem talál egyezést.
  const cityStopNames = React.useMemo(
    () => [...new Set(allPhysicalStops.map(s => s.name))].sort((a, b) => a.localeCompare(b, 'hu')),
    [allPhysicalStops]
  );

  // Térképi popupok "Indulások" gombja ezen keresztül nyitja a megálló-nézőt
  React.useEffect(() => {
    window.__openStopViewer = (stopName, mode) => { setStopViewerStop(stopName || null); setStopViewerMode(mode || 'city'); setStopViewerOpen(true); };
    return () => { window.__openStopViewer = undefined; };
  }, []);
  const [sheetOpen, setSheetOpen] = React.useState(false);
  const didPushHistory = React.useRef(false);

  function openSheet() {
    setSheetOpen(true);
    history.pushState({ sheet: true }, "");
    didPushHistory.current = true;
  }
  function closeSheet() {
    setSheetOpen(false);
    if (didPushHistory.current) {
      didPushHistory.current = false;
      history.back();
    }
  }
  React.useEffect(() => {
    function onPop() {
      if (didPushHistory.current) {
        didPushHistory.current = false;
        setSheetOpen(false);
      }
    }
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, []);
  const [planIsWeekend, setPlanIsWeekend] = React.useState(() => { const d = new Date(); return d.getDay() === 0 || d.getDay() === 6; });
  const [planNowMins, setPlanNowMins] = React.useState(() => { const d = new Date(); return d.getHours() * 60 + d.getMinutes(); });

  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 15000);
    return () => clearInterval(id);
  }, []);

  const nowFmt = U.fmtTime(now.getHours() * 60 + now.getMinutes());
  const dateFmt = now.toLocaleDateString(lang === "hu" ? "hu-HU" : "en-US", { weekday: "long", month: "short", day: "numeric" });

  // "auto" módban a kiválasztott nap (dayOffset-tel eltolva) dönt a beállított nyári-szünet tartomány alapján
  const schoolHoliday = React.useMemo(() => {
    const d = new Date(now); d.setDate(d.getDate() + dayOffset);
    return window.SchoolHolidayUtil.resolve(schoolHolidayMode, d);
  }, [schoolHolidayMode, now, dayOffset, schoolHolidayRange]);

  function computePlanTime(overrides = {}) {
    const effectiveMode = overrides.timeMode ?? timeMode;
    const effectiveTime = overrides.customTime ?? customTime;
    const effectiveOffset = overrides.dayOffset ?? dayOffset;
    let planTime;
    if (effectiveMode === "now") {
      planTime = new Date();
    } else {
      const [h, m] = effectiveTime.split(":").map(Number);
      planTime = new Date();
      planTime.setDate(planTime.getDate() + effectiveOffset);
      planTime.setHours(h, m, 0, 0);
    }
    return planTime;
  }

  function plan(overrides = {}) {
    const effectiveFrom = overrides.fromStop ?? fromStop;
    const effectiveTo = overrides.toStop ?? toStop;
    const planTime = computePlanTime(overrides);
    const r = window.planCityRoutes({
      now: planTime,
      fromStop: effectiveFrom,
      toStop: effectiveTo,
      walkMin,
      maxResults: 9,
      schoolHoliday: overrides.schoolHoliday ?? window.SchoolHolidayUtil.resolve(schoolHolidayMode, planTime),
    });
    setResults(r);
    setPlanIsWeekend(planTime.getDay() === 0 || planTime.getDay() === 6);
    setPlanNowMins(planTime.getHours() * 60 + planTime.getMinutes());
    setFormCollapsed(true);
  }

  function swap() {
    const newFrom = toStop;
    const newTo = fromStop;
    setFromStop(newFrom); localStorage.setItem("city_from", newFrom);
    setToStop(newTo);     localStorage.setItem("city_to", newTo);
    if (newFrom && newTo && newFrom !== newTo) {
      plan({ fromStop: newFrom, toStop: newTo });
    } else {
      setResults(null); setFormCollapsed(false);
    }
  }

  const canPlan = fromStop && toStop && fromStop !== toStop;
  const gpsSupported = typeof navigator !== "undefined" && !!navigator.geolocation;

  function handleGps() {
    if (!toStop || gpsState === 'loading') return;
    setGpsState('loading');
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        const { latitude, longitude } = pos.coords;
        const ranked = allPhysicalStops
          .filter(s => s.name !== toStop)
          .map(s => ({ ...s, dist: _haversineM(latitude, longitude, s.lat, s.lon) }))
          .sort((a, b) => a.dist - b.dist);

        const candidates = [];
        const seenNames = new Set();
        for (const s of ranked) {
          if (seenNames.has(s.name)) continue;
          seenNames.add(s.name);
          candidates.push(s.name);
          if (candidates.length >= 3) break;
        }

        if (candidates.length === 0) { setGpsState('error'); setTimeout(() => setGpsState('idle'), 3000); return; }

        const planTime = computePlanTime();
        const schoolHol = window.SchoolHolidayUtil.resolve(schoolHolidayMode, planTime);
        let best = null;
        for (const name of candidates) {
          const r = window.planCityRoutes({ now: planTime, fromStop: name, toStop, walkMin, maxResults: 1, schoolHoliday: schoolHol });
          if (r.length && (!best || r[0].totalDuration < best.duration)) {
            best = { name, duration: r[0].totalDuration };
          }
        }
        const winner = best ? best.name : candidates[0];

        setFromStop(winner); localStorage.setItem("city_from", winner);
        plan({ fromStop: winner });
        setGpsState('idle');
      },
      () => { setGpsState('error'); setTimeout(() => setGpsState('idle'), 3000); },
      { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
    );
  }

  return (
    <div className="v1">
      {timetableBusId && (
        <window.BusTimetableModal busId={timetableBusId} onClose={() => setTimetableBusId(null)} isWeekend={planIsWeekend} nowMins={planNowMins} lang={lang} />
      )}
      {stopViewerOpen && window.StopTimetableModal && (
        <window.StopTimetableModal key={stopViewerStop || 'search'} initialStop={stopViewerStop} initialMode={stopViewerMode}
          onClose={() => { setStopViewerOpen(false); setStopViewerStop(null); }}
          dayType={U.dayType(now, schoolHoliday)} lang={lang} />
      )}
      {/* Header */}
      <div className="v1-header" style={isMobile ? {flexDirection:"row", alignItems:"center", justifyContent:"space-between", gap:8} : {}}>
        <div style={isMobile ? {flex:1, minWidth:0} : {}}>
          <div style={{display:"flex", alignItems:"center", gap:10}}>
            <div className="v1-title">VeszprémBusz 🚌</div>
            <div style={{fontSize:11,fontWeight:700,background:"linear-gradient(135deg,#7C3AED,#C026D3)",color:"white",padding:"2px 8px",borderRadius:6}}>{window.APP_VERSION}</div>
            <div style={{marginLeft:"auto", display:"flex", gap:4}}>
              <button className="tweaks-pill" style={lang==="hu"?{background:"var(--accent)",color:"white"}:{}} onClick={() => switchLang("hu")}>HU</button>
              <button className="tweaks-pill" style={lang==="en"?{background:"var(--accent)",color:"white"}:{}} onClick={() => switchLang("en")}>EN</button>
            </div>
          </div>
          {!isMobile && <div className="v1-subtitle">{t.citySubtitle}</div>}
        </div>
        {!isMobile && (
          <div
            className="v1-clock"
            role="button"
            tabIndex={0}
            aria-label={lang === "hu" ? (timeMode === "now" ? "Jelenlegi idő – kattints az időbeállításhoz" : "Egyéni idő – kattints a visszaállításhoz") : (timeMode === "now" ? "Current time – click to set time" : "Custom time – click to reset to now")}
            onClick={() => { if (timeMode === "now") openSheet(); else { setTimeMode("now"); localStorage.setItem("city_timeMode","now"); if (canPlan) plan({ timeMode: "now" }); } }}
            onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (timeMode === "now") openSheet(); else { setTimeMode("now"); localStorage.setItem("city_timeMode","now"); if (canPlan) plan({ timeMode: "now" }); } } }}
            style={{
              cursor:"pointer",
              background: timeMode !== "now" ? "var(--accent)" : undefined,
              color: timeMode !== "now" ? "white" : undefined,
              outline: timeMode === "now" ? "3px solid var(--sun)" : "3px solid var(--accent)",
              outlineOffset: 2,
              transition: "background 0.2s, outline 0.2s",
            }}
          >
            <div className="v1-clock-label">{timeMode === "now" ? (t.nowBtn || "MOST") : (t.customTimeLabel || "SAJÁT IDŐ")}</div>
            <div className="v1-clock-time">{timeMode === "now" ? nowFmt : customTime}</div>
            <div className="v1-clock-date">{dateFmt}</div>
          </div>
        )}
      </div>
      {isMobile && (
        <div style={{marginTop:4, marginBottom:10}}>
          <div className="v1-subtitle">{t.citySubtitle}</div>
        </div>
      )}


      {/* Planner form */}
      {formCollapsed && results !== null ? (
        <button onClick={() => setFormCollapsed(false)} style={{
          display:"flex", alignItems:"center", justifyContent:"space-between",
          background:"white", borderRadius:"var(--radius)",
          padding:"11px 14px", boxShadow:"var(--shadow)",
          border:"none", cursor:"pointer", fontFamily:"Nunito,sans-serif",
          textAlign:"left",
          ...(isMobile ? { width:"100%", marginBottom: 12 } : { maxWidth: 580, margin: "0 auto 18px" }),
        }}>
          <div style={{display:"flex", flexDirection:"column", gap:2, minWidth:0}}>
            <div style={{fontSize:11, fontWeight:800, color:"var(--ink-soft)", textTransform:"uppercase", letterSpacing:"0.06em"}}>{t.routeSummaryLabel}</div>
            <div style={{fontSize:13, fontWeight:800, color:"var(--ink)", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>
              {fromStop} → {toStop}
            </div>
          </div>
          <span style={{fontSize:18, color:"var(--ink-soft)", flexShrink:0, marginLeft:8}}>✎</span>
        </button>
      ) : (
      <div className="city-form-mobile" style={{
        background: "white", borderRadius: "var(--radius)",
        boxShadow: "var(--shadow)", overflow: "hidden",
        ...(isMobile ? { marginBottom: 12 } : { maxWidth: 580, margin: "0 auto 18px" }),
      }}>
        <div style={{display:"flex", alignItems:"stretch"}}>
          <button onClick={swap} title={t.swapStops} aria-label={t.swapStops} style={{
            background:"none", border:"none", borderRight:"2px solid var(--line)",
            padding:"0 14px", cursor:"pointer", fontSize:20, fontWeight:900, color:"var(--ink-soft)",
            display:"flex", alignItems:"center", flexShrink:0,
          }}>⇅</button>
          <div style={{flex:1, minWidth:0}}>
            <div style={{padding:"10px 12px 8px"}}>
              <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", gap:6, marginBottom:6}}>
                <label className="city-stop-label" htmlFor="from-stop" style={{display:"block"}}>{t.fromLabel}</label>
                {gpsSupported && (
                  <button type="button" onClick={handleGps}
                    disabled={!toStop || gpsState === 'loading'}
                    title={!toStop ? t.gpsNeedsDestination : (gpsState === 'error' ? t.gpsError : t.gpsButtonTooltip)}
                    aria-label={!toStop ? t.gpsNeedsDestination : (gpsState === 'error' ? t.gpsError : t.gpsButtonTooltip)}
                    style={{
                      display:"flex", alignItems:"center", gap:5,
                      background:"none", border:"none", padding:"2px 4px",
                      cursor: (!toStop || gpsState === 'loading') ? "default" : "pointer",
                      opacity: (!toStop || gpsState === 'loading') ? 0.35 : 1,
                      color: gpsState === 'error' ? '#e53935' : 'var(--ink-soft)',
                    }}
                  >
                    <span style={{ fontSize: 19, lineHeight: 1 }}>{gpsState === 'loading' ? '⏳' : '🛰️'}</span>
                    <span style={{ fontSize: 11, fontWeight: 800, fontFamily: "Nunito,sans-serif", textTransform: "uppercase", letterSpacing: "0.06em" }}>{t.gpsLabel || "GPS"}</span>
                  </button>
                )}
              </div>
              <window.StopSearch id="from-stop" value={fromStop}
                onChange={v => { setFromStop(v); localStorage.setItem("city_from", v); setResults(null); setFormCollapsed(false); }}
                placeholder={t.stopPlaceholder} stopList={cityStopNames} />
            </div>
            <div style={{padding:"8px 12px 8px"}}>
              <label className="city-stop-label" htmlFor="to-stop" style={{display:"block"}}>{t.toLabel}</label>
              <window.StopSearch id="to-stop" value={toStop}
                onChange={v => { setToStop(v); localStorage.setItem("city_to", v); setResults(null); setFormCollapsed(false); }}
                placeholder={t.stopPlaceholder} stopList={cityStopNames} />
            </div>
            <div style={{padding:"8px 10px 10px"}}>
              <button
                className="v1-btn primary"
                style={{ width:"100%", justifyContent:"center", opacity: canPlan ? 1 : 0.4, cursor: canPlan ? "pointer" : "not-allowed" }}
                onClick={canPlan ? plan : undefined}
              >{t.searchBtn}</button>
            </div>
          </div>
        </div>
      </div>
      )}

      {/* Results */}
      <div aria-live="polite" role="region" aria-label={lang === "hu" ? "Útvonaltervek" : "Route options"}>
      {results === null ? (
        <div className="v1-empty">
          <div className="v1-empty-emoji">🗺️</div>
          <div className="v1-empty-title">{t.selectStops}</div>
          <div className="v1-empty-hint">{t.selectStopsHint}</div>
        </div>
      ) : results.length === 0 ? (
        <div className="v1-empty">
          <div className="v1-empty-emoji">😔</div>
          <div className="v1-empty-title">{t.noRoutesCity}</div>
          <div className="v1-empty-hint">
            {t.noRoutesHintCity}{" "}
            <strong>{fromStop}</strong> → <strong>{toStop}</strong>{lang === "hu" ? " között." : "."}
          </div>
        </div>
      ) : (
        <>
          {/* Hero banner — best result */}
          <div className="city-hero-banner">
            <div>
              <div style={{ fontSize: 11, opacity: 0.85, fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", marginBottom: 4 }}>
                {t.bestRoute}
              </div>
              <div style={{ fontSize: isMobile ? 28 : 52, fontWeight: 900, lineHeight: 1, fontVariantNumeric: "tabular-nums" }}>
                {U.fmtTime(results[0].arriveAt)}
              </div>
              <div style={{ fontSize: 12, opacity: 0.9, marginTop: 3 }}>
                {toStop} · {results[0].totalDuration} {t.min}
              </div>
            </div>
            {!isMobile && (
              <div style={{ textAlign:"center" }}>
                <div style={{ fontSize:11, opacity:0.7, fontWeight:700, letterSpacing:"0.1em", textTransform:"uppercase", marginBottom:4 }}>
                  {lang === "hu" ? "Keresési idő" : "Search time"}
                </div>
                <div style={{ fontSize:42, fontWeight:900, lineHeight:1, fontVariantNumeric:"tabular-nums" }}>
                  {timeMode === "now" ? (t.nowBtn || "MOST") : customTime}
                </div>
                <div style={{ fontSize:13, opacity:0.85, marginTop:5 }}>
                  {dayOffset === 0 ? (t.today || "Ma") : dayOffset === 1 ? (t.tomorrow || "Holnap") : (() => { const d = new Date(); d.setDate(d.getDate() + dayOffset); return d.toLocaleDateString(lang === "hu" ? "hu-HU" : "en-US", { weekday: "long" }); })()}
                  {schoolHoliday ? " · 🏖️" : ""}
                </div>
              </div>
            )}
            <div style={{ textAlign: "right" }}>
              <div style={{ fontSize: 11, opacity: 0.85 }}>{results.length} {t.routesCount}</div>
              <div style={{ fontSize: isMobile ? 17 : 36, fontWeight: 900, lineHeight: 1, marginTop: 4 }}>
                {results[0].type === "direct" ? t.direct : t.oneTransfer}
              </div>
              <div style={{ fontSize: 12, opacity: 0.8, marginTop: 4 }}>
                {fromStop.length > 20 ? fromStop.slice(0, 20) + "…" : fromStop} →
              </div>
            </div>
          </div>

          <div className="city-results-grid">
            {results.map((r, i) => (
              <CityRouteCard
                key={i}
                route={r}
                index={i + 1}
                isPrimary={i === 0}
                fromStop={fromStop}
                toStop={toStop}
                walkMin={walkMin}
                isWeekend={planIsWeekend}
                nowMins={planNowMins}
                lang={lang}
              />
            ))}
          </div>
        </>
      )}
      </div>

      <div className="app-footer">© 2026 Sándor Norbert</div>

      <CityMobilePill
        timeMode={timeMode} setTimeMode={setTimeMode}
        customTime={customTime} setCustomTime={setCustomTime}
        dayOffset={dayOffset} setDayOffset={setDayOffset}
        schoolHoliday={schoolHoliday} schoolHolidayMode={schoolHolidayMode} setSchoolHolidayMode={setSchoolHolidayMode}
        schoolHolidayRange={schoolHolidayRange} setSchoolHolidayRange={setSchoolHolidayRange}
        canPlan={canPlan} plan={plan} lang={lang}
        onTimetable={id => setTimetableBusId(id)}
        onStopViewer={() => { setStopViewerStop(null); setStopViewerOpen(true); }}
        open={sheetOpen} openSheet={openSheet} onClose={closeSheet}
      />


    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<CityApp />);