import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router';
import { useTranslation, Trans } from 'react-i18next';
import type { TFunction } from 'i18next';
import { MapContainer, TileLayer, Marker, Popup, Polyline, useMap, useMapEvents } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { arabicUiClass, brandTitleClass } from './lib/brandTypography';
import { OmniBrandMark } from './OmniBrandMark';
import { busMapIcon, schoolMapIcon, stopMapIcon, studentPickupCoords } from './lib/mapLayerIcons';
import {
  Bus,
  Search,
  ArrowRightFromLine,
  Bell,
  AlertTriangle,
  Navigation,
  CheckCircle,
  XCircle,
  HeartPulse,
  RefreshCw,
  Users,
  PlusCircle,
  Check,
  Truck,
  Cpu,
  Database,
  Activity,
  FileUp,
  Pencil,
  Download,
  ArrowLeft,
  MapPin,
  Layers,
  ListOrdered,
  Phone,
  Building2,
  Radio,
  Link2,
  Trash2,
  Menu,
  X,
  LifeBuoy,
  Lightbulb,
  Inbox,
  Wallet,
  Home,
} from 'lucide-react';
import { api, apiJson, ApiError, parseFetchJson, readJsonLoose } from './api';
import {
  type Role,
  type AuthedUser,
  ALL_MANAGEABLE_ROLES,
  ALL_PERMISSION_STRINGS,
  userHas,
  isParentRole,
  isStudentRole,
  isDriverRole,
  isSchoolStaffRole,
  isGovernmentViewer,
  roleLabelKey,
  roleBadgeTone,
  showIdeasNav,
  type ScopeRow,
} from './authzClient';
import { IRAQ_MAP_CITY_LABEL_KEYS, IRAQ_MAP_CITY_PRESETS, IRAQ_MAP_DEFAULT } from './lib/iraqMapViews';
import {
  COMING_SOON_ENABLED,
  COMING_SOON_UNLOCK_STORAGE_KEY,
  DEMO_QUICK_LOGINS_ENABLED,
  SHOW_FLEET_TELEMATICS_BANNER,
} from './lib/productFlags';
import { ComingSoonPage } from './ComingSoonPage';
import { getSocket, disconnectSocket } from './socket';
import { FeedbackFeaturesTab, FeedbackSupportTab, SupportAgentDeskTab } from './feedback/FeedbackPages';

delete (L.Icon.Default.prototype as unknown as { _getIconUrl?: unknown })._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
  iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
  shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
});

/** Standalone GPS highlight (e.g. unlinked tracker from ingest) — distinct from bus and student markers. */
const gpsSpotIcon = new L.Icon({
  iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-violet.png',
  shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
  iconSize: [22, 35],
  iconAnchor: [11, 35],
  popupAnchor: [1, -34],
});

/** Drop null/undefined entries from API-backed arrays so .map/.find callbacks never see a missing row. */
function compact(items: readonly unknown[] | null | undefined): any[] {
  return (items ?? []).filter((x) => x != null);
}

/** Every row on the current inventory page is included in the selection (selection may also include rows on other pages). */
function fleetPageFullySelected(selectedImeis: string[], pageDevices: readonly unknown[] | null | undefined): boolean {
  const devs = compact(pageDevices);
  if (devs.length === 0) return false;
  return devs.every((d) => selectedImeis.includes(String((d as { imei?: unknown }).imei ?? '').trim()));
}

/** Map a fleet device row to the Register / activate device form (including formatted desired_config JSON). */
function fleetDeviceToActivateForm(d: {
  imei?: unknown;
  iccid?: unknown;
  phone_number?: unknown;
  device_model?: unknown;
  notes?: unknown;
  desired_config?: unknown;
  firmware?: unknown;
  config_profile?: unknown;
}) {
  let desired_config_json = '';
  try {
    const dc = d.desired_config;
    if (dc == null) desired_config_json = '';
    else if (typeof dc === 'string') desired_config_json = JSON.stringify(JSON.parse(dc), null, 2);
    else if (typeof dc === 'object') desired_config_json = JSON.stringify(dc, null, 2);
    else desired_config_json = '';
  } catch {
    desired_config_json = '';
  }
  const cp = String(d.config_profile ?? 'Standard').trim();
  return {
    imei: String(d.imei ?? ''),
    iccid: String(d.iccid ?? ''),
    phone_number: String(d.phone_number ?? ''),
    device_model: String(d.device_model ?? ''),
    notes: String(d.notes ?? ''),
    desired_config_json,
    firmware: String(d.firmware ?? ''),
    config_profile: cp || 'Standard',
  };
}

/** Next stop the driver is heading to (trip.current_stop indexes the active pickup). */
function getNextStopForDriver(trip: {
  current_stop: number;
  stops: Array<{
    student_id?: string;
    status?: string;
    student?: {
      name?: string;
      address?: { lat: number; lng: number };
      lat?: number;
      lng?: number;
    } | null;
  }>;
} | null | undefined): { name: string; detail?: string } | null {
  if (!trip?.stops?.length) return null;
  let idx = trip.current_stop;
  while (idx < trip.stops.length) {
    const s = trip.stops[idx];
    if (!s) {
      idx++;
      continue;
    }
    if (s.status === 'sick' || s.status === 'skipped') {
      idx++;
      continue;
    }
    const name = s.student?.name || s.student_id || '';
    const addr = s.student?.address;
    const lat = addr?.lat ?? s.student?.lat;
    const lng = addr?.lng ?? s.student?.lng;
    const detail = typeof lat === 'number' && typeof lng === 'number' ? `${lat.toFixed(4)}, ${lng.toFixed(4)}` : undefined;
    return { name: name || '—', detail };
  }
  return null;
}

function tripStopStatusLabel(status: string | undefined, t: (k: string) => string) {
  if (status === 'pending') return t('dashboard.stopStatusPending');
  if (status === 'boarded') return t('dashboard.stopStatusBoarded');
  if (status === 'sick') return t('dashboard.stopStatusSick');
  return status || t('dashboard.stopStatusOther');
}

function MapFlyToTarget({ lat, lng, seq, zoom = 15 }: { lat: number; lng: number; seq: number; zoom?: number }) {
  const map = useMap();
  useEffect(() => {
    map.flyTo([lat, lng], zoom, { duration: 1.1 });
  }, [lat, lng, seq, zoom, map]);
  return null;
}

const MAP_FOLLOW_LIVE_ZOOM = 16;

/** Keeps the map centered on a moving bus while live-follow is active. */
function MapFollowLiveBus({ busId, lat, lng }: { busId: string; lat: number; lng: number }) {
  const map = useMap();
  const lastBusIdRef = useRef<string | null>(null);
  useEffect(() => {
    if (!Number.isFinite(lat) || !Number.isFinite(lng)) return;
    const isNewBus = lastBusIdRef.current !== busId;
    lastBusIdRef.current = busId;
    if (isNewBus) {
      map.flyTo([lat, lng], MAP_FOLLOW_LIVE_ZOOM, { duration: 1.1 });
    } else {
      map.panTo([lat, lng], { animate: true, duration: 0.55 });
    }
  }, [busId, lat, lng, map]);
  return null;
}

/** Stop live-follow when the user pans the map manually. */
function MapFollowStopOnUserPan({ onStop }: { onStop: () => void }) {
  useMapEvents({
    dragstart: () => onStop(),
  });
  return null;
}

function busSeatsFree(bus: Record<string, unknown>): number {
  const cap = Number(bus.capacity) || 0;
  const occ = Number(bus.occupancy) || 0;
  return Math.max(0, cap - occ);
}

function lineBusOptionLabel(bus: Record<string, unknown>, t: (key: string, opts?: Record<string, unknown>) => string): string {
  const plate = String(bus.license_plate || bus.id || '—');
  const model = String(bus.make_model || '').trim() || t('parentUi.busTypeUnknown');
  const cap = Number(bus.capacity) || 0;
  const free = busSeatsFree(bus);
  return `${plate} · ${model} · ${t('parentUi.busSeatsFree', { free, cap })}`;
}

type GlobalSearchResult = {
  query: string;
  users: Array<{
    id: string;
    role: string;
    name: string;
    email: string | null;
    school_id: string | null;
    bus_id: string | null;
    school_name: string | null;
    bus_license_plate: string | null;
  }>;
  buses: Array<{
    id: string;
    license_plate: string | null;
    imei: string | null;
    school_id: string | null;
    school_name: string | null;
    status: string | null;
    driver_name: string | null;
    lat: number | null;
    lng: number | null;
  }>;
  devices: Array<{
    imei: string;
    phone_number: string | null;
    iccid: string | null;
    device_model: string | null;
    device_status: string | null;
    bus_id: string | null;
    bus_license_plate: string | null;
    school_name: string | null;
  }>;
  students: Array<{
    id: string;
    name: string;
    school_id: string | null;
    parent_id: string | null;
    lat: number | null;
    lng: number | null;
    school_name: string | null;
    parent_name: string | null;
  }>;
  schools: Array<{
    id: string;
    name: string;
    lat?: number | null;
    lng?: number | null;
    address_line1?: string | null;
    address_city?: string | null;
  }>;
};

export type { Role } from './authzClient';

/** Seeded Iraq demo users — keep in sync with `IRAQ_DEMO_LOGIN_USER_ROWS` in `seedIraqDemo.ts`. */
const DEMO_QUICK_LOGINS: readonly { role: Role; email: string }[] = [
  { role: 'government_operator', email: 'gov.admin@demo.local' },
  { role: 'government_viewer', email: 'gov.viewer@demo.local' },
  { role: 'school', email: 'school1@demo.local' },
  { role: 'school', email: 'school2@demo.local' },
  { role: 'school_operator', email: 'school.op@demo.local' },
  { role: 'fleet_operator', email: 'fleet.op@demo.local' },
  { role: 'parent', email: 'parent1@demo.local' },
  { role: 'driver', email: 'driver@demo.local' },
];

function demoQuickLoginSectionEnabled(): boolean {
  return DEMO_QUICK_LOGINS_ENABLED;
}

function demoSeedPasswordPlain(): string {
  const v = import.meta.env.VITE_SEED_DEMO_PASSWORD;
  return typeof v === 'string' && v.trim() !== '' ? v.trim() : 'DemoPass123';
}

export interface User extends AuthedUser {
  role: string;
}
export interface School {
  id: string;
  name: string;
  address_line1?: string | null;
  address_city?: string | null;
  lat?: number | null;
  lng?: number | null;
  student_count?: number;
  class_count?: number;
  bus_count?: number;
}

function schoolHasMapCoords(sch: School): boolean {
  const la = sch.lat;
  const ln = sch.lng;
  return typeof la === 'number' && typeof ln === 'number' && Number.isFinite(la) && Number.isFinite(ln);
}

function BootLoading() {
  const { t } = useTranslation();
  return (
    <div className="flex min-h-[100dvh] items-center justify-center bg-slate-50 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-[max(1rem,env(safe-area-inset-top))] text-slate-600">
      {t('common.loading')}
    </div>
  );
}

function LanguageSwitcher() {
  const { i18n, t } = useTranslation();
  return (
    <select
      value={i18n.language}
      onChange={(e) => void i18n.changeLanguage(e.target.value)}
      className="min-h-10 rounded-lg border border-slate-200 bg-white px-2 py-2 text-sm text-slate-700 sm:min-h-0 sm:py-1.5"
      aria-label={t('login.lang')}
    >
      <option value="en">English</option>
      <option value="ar-IQ">العربية العراقية</option>
      <option value="ckb">کوردی (سۆرانی)</option>
    </select>
  );
}

function Login({
  onSuccess,
}: {
  onSuccess: (user: User, needsBootstrap: boolean) => void;
}) {
  const { t, i18n } = useTranslation();
  const [identifier, setIdentifier] = useState('');
  const [loginStep, setLoginStep] = useState<'identifier' | 'password' | 'otp'>('identifier');
  const [authMethod, setAuthMethod] = useState<'password' | 'otp'>('password');
  const [otpChannels, setOtpChannels] = useState<Array<'sms' | 'whatsapp'>>(['sms']);
  const [otpChannel, setOtpChannel] = useState<'sms' | 'whatsapp'>('sms');
  const [otpCode, setOtpCode] = useState('');
  const [otpSent, setOtpSent] = useState(false);
  const [otpInfo, setOtpInfo] = useState('');
  const [password, setPassword] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');
  const [reopenToken, setReopenToken] = useState('');
  const [reopenBusy, setReopenBusy] = useState(false);
  const [reopenMsg, setReopenMsg] = useState('');
  const [demoBusyEmail, setDemoBusyEmail] = useState<string | null>(null);
  /** `ok` = DB ready; `/readyz` JSON `reason` or network failure. */
  const [dbGate, setDbGate] = useState<
    'checking' | 'ok' | 'no_database' | 'db_auth' | 'db_conn' | 'db_other' | 'network'
  >('checking');

  useEffect(() => {
    api('/readyz')
      .then(async (r) => {
        if (r.ok) {
          setDbGate('ok');
          return;
        }
        const j = (await readJsonLoose<{ reason?: string }>(r)) as { reason?: string };
        const reason = j.reason;
        if (reason === 'no_database') setDbGate('no_database');
        else if (reason === 'db_auth_failed') setDbGate('db_auth');
        else if (reason === 'db_connection_failed') setDbGate('db_conn');
        else if (reason === 'db_unavailable' || reason === 'db_setup_failed') setDbGate('db_other');
        else setDbGate('db_other');
      })
      .catch(() => setDbGate('network'));
  }, []);

  const mapLoginError = (d: { error?: string; code?: string }, status: number) => {
    if (d.code === 'BOOTSTRAP_ADMIN_RETIRED') setError(t('login.bootstrapAdminRetired'));
    else if (d.code === 'ACCOUNT_DISABLED') setError(t('login.accountDisabled'));
    else if (d.code === 'BOOTSTRAP_REQUIRED') setError(t('login.bootstrapRequired'));
    else if (d.code === 'SESSION_PERSIST_FAILED') setError(t('login.sessionPersistError'));
    else if (d.code === 'AUTH_PASSWORD_REQUIRED') setError(t('login.otpPasswordRequired'));
    else if (d.code === 'OTP_NOT_CONFIGURED') setError(t('login.otpNotConfigured'));
    else if (d.code === 'OTP_SEND_FAILED') setError(t('login.otpSendFailed'));
    else if (d.code === 'OTP_EXPIRED' || d.code === 'INVALID_OTP') setError(t('login.otpInvalid'));
    else if (d.code === 'OTP_LOCKED') setError(t('login.otpLocked'));
    else if (d.code === 'INVALID_CREDENTIALS' || status === 401) setError(t('login.invalid'));
    else setError(d.error || t('login.invalid'));
  };

  const runLoginRequest = async (loginIdentifier: string, loginPassword: string) => {
    const res = await api('/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ identifier: loginIdentifier, password: loginPassword }),
    });
    const data = await readJsonLoose(res);
    if (!res.ok) {
      mapLoginError(data as { error?: string; code?: string }, res.status);
      return;
    }
    onSuccess((data as { user: User }).user, !!(data as { needsBootstrap?: boolean }).needsBootstrap);
  };

  const handleContinueIdentifier = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setOtpInfo('');
    const id = identifier.trim();
    if (!id) return;
    setBusy(true);
    try {
      const res = await api('/api/auth/login/method', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ identifier: id }),
      });
      const data = (await readJsonLoose(res)) as {
        method?: 'password' | 'otp';
        channels?: Array<'sms' | 'whatsapp'>;
      };
      if (!res.ok) {
        setError(t('login.authMethodFailed'));
        return;
      }
      const method = data.method === 'password' ? 'password' : 'otp';
      setAuthMethod(method);
      const ch = (Array.isArray(data.channels) && data.channels.length
        ? data.channels.filter((c): c is 'sms' | 'whatsapp' => c === 'sms' || c === 'whatsapp')
        : ['sms']) as Array<'sms' | 'whatsapp'>;
      setOtpChannels(ch.length ? ch : ['sms']);
      setOtpChannel(ch.includes('whatsapp') ? 'whatsapp' : (ch[0] ?? 'sms'));
      setLoginStep(method === 'password' ? 'password' : 'otp');
      setOtpSent(false);
      setOtpCode('');
    } catch {
      setError(t('login.authMethodFailed'));
    } finally {
      setBusy(false);
    }
  };

  const handlePasswordLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setReopenMsg('');
    setBusy(true);
    try {
      await runLoginRequest(identifier.trim(), password);
    } catch {
      setError(t('login.invalid'));
    } finally {
      setBusy(false);
    }
  };

  const handleOtpRequest = async (channel: 'sms' | 'whatsapp') => {
    setError('');
    setOtpInfo('');
    setBusy(true);
    try {
      const res = await api('/api/auth/otp/request', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phone: identifier.trim(), channel }),
      });
      const data = await readJsonLoose(res);
      if (!res.ok) {
        mapLoginError(data as { error?: string; code?: string }, res.status);
        return;
      }
      setOtpChannel(channel);
      setOtpSent(true);
      setOtpInfo(t('login.otpSent'));
    } catch {
      setError(t('login.otpSendFailed'));
    } finally {
      setBusy(false);
    }
  };

  const handleOtpVerify = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setBusy(true);
    try {
      const res = await api('/api/auth/otp/verify', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phone: identifier.trim(), code: otpCode.trim() }),
      });
      const data = await readJsonLoose(res);
      if (!res.ok) {
        mapLoginError(data as { error?: string; code?: string }, res.status);
        return;
      }
      onSuccess((data as { user: User }).user, !!(data as { needsBootstrap?: boolean }).needsBootstrap);
    } catch {
      setError(t('login.otpInvalid'));
    } finally {
      setBusy(false);
    }
  };

  const resetLoginFlow = () => {
    setLoginStep('identifier');
    setPassword('');
    setOtpCode('');
    setOtpSent(false);
    setOtpInfo('');
    setError('');
  };

  const handleReopenBootstrap = async () => {
    setError('');
    setReopenMsg('');
    const tok = reopenToken.trim();
    if (!tok) {
      setError(t('login.reopenTokenMissing'));
      return;
    }
    setReopenBusy(true);
    try {
      const res = await api('/api/bootstrap/reopen', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ reopenToken: tok }),
      });
      const data = await readJsonLoose(res);
      if (!res.ok) {
        const d = data as { code?: string; error?: string };
        if (d.code === 'BOOTSTRAP_REOPEN_DISABLED') setError(t('login.reopenDisabled'));
        else if (d.code === 'BOOTSTRAP_REOPEN_UNAUTHORIZED') setError(t('login.reopenUnauthorized'));
        else if (d.code === 'BOOTSTRAP_REOPEN_NOT_NEEDED') setError(t('login.reopenNotNeeded'));
        else if (d.code === 'BOOTSTRAP_REOPEN_FAILED') setError(t('login.reopenFailed'));
        else setError(d.error || t('login.invalid'));
        return;
      }
      setReopenToken('');
      setReopenMsg(t('login.reopenSuccess'));
    } catch {
      setError(t('login.invalid'));
    } finally {
      setReopenBusy(false);
    }
  };

  const handleDemoQuickLogin = async (demoEmail: string) => {
    setError('');
    setIdentifier(demoEmail);
    const pw = demoSeedPasswordPlain();
    setPassword(pw);
    setLoginStep('password');
    setAuthMethod('password');
    setDemoBusyEmail(demoEmail);
    try {
      await runLoginRequest(demoEmail, pw);
    } catch {
      setError(t('login.invalid'));
    } finally {
      setDemoBusyEmail(null);
    }
  };

  return (
    <div
      className={`flex min-h-[100dvh] flex-col items-center justify-center bg-slate-50 p-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-[max(1rem,env(safe-area-inset-top))] font-sans text-slate-800 ${arabicUiClass(i18n.language)}`}
    >
      <div className="absolute end-4 top-[max(1rem,env(safe-area-inset-top))] z-10">
        <LanguageSwitcher />
      </div>
      <div className="mx-auto w-full max-w-md rounded-xl border border-slate-200 bg-white p-5 shadow sm:p-8">
        <div className="flex justify-center mb-6">
          <OmniBrandMark className="h-16 w-16 drop-shadow-md" />
        </div>
        <h2
          className={`text-2xl text-center text-slate-800 mb-1 tracking-tight ${brandTitleClass(i18n.language)}`}
        >
          {t('login.title')}
        </h2>
        <p className="text-center text-slate-500 text-sm mb-6">{t('login.subtitle')}</p>
        {dbGate !== 'ok' && dbGate !== 'checking' ? (
          <div className="text-sm bg-orange-50 p-4 rounded-xl text-orange-800 border border-orange-200 text-center font-medium leading-relaxed">
            {dbGate === 'no_database'
              ? t('login.dbErrorMissingUrl')
              : dbGate === 'network'
                ? t('login.dbErrorNetwork')
                : dbGate === 'db_auth'
                  ? t('login.dbErrorPgAuth')
                  : dbGate === 'db_conn'
                    ? t('login.dbErrorPgConn')
                    : t('login.dbErrorUnreachable')}
          </div>
        ) : (
          <div className="space-y-4">
            {error && <div className="text-sm text-red-600 bg-red-50 border border-red-100 rounded-lg p-2">{error}</div>}
            {otpInfo ? (
              <div className="text-sm text-green-800 bg-green-50 border border-green-100 rounded-lg p-2">{otpInfo}</div>
            ) : null}
            {loginStep === 'identifier' ? (
              <form onSubmit={(e) => void handleContinueIdentifier(e)} className="space-y-4">
                <div>
                  <label className="block text-[0.85rem] font-bold text-slate-800 mb-1">{t('login.identifier')}</label>
                  <p className="mb-2 text-xs text-slate-500">{t('login.identifierHint')}</p>
                  <input
                    type="text"
                    autoComplete="username"
                    inputMode="email"
                    className="w-full rounded-lg border border-slate-200 bg-slate-50 p-3 text-[0.95rem] outline-none focus:ring-2 focus:ring-blue-500 sm:bg-slate-100 sm:p-2.5 sm:text-[0.9rem]"
                    value={identifier}
                    onChange={(e) => setIdentifier(e.target.value)}
                    required
                    disabled={demoBusyEmail !== null || busy}
                  />
                </div>
                <button
                  type="submit"
                  disabled={demoBusyEmail !== null || busy}
                  className="flex min-h-11 w-full items-center justify-center gap-2 rounded-lg bg-blue-500 py-3 font-medium text-white hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-60 sm:min-h-0 sm:py-2.5"
                >
                  {busy ? t('common.loading') : t('login.continue')} <ArrowRightFromLine className="w-4 h-4" />
                </button>
              </form>
            ) : loginStep === 'password' ? (
              <form onSubmit={(e) => void handlePasswordLogin(e)} className="space-y-4">
                <button
                  type="button"
                  className="text-sm text-blue-600 hover:underline"
                  onClick={resetLoginFlow}
                  disabled={busy || demoBusyEmail !== null}
                >
                  {t('login.back')}
                </button>
                <div>
                  <label className="block text-[0.85rem] font-bold text-slate-800 mb-1">{t('login.password')}</label>
                  <input
                    type="password"
                    autoComplete="current-password"
                    className="w-full rounded-lg border border-slate-200 bg-slate-50 p-3 text-[0.95rem] outline-none focus:ring-2 focus:ring-blue-500 sm:bg-slate-100 sm:p-2.5 sm:text-[0.9rem]"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    required
                    disabled={demoBusyEmail !== null || busy}
                  />
                </div>
                <button
                  type="submit"
                  disabled={demoBusyEmail !== null || busy}
                  className="flex min-h-11 w-full items-center justify-center gap-2 rounded-lg bg-blue-500 py-3 font-medium text-white hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-60 sm:min-h-0 sm:py-2.5"
                >
                  {busy ? t('common.loading') : t('login.submit')} <ArrowRightFromLine className="w-4 h-4" />
                </button>
              </form>
            ) : (
              <div className="space-y-4">
                <button
                  type="button"
                  className="text-sm text-blue-600 hover:underline"
                  onClick={resetLoginFlow}
                  disabled={busy || demoBusyEmail !== null}
                >
                  {t('login.back')}
                </button>
                <div>
                  <p className="text-sm font-semibold text-slate-800">{t('login.otpTitle')}</p>
                  <p className="mt-1 text-xs text-slate-500">{t('login.otpHint')}</p>
                </div>
                <div className="flex flex-col gap-2 sm:flex-row">
                  {otpChannels.includes('sms') ? (
                    <button
                      type="button"
                      disabled={busy || demoBusyEmail !== null}
                      onClick={() => void handleOtpRequest('sms')}
                      className="min-h-11 flex-1 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium hover:bg-slate-50 disabled:opacity-60"
                    >
                      {t('login.otpSendSms')}
                    </button>
                  ) : null}
                  {otpChannels.includes('whatsapp') ? (
                    <button
                      type="button"
                      disabled={busy || demoBusyEmail !== null}
                      onClick={() => void handleOtpRequest('whatsapp')}
                      className="min-h-11 flex-1 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm font-medium text-emerald-900 hover:bg-emerald-100 disabled:opacity-60"
                    >
                      {t('login.otpSendWhatsApp')}
                    </button>
                  ) : null}
                </div>
                {otpSent ? (
                  <form onSubmit={(e) => void handleOtpVerify(e)} className="space-y-3">
                    <div>
                      <label className="block text-[0.85rem] font-bold text-slate-800 mb-1">{t('login.otpCodeLabel')}</label>
                      <input
                        inputMode="numeric"
                        pattern="[0-9]{6}"
                        maxLength={6}
                        autoComplete="one-time-code"
                        className="w-full rounded-lg border border-slate-200 bg-slate-50 p-3 text-center text-lg tracking-widest outline-none focus:ring-2 focus:ring-blue-500"
                        value={otpCode}
                        onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
                        required
                        disabled={busy}
                      />
                    </div>
                    <button
                      type="submit"
                      disabled={busy || otpCode.length !== 6}
                      className="flex min-h-11 w-full items-center justify-center rounded-lg bg-blue-500 py-3 font-medium text-white hover:bg-blue-600 disabled:opacity-60"
                    >
                      {busy ? t('common.loading') : t('login.otpVerify')}
                    </button>
                  </form>
                ) : null}
              </div>
            )}
            <details className="rounded-lg border border-slate-200 bg-slate-50/90 text-sm text-slate-700">
              <summary className="cursor-pointer select-none px-3 py-2 font-medium text-slate-600 hover:bg-slate-100/80 rounded-lg">
                {t('login.reopenSummary')}
              </summary>
              <div className="space-y-2 border-t border-slate-200 p-3">
                <p className="text-xs leading-relaxed text-slate-500">{t('login.reopenHint')}</p>
                <label className="block text-[0.75rem] font-semibold uppercase tracking-wide text-slate-500">
                  {t('login.reopenTokenLabel')}
                </label>
                <input
                  type="password"
                  autoComplete="off"
                  className="w-full rounded-lg border border-slate-200 bg-white p-2.5 text-[0.9rem] outline-none focus:ring-2 focus:ring-blue-500"
                  value={reopenToken}
                  onChange={(e) => setReopenToken(e.target.value)}
                  disabled={reopenBusy || demoBusyEmail !== null}
                  placeholder={t('login.reopenTokenPlaceholder')}
                />
                <button
                  type="button"
                  disabled={reopenBusy || demoBusyEmail !== null}
                  onClick={() => void handleReopenBootstrap()}
                  className="w-full rounded-lg border border-amber-200 bg-amber-50 py-2 text-sm font-medium text-amber-900 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {reopenBusy ? t('common.loading') : t('login.reopenSubmit')}
                </button>
                {reopenMsg ? (
                  <div className="rounded-md border border-green-200 bg-green-50 p-2 text-xs text-green-800">{reopenMsg}</div>
                ) : null}
              </div>
            </details>
            {demoQuickLoginSectionEnabled() && (
              <div className="border-t border-slate-200 pt-4">
                <p className="text-xs font-semibold uppercase tracking-wide text-slate-500">{t('login.demoTitle')}</p>
                <p className="mt-1 text-xs leading-relaxed text-slate-500">{t('login.demoHint')}</p>
                <div className="mt-3 grid grid-cols-2 gap-2 sm:grid-cols-3">
                  {DEMO_QUICK_LOGINS.map(({ role, email: demoEmail }) => {
                    const busy = demoBusyEmail === demoEmail;
                    const accountHint = demoEmail.replace(/@demo\.local$/i, '');
                    return (
                      <button
                        key={demoEmail}
                        type="button"
                        disabled={demoBusyEmail !== null}
                        onClick={() => void handleDemoQuickLogin(demoEmail)}
                        className="min-h-[2.75rem] rounded-lg border border-slate-200 bg-slate-50 px-2 py-2 text-start text-sm font-medium text-slate-800 hover:border-blue-300 hover:bg-blue-50 disabled:cursor-not-allowed disabled:opacity-60"
                        aria-busy={busy}
                      >
                        {busy ? (
                          t('common.loading')
                        ) : (
                          <span className="flex flex-col gap-0.5 leading-tight">
                            <span>{t(`roles.${role}`)}</span>
                            <span className="text-[10px] font-normal text-slate-500">{accountHint}</span>
                          </span>
                        )}
                      </button>
                    );
                  })}
                </div>
              </div>
            )}
          </div>
        )}
      </div>
      <p className="mt-4 max-w-md text-center text-xs text-slate-500">
        <a href="/privacy" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">
          {t('legal.privacyPolicy')}
        </a>
        <span className="mx-2 text-slate-300" aria-hidden>
          ·
        </span>
        <a href="/account-deletion" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">
          {t('legal.accountDeletion')}
        </a>
      </p>
    </div>
  );
}

function BootstrapWizard({ onDone }: { onDone: () => void }) {
  const { t } = useTranslation();
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const submit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    try {
      await apiJson('/api/bootstrap/complete', { name, email, password });
      alert(t('bootstrap.success'));
      onDone();
    } catch (err) {
      if (err instanceof ApiError && err.code === 'SESSION_REQUIRED') setError(t('bootstrap.sessionLost'));
      else if (err instanceof ApiError && err.code === 'NOT_BOOTSTRAP_ADMIN') setError(t('bootstrap.notBootstrap'));
      else setError(err instanceof Error ? err.message : 'Error');
    }
  };
  return (
    <div className="flex min-h-[100dvh] flex-col items-center justify-center bg-slate-50 p-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-[max(1rem,env(safe-area-inset-top))]">
      <div className="absolute end-4 top-[max(1rem,env(safe-area-inset-top))] z-10">
        <LanguageSwitcher />
      </div>
      <div className="mx-auto w-full max-w-md rounded-xl border border-slate-200 bg-white p-5 shadow sm:p-8">
        <h2 className="text-xl font-bold mb-2">{t('bootstrap.title')}</h2>
        <p className="text-sm text-slate-600 mb-6">{t('bootstrap.intro')}</p>
        {error && <div className="mb-4 text-sm text-red-600 bg-red-50 p-2 rounded">{error}</div>}
        <form onSubmit={submit} className="space-y-4">
          <input
            required
            className="min-h-11 w-full rounded-lg border border-slate-200 p-3 sm:min-h-0 sm:p-2"
            placeholder={t('bootstrap.name')}
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
          <input
            required
            type="email"
            className="min-h-11 w-full rounded-lg border border-slate-200 p-3 sm:min-h-0 sm:p-2"
            placeholder={t('bootstrap.email')}
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <input
            required
            type="password"
            minLength={10}
            className="min-h-11 w-full rounded-lg border border-slate-200 p-3 sm:min-h-0 sm:p-2"
            placeholder={t('bootstrap.password')}
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <button type="submit" className="min-h-11 w-full rounded-lg bg-indigo-600 py-3 font-medium text-white sm:min-h-0 sm:py-2.5">
            {t('bootstrap.submit')}
          </button>
        </form>
      </div>
    </div>
  );
}

function DriverDashboard({ user, onLogout }: { user: User; onLogout: () => void }) {
  const { t } = useTranslation();
  const [trip, setTrip] = useState<{ current_stop: number; stops: any[] } | null>(null);
  const [driverShell, setDriverShell] = useState<'main' | 'support' | 'features'>('main');
  useEffect(() => {
    if (!showIdeasNav() && driverShell === 'features') setDriverShell('main');
  }, [driverShell]);
  const [driverMain, setDriverMain] = useState<'home' | 'scope' | 'students' | 'notices' | 'requests' | 'run'>('run');
  const [wallet, setWallet] = useState<{ wallet?: { balance_minor: number }; ledger?: unknown[]; withdrawals?: unknown[] } | null>(null);
  const [roster, setRoster] = useState<any[]>([]);
  const [servedSchools, setServedSchools] = useState<Array<{ school_id: string; school_name: string }>>([]);
  const [allSchools, setAllSchools] = useState<Array<{ id: string; name: string }>>([]);
  const [selectedSchoolIds, setSelectedSchoolIds] = useState<Set<string>>(new Set());
  const [notices, setNotices] = useState<any[]>([]);
  const [requests, setRequests] = useState<any[]>([]);
  const [wdAmount, setWdAmount] = useState('');
  const [wdIban, setWdIban] = useState('');
  const [wdHolder, setWdHolder] = useState('');
  const [noticeTo, setNoticeTo] = useState('');
  const [noticeBody, setNoticeBody] = useState('');

  const fetchTrip = () => {
    if (!user.bus_id) return;
    api(`/api/trip/${user.bus_id}`)
      .then((r) => parseFetchJson(r))
      .then(setTrip)
      .catch(() => {});
  };

  const loadWallet = () => {
    void api('/api/wallet/me')
      .then((r) => parseFetchJson(r))
      .then(setWallet)
      .catch(() => setWallet(null));
  };
  const loadRoster = () => {
    void api('/api/driver/roster')
      .then((r) => parseFetchJson(r))
      .then((d: { students?: any[] }) => setRoster(d.students || []))
      .catch(() => setRoster([]));
  };
  const loadServed = () => {
    void api('/api/driver/served-schools')
      .then((r) => parseFetchJson(r))
      .then((rows: Array<{ school_id: string; school_name: string }>) => {
        setServedSchools(rows);
        setSelectedSchoolIds(new Set(rows.map((x) => x.school_id)));
      })
      .catch(() => {});
  };
  const loadSchools = () => {
    void api('/api/schools')
      .then((r) => parseFetchJson(r))
      .then((rows: Array<{ id: string; name: string }>) => setAllSchools(rows))
      .catch(() => {});
  };
  const loadNotices = () => {
    void api('/api/transport/notices')
      .then((r) => parseFetchJson(r))
      .then(setNotices)
      .catch(() => setNotices([]));
  };
  const loadRequests = () => {
    void api('/api/transport/requests')
      .then((r) => parseFetchJson(r))
      .then(setRequests)
      .catch(() => setRequests([]));
  };

  useEffect(() => {
    if (!user.bus_id) return;
    fetchTrip();
    const socket = getSocket();
    const onTrip = (data: { busId: string; trip: { current_stop: number; stops: any[] } }) => {
      if (data.busId === user.bus_id) setTrip(data.trip);
    };
    const onWallet = () => loadWallet();
    const onTn = () => {
      loadNotices();
      loadRequests();
    };
    socket.on('tripUpdate', onTrip);
    socket.on('walletUpdated', onWallet);
    socket.on('transportNotice', onTn);
    return () => {
      socket.off('tripUpdate', onTrip);
      socket.off('walletUpdated', onWallet);
      socket.off('transportNotice', onTn);
    };
  }, [user.bus_id]);

  useEffect(() => {
    if (driverShell !== 'main') return;
    if (driverMain === 'home') loadWallet();
    if (driverMain === 'students') loadRoster();
    if (driverMain === 'scope') {
      loadSchools();
      loadServed();
    }
    if (driverMain === 'notices') loadNotices();
    if (driverMain === 'requests') loadRequests();
  }, [driverShell, driverMain]);

  const handleAction = async (studentId: string, action: 'boarded' | 'no_show') => {
    try {
      const r = await api('/api/trip/action', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ busId: user.bus_id, studentId, action }),
      });
      await parseFetchJson(r);
      fetchTrip();
    } catch (e) {
      if (e instanceof ApiError && (e.status === 402 || e.code === 'INSUFFICIENT_WALLET')) {
        alert(t('wallet.insufficientForBoarding'));
      } else if (e instanceof Error) {
        alert(e.message);
      }
    }
  };

  if (driverShell === 'support' || (driverShell === 'features' && showIdeasNav())) {
    return (
      <div className="flex min-h-[100dvh] flex-col bg-slate-100 font-sans text-slate-800">
        <header className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-b border-slate-800 bg-slate-900 p-3 text-white sm:p-4 pt-[max(0.75rem,env(safe-area-inset-top))]">
          <div className="flex flex-wrap items-center gap-2">
            <LanguageSwitcher />
            <button
              type="button"
              onClick={() => setDriverShell('main')}
              className="rounded-lg border border-slate-600 bg-slate-800 px-3 py-2 text-sm font-bold hover:bg-slate-700"
            >
              ← {t('driver.backToRoute')}
            </button>
          </div>
          <button type="button" onClick={onLogout} className="min-h-10 shrink-0 rounded-lg px-3 py-2 text-sm text-slate-300 hover:bg-slate-800 hover:text-white">
            {t('driver.logout')}
          </button>
        </header>
        <div className="flex min-h-0 min-h-[60dvh] flex-1 flex-col">
          {driverShell === 'support' ? <FeedbackSupportTab user={user} /> : <FeedbackFeaturesTab user={user} />}
        </div>
      </div>
    );
  }

  const currentStop = trip?.stops?.[trip.current_stop];
  const student = currentStop?.student;

  const tabClass = (m: typeof driverMain) =>
    `flex flex-col items-center justify-center gap-0.5 py-2 text-[0.65rem] font-bold sm:text-xs ${driverMain === m ? 'bg-slate-900 text-white' : 'text-slate-600 hover:bg-slate-100'}`;

  return (
    <div className="flex min-h-[100dvh] flex-col bg-slate-100 font-sans text-slate-800">
      <header className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-b border-slate-800 bg-slate-900 p-3 text-white sm:p-4 pt-[max(0.75rem,env(safe-area-inset-top))]">
        <div className="flex min-w-0 flex-1 flex-wrap items-center gap-2 sm:gap-3">
          <LanguageSwitcher />
          <button
            type="button"
            onClick={() => {
              fetchTrip();
              if (driverMain === 'home') loadWallet();
            }}
            disabled={!user.bus_id}
            className="flex min-h-10 items-center gap-2 rounded-lg border border-slate-600 bg-slate-800 px-2.5 py-2 text-sm font-semibold text-white hover:bg-slate-700 disabled:opacity-40 sm:py-1.5"
            title={t('common.refresh')}
            aria-label={t('common.refresh')}
          >
            <RefreshCw className="h-4 w-4 shrink-0" aria-hidden />
            <span className="hidden sm:inline">{t('common.refresh')}</span>
          </button>
          <button
            type="button"
            onClick={() => setDriverShell('support')}
            className="flex min-h-10 items-center gap-2 rounded-lg border border-teal-700 bg-teal-900/40 px-2.5 py-2 text-sm font-semibold text-teal-100 hover:bg-teal-900/70 sm:py-1.5"
          >
            <LifeBuoy className="h-4 w-4 shrink-0" aria-hidden />
            <span className="hidden sm:inline">{t('dashboard.supportNav')}</span>
          </button>
          {showIdeasNav() ? (
            <button
              type="button"
              onClick={() => setDriverShell('features')}
              className="flex min-h-10 items-center gap-2 rounded-lg border border-amber-700 bg-amber-900/35 px-2.5 py-2 text-sm font-semibold text-amber-100 hover:bg-amber-900/60 sm:py-1.5"
            >
              <Lightbulb className="h-4 w-4 shrink-0" aria-hidden />
              <span className="hidden sm:inline">{t('dashboard.featuresNav')}</span>
            </button>
          ) : null}
          <div className="flex min-w-0 max-w-full items-center gap-2 rounded-lg bg-slate-800 px-2 py-1.5 sm:px-3 sm:py-1">
            <Bus className="h-4 w-4 shrink-0 text-blue-400" />
            <span className="truncate font-bold">{user.name}</span>
          </div>
        </div>
        <button type="button" onClick={onLogout} className="min-h-10 shrink-0 rounded-lg px-3 py-2 text-sm text-slate-300 hover:bg-slate-800 hover:text-white">
          {t('driver.logout')}
        </button>
      </header>

      <div className="mx-auto w-full max-w-lg flex-1 overflow-y-auto overscroll-y-contain p-3 pb-24 sm:p-4 sm:pb-28">
        {driverMain === 'home' && (
          <div className="space-y-4">
            <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm">
              <div className="text-xs font-bold uppercase text-slate-500">{t('driver.walletTitle')}</div>
              <div className="mt-1 text-3xl font-black text-slate-900">{Number(wallet?.wallet?.balance_minor ?? 0).toLocaleString()} IQD</div>
            </div>
            <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm space-y-3">
              <div className="text-sm font-bold text-slate-800">{t('driver.withdrawTitle')}</div>
              <input
                type="number"
                className="w-full rounded-lg border p-2"
                placeholder={t('driver.amountIqd')}
                value={wdAmount}
                onChange={(e) => setWdAmount(e.target.value)}
              />
              <input
                type="text"
                className="w-full rounded-lg border p-2 font-mono"
                placeholder="IBAN"
                value={wdIban}
                onChange={(e) => setWdIban(e.target.value)}
              />
              <input
                type="text"
                className="w-full rounded-lg border p-2"
                placeholder={t('driver.holderName')}
                value={wdHolder}
                onChange={(e) => setWdHolder(e.target.value)}
              />
              <button
                type="button"
                className="w-full rounded-lg bg-indigo-600 py-2 font-bold text-white"
                onClick={() =>
                  void api('/api/wallet/me/withdraw', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                      amountMinor: Math.round(Number(wdAmount)),
                      iban: wdIban,
                      holderName: wdHolder,
                    }),
                  })
                    .then(() => {
                      setWdAmount('');
                      setWdIban('');
                      setWdHolder('');
                      loadWallet();
                    })
                    .catch((e) => alert(e instanceof Error ? e.message : 'Error'))
                }
              >
                {t('driver.submitWithdraw')}
              </button>
            </div>
            <div className="text-xs text-slate-500">{t('driver.withdrawStaffHint')}</div>
          </div>
        )}

        {driverMain === 'scope' && (
          <div className="space-y-2">
            <p className="text-sm text-slate-600">{t('driver.scopeIntro')}</p>
            <div className="max-h-[55dvh] space-y-2 overflow-y-auto rounded-xl border border-slate-200 bg-white p-3">
              {allSchools.map((s) => (
                <label key={s.id} className="flex items-center gap-2 text-sm">
                  <input
                    type="checkbox"
                    checked={selectedSchoolIds.has(s.id)}
                    onChange={() => {
                      setSelectedSchoolIds((prev) => {
                        const n = new Set(prev);
                        if (n.has(s.id)) n.delete(s.id);
                        else n.add(s.id);
                        return n;
                      });
                    }}
                  />
                  {s.name}
                </label>
              ))}
            </div>
            <button
              type="button"
              className="w-full rounded-lg bg-slate-900 py-2 font-bold text-white"
              onClick={() =>
                void api('/api/driver/served-schools', {
                  method: 'PUT',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ schoolIds: [...selectedSchoolIds] }),
                })
                  .then(() => loadServed())
                  .catch(() => alert('Save failed'))
              }
            >
              {t('driver.saveScope')}
            </button>
          </div>
        )}

        {driverMain === 'students' && (
          <div className="space-y-2">
            {roster.length === 0 ? (
              <p className="text-slate-500">{t('driver.rosterEmpty')}</p>
            ) : (
              roster.map((s: any) => (
                <div key={s.id} className="rounded-xl border border-slate-200 bg-white p-3 text-sm">
                  <div className="font-bold">{s.name}</div>
                  <div className="text-slate-600">{s.address_city}</div>
                  <div className="mt-2 flex items-center gap-2 text-slate-700">
                    <Phone className="h-4 w-4 shrink-0" />
                    <span>{s.parent_phone || '—'}</span>
                  </div>
                  <div className="text-xs text-slate-500">{s.parent_name}</div>
                </div>
              ))
            )}
          </div>
        )}

        {driverMain === 'notices' && (
          <div className="space-y-4">
            <div className="rounded-xl border border-slate-200 bg-white p-3 space-y-2">
              <div className="text-sm font-bold">{t('driver.newNotice')}</div>
              <select className="w-full rounded border p-2" value={noticeTo} onChange={(e) => setNoticeTo(e.target.value)}>
                <option value="">{t('driver.recipient')}</option>
                {roster.map((s: any) =>
                  s.parent_id ? (
                    <option key={s.id} value={s.parent_id}>
                      {s.parent_name || s.parent_id} ({s.name})
                    </option>
                  ) : null,
                )}
              </select>
              <textarea className="w-full rounded border p-2 text-sm" rows={3} value={noticeBody} onChange={(e) => setNoticeBody(e.target.value)} />
              <button
                type="button"
                className="w-full rounded-lg bg-teal-600 py-2 font-bold text-white"
                onClick={() => {
                  if (!noticeTo || !noticeBody.trim()) return;
                  void api('/api/transport/notices', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ toUserId: noticeTo, body: noticeBody, kind: 'driver_message' }),
                  })
                    .then(() => {
                      setNoticeBody('');
                      loadNotices();
                    })
                    .catch(() => alert('Failed'));
                }}
              >
                {t('driver.sendNotice')}
              </button>
            </div>
            {notices.map((n: any) => (
              <div key={n.id} className="rounded-xl border border-slate-100 bg-white p-3 text-sm">
                <div className="text-xs text-slate-400">{new Date(n.created_at).toLocaleString()}</div>
                <div className="font-bold">{n.from_name}</div>
                <div>{n.body}</div>
                {!n.read_at ? (
                  <button type="button" className="mt-2 text-xs text-indigo-600 underline" onClick={() => void api(`/api/transport/notices/${n.id}/read`, { method: 'PATCH' }).then(() => loadNotices())}>
                    {t('driver.markRead')}
                  </button>
                ) : null}
              </div>
            ))}
          </div>
        )}

        {driverMain === 'requests' && (
          <div className="space-y-3">
            {requests.length === 0 ? (
              <p className="text-slate-500">{t('driver.noRequests')}</p>
            ) : (
              requests.map((r: any) => (
                <div key={r.id} className="rounded-xl border border-slate-200 bg-white p-3 text-sm space-y-2">
                  <div className="font-bold">{r.student_name || r.student_id}</div>
                  <div className="text-slate-600">{r.note}</div>
                  <div className="flex gap-2">
                    <button
                      type="button"
                      className="flex-1 rounded-lg bg-green-600 py-2 font-bold text-white"
                      onClick={() =>
                        void api(`/api/transport/requests/${encodeURIComponent(r.id)}`, {
                          method: 'PATCH',
                          headers: { 'Content-Type': 'application/json' },
                          body: JSON.stringify({ status: 'accepted' }),
                        })
                          .then(() => loadRequests())
                          .catch((e) => alert((e as Error)?.message || 'err'))
                      }
                    >
                      {t('driver.accept')}
                    </button>
                    <button
                      type="button"
                      className="flex-1 rounded-lg border border-slate-300 py-2 font-bold"
                      onClick={() =>
                        void api(`/api/transport/requests/${encodeURIComponent(r.id)}`, {
                          method: 'PATCH',
                          headers: { 'Content-Type': 'application/json' },
                          body: JSON.stringify({ status: 'declined' }),
                        }).then(() => loadRequests())
                      }
                    >
                      {t('driver.decline')}
                    </button>
                  </div>
                </div>
              ))
            )}
          </div>
        )}

        {driverMain === 'run' &&
          (!trip ? (
            <div className="flex flex-1 items-center justify-center p-6 text-center text-base font-bold text-slate-600">{t('driver.loading')}</div>
          ) : (
            <div className="space-y-3">
              {student ? (
                <div className="mb-6 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl">
                  <div className="bg-blue-500 p-4 text-white">
                    <div className="mb-1 text-[0.75rem] font-bold uppercase tracking-wider text-blue-100">{t('driver.nextStop')}</div>
                    <h2 className="text-2xl font-black">{student.name}</h2>
                  </div>
                  <div className="p-4 sm:p-6">
                    <a
                      href={`https://www.google.com/maps/dir/?api=1&destination=${student.address.lat},${student.address.lng}`}
                      target="_blank"
                      rel="noreferrer"
                      className="mb-6 flex min-h-12 items-center justify-center gap-2 rounded-xl border border-slate-200 bg-slate-100 py-3 font-bold text-slate-800 transition hover:bg-slate-200"
                    >
                      <Navigation className="h-5 w-5 text-blue-500" /> {t('driver.navigate')}
                    </a>
                    <div className="grid grid-cols-2 gap-3">
                      <button
                        type="button"
                        onClick={() => handleAction(currentStop.student_id, 'boarded')}
                        className="flex flex-col items-center gap-1 rounded-xl bg-green-500 py-4 font-bold text-white shadow-sm transition hover:bg-green-600"
                      >
                        <CheckCircle className="h-8 w-8" /> {t('driver.onboard')}
                      </button>
                      <button
                        type="button"
                        onClick={() => handleAction(currentStop.student_id, 'no_show')}
                        className="flex flex-col items-center gap-1 rounded-xl bg-orange-500 py-4 font-bold text-white shadow-sm transition hover:bg-orange-600"
                      >
                        <XCircle className="h-8 w-8" /> {t('driver.absent')}
                      </button>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="mb-6 rounded-2xl border border-green-200 bg-green-100 p-6 text-center text-green-800 shadow-sm">
                  <CheckCircle className="mx-auto mb-2 h-12 w-12 text-green-500" />
                  <h2 className="text-xl font-bold">{t('driver.done')}</h2>
                </div>
              )}
              <h3 className="mb-3 px-2 font-bold text-slate-800">
                {t('driver.stops')} ({trip.stops.length})
              </h3>
              <div className="space-y-2 pb-4">
                {trip.stops.map((stop: any, idx: number) => {
                  let bg = 'bg-white';
                  let icon: React.ReactNode = <div className="h-4 w-4 rounded-full border-2 border-slate-300" />;
                  if (stop.status === 'boarded') {
                    bg = 'bg-green-50 opacity-60';
                    icon = <CheckCircle className="h-5 w-5 text-green-500" />;
                  } else if (stop.status === 'no_show') {
                    bg = 'bg-orange-50 opacity-60';
                    icon = <XCircle className="h-5 w-5 text-orange-500" />;
                  } else if (stop.status === 'sick') {
                    bg = 'bg-slate-100 opacity-50';
                    icon = <HeartPulse className="h-5 w-5 text-slate-400" />;
                  } else if (idx === trip.current_stop) {
                    bg = 'border border-blue-200 bg-blue-50';
                    icon = <Bus className="h-5 w-5 text-blue-500" />;
                  }
                  const sn = stop.student?.name ?? '?';
                  return (
                    <div key={stop.student_id} className={`flex items-center gap-3 rounded-xl border border-slate-200 p-4 ${bg}`}>
                      {icon}
                      <div>
                        <div className="text-sm font-bold">{sn}</div>
                        <div className="text-[0.65rem] uppercase text-slate-500">{stop.status === 'sick' ? t('driver.sick') : stop.status}</div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
      </div>

      <div className="fixed bottom-[calc(3.25rem+env(safe-area-inset-bottom))] left-0 right-0 z-30 flex flex-wrap items-center justify-center gap-x-3 gap-y-0.5 border-t border-slate-100 bg-white/95 px-2 py-1 text-[10px] text-slate-500">
        <a href="/privacy" target="_blank" rel="noopener noreferrer" className="hover:text-blue-600 hover:underline">
          {t('legal.privacyPolicy')}
        </a>
        <span aria-hidden>·</span>
        <a href="/account-deletion" target="_blank" rel="noopener noreferrer" className="hover:text-blue-600 hover:underline">
          {t('legal.accountDeletion')}
        </a>
        <span aria-hidden>·</span>
        <button type="button" className="text-red-600 hover:underline" onClick={() => void requestDeleteMyAccount(t, onLogout)}>
          {t('legal.deleteAccount')}
        </button>
      </div>

      <nav className="fixed bottom-0 left-0 right-0 z-40 grid grid-cols-6 border-t border-slate-200 bg-white pb-[max(0.25rem,env(safe-area-inset-bottom))] shadow-[0_-4px_12px_rgba(0,0,0,0.06)]">
        <button type="button" className={tabClass('home')} onClick={() => setDriverMain('home')}>
          <Home className="mx-auto h-5 w-5" />
          <span>{t('driver.tabHome')}</span>
        </button>
        <button type="button" className={tabClass('scope')} onClick={() => setDriverMain('scope')}>
          <MapPin className="mx-auto h-5 w-5" />
          <span>{t('driver.tabScope')}</span>
        </button>
        <button type="button" className={tabClass('students')} onClick={() => setDriverMain('students')}>
          <Users className="mx-auto h-5 w-5" />
          <span>{t('driver.tabStudents')}</span>
        </button>
        <button type="button" className={tabClass('notices')} onClick={() => setDriverMain('notices')}>
          <Inbox className="mx-auto h-5 w-5" />
          <span>{t('driver.tabNotices')}</span>
        </button>
        <button type="button" className={tabClass('requests')} onClick={() => setDriverMain('requests')}>
          <ListOrdered className="mx-auto h-5 w-5" />
          <span>{t('driver.tabRequests')}</span>
        </button>
        <button type="button" className={tabClass('run')} onClick={() => setDriverMain('run')}>
          <Bus className="mx-auto h-5 w-5" />
          <span>{t('driver.tabRun')}</span>
        </button>
      </nav>
    </div>
  );
}

/** First existing child's pickup (same parent) — default for new enrollment map / address. */
function firstExistingChildPickup(
  studentsList: any[],
  parentId: string,
): { lat: number; lng: number; line1: string; city: string } {
  const defLat = 33.312805;
  const defLng = 44.361488;
  for (const s of studentsList) {
    if (String(s.parent_id) !== parentId) continue;
    const lat = Number(s.lat ?? (s.address as { lat?: number } | undefined)?.lat);
    const lng = Number(s.lng ?? (s.address as { lng?: number } | undefined)?.lng);
    if (Number.isFinite(lat) && Number.isFinite(lng) && !(lat === 0 && lng === 0)) {
      const addr = s.address as { line1?: string; city?: string } | undefined;
      const line1 = String(s.address_line1 ?? addr?.line1 ?? '').trim();
      const city = String(s.address_city ?? addr?.city ?? '').trim();
      return { lat, lng, line1, city };
    }
  }
  return { lat: defLat, lng: defLng, line1: '', city: '' };
}

function PickupMapClickLayer({ onPick }: { onPick: (lat: number, lng: number) => void }) {
  useMapEvents({
    click(e) {
      onPick(e.latlng.lat, e.latlng.lng);
    },
  });
  return null;
}

function PickupMapFlyTo({ lat, lng, seq }: { lat: number; lng: number; seq: number }) {
  const map = useMap();
  const target = useRef({ lat, lng });
  target.current = { lat, lng };
  useEffect(() => {
    if (seq <= 0) return;
    const { lat: la, lng: ln } = target.current;
    map.flyTo([la, ln], Math.max(map.getZoom(), 15), { duration: 0.6 });
  }, [seq, map]);
  return null;
}

function PickupLocationMapModal({
  t,
  open,
  initialLat,
  initialLng,
  onClose,
  onConfirm,
}: {
  t: TFunction;
  open: boolean;
  initialLat: number;
  initialLng: number;
  onClose: () => void;
  onConfirm: (lat: number, lng: number, line1: string, city: string) => void;
}) {
  const [lat, setLat] = useState(initialLat);
  const [lng, setLng] = useState(initialLng);
  const [flySeq, setFlySeq] = useState(0);
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    if (open) {
      setLat(initialLat);
      setLng(initialLng);
      setFlySeq(0);
    }
  }, [open, initialLat, initialLng]);

  const goMyLocation = () => {
    if (!navigator.geolocation) {
      alert(t('students.geoNotSupported'));
      return;
    }
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        setLat(pos.coords.latitude);
        setLng(pos.coords.longitude);
        setFlySeq((n) => n + 1);
      },
      () => alert(t('students.geoDenied')),
      { enableHighAccuracy: true, maximumAge: 30_000, timeout: 12_000 },
    );
  };

  const confirmPick = async () => {
    setBusy(true);
    try {
      const r = await api(
        `/api/geocode/reverse?lat=${encodeURIComponent(String(lat))}&lng=${encodeURIComponent(String(lng))}`,
      );
      const j = (await readJsonLoose(r)) as { address_line1?: string; address_city?: string };
      if (!r.ok) {
        onConfirm(lat, lng, t('students.pickupPinFallback'), 'Iraq');
        return;
      }
      const line1 = typeof j.address_line1 === 'string' && j.address_line1.trim() ? j.address_line1.trim() : t('students.pickupPinFallback');
      const city = typeof j.address_city === 'string' && j.address_city.trim() ? j.address_city.trim() : 'Iraq';
      onConfirm(lat, lng, line1, city);
    } catch {
      onConfirm(lat, lng, t('students.pickupPinFallback'), 'Iraq');
    } finally {
      setBusy(false);
    }
  };

  if (!open) return null;

  return (
    <div
      className="fixed inset-0 z-[1001] flex items-end justify-center bg-slate-900/50 p-0 sm:items-center sm:p-4"
      role="dialog"
      aria-modal
      aria-label={t('students.pickupMapTitle')}
    >
      <div className="flex max-h-[min(92dvh,560px)] w-full max-w-lg flex-col overflow-hidden rounded-t-2xl bg-white shadow-xl sm:rounded-2xl">
        <div className="flex items-center justify-between border-b border-slate-100 px-4 py-3">
          <h4 className="text-base font-bold">{t('students.pickupMapTitle')}</h4>
          <button type="button" className="rounded p-2 text-slate-500 hover:bg-slate-100" onClick={onClose} aria-label={t('dashboard.closeMenu')}>
            <X className="h-5 w-5" />
          </button>
        </div>
        <p className="px-4 py-2 text-xs text-slate-600">{t('students.pickupMapHint')}</p>
        <div className="relative h-56 w-full shrink-0 border-y border-slate-200 sm:h-64">
          <MapContainer center={[lat, lng]} zoom={15} scrollWheelZoom className="h-full w-full" style={{ zIndex: 0 }}>
            <TileLayer url="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png" />
            <PickupMapFlyTo lat={lat} lng={lng} seq={flySeq} />
            <PickupMapClickLayer onPick={(la, ln) => { setLat(la); setLng(ln); }} />
            <Marker
              position={[lat, lng]}
              draggable
              eventHandlers={{
                dragend: (e) => {
                  const p = e.target.getLatLng();
                  setLat(p.lat);
                  setLng(p.lng);
                },
              }}
            />
          </MapContainer>
          <button
            type="button"
            onClick={() => goMyLocation()}
            className="absolute end-3 top-3 z-[500] flex h-11 w-11 items-center justify-center rounded-full border border-slate-200 bg-white shadow-md hover:bg-slate-50"
            title={t('students.myLocation')}
            aria-label={t('students.myLocation')}
          >
            <Navigation className="h-5 w-5 text-blue-600" />
          </button>
        </div>
        <div className="flex flex-wrap gap-2 p-4 pb-[max(0.75rem,env(safe-area-inset-bottom))]">
          <button type="button" onClick={onClose} className="min-h-11 flex-1 rounded-lg bg-slate-100 px-3 py-2 text-sm font-semibold">
            {t('common.cancel')}
          </button>
          <button
            type="button"
            disabled={busy}
            onClick={() => void confirmPick()}
            className="min-h-11 flex-1 rounded-lg bg-blue-600 px-3 py-2 text-sm font-semibold text-white disabled:opacity-60"
          >
            {busy ? t('common.loading') : t('students.confirmPickupLocation')}
          </button>
        </div>
      </div>
    </div>
  );
}

function StudentManagement({
  user,
  students,
  schools,
  onRefresh,
}: {
  user: User;
  students: any[];
  schools: School[];
  onRefresh: () => void;
}) {
  const { t } = useTranslation();
  const [showAddModal, setShowAddModal] = useState(false);
  const [newStudent, setNewStudent] = useState({
    name: '',
    school_id: schools[0]?.id || '',
    lat: 33.312805,
    lng: 44.361488,
    address_line1: '',
    address_city: '',
    child_email: '',
    child_password: '',
  });
  const [schoolSearch, setSchoolSearch] = useState('');
  const [pickupMapOpen, setPickupMapOpen] = useState(false);
  const [pickupMapContext, setPickupMapContext] = useState<'enroll' | 'edit' | 'staff'>('enroll');
  const [editStudent, setEditStudent] = useState<Record<string, unknown> | null>(null);
  const [editSt, setEditSt] = useState({
    name: '',
    lat: 33.312805,
    lng: 44.361488,
    address_line1: '',
    address_city: '',
    class_id: '',
  });
  const [editClassOptions, setEditClassOptions] = useState<Array<{ id: string; name: string }>>([]);

  const [staffAddOpen, setStaffAddOpen] = useState(false);
  const [staffParentMode, setStaffParentMode] = useState<'new' | 'existing'>('new');
  const [staffForm, setStaffForm] = useState({
    name: '',
    lat: 33.312805,
    lng: 44.361488,
    address_line1: '',
    address_city: '',
    parent_id: '',
    parent_name: '',
    parent_email: '',
    parent_phone: '',
    parent_password: '',
    class_id: '',
    child_email: '',
    child_password: '',
    status: 'active' as 'active' | 'pending_approval',
  });
  const [staffParents, setStaffParents] = useState<Array<{ id: string; name?: string; email?: string }>>([]);
  const [staffClasses, setStaffClasses] = useState<Array<{ id: string; name: string }>>([]);

  const staffSchoolId = useMemo(() => {
    if (user.school_id != null && String(user.school_id) !== '') return String(user.school_id);
    return schools[0]?.id || '';
  }, [user.school_id, schools]);

  const filteredSchoolsForEnroll = useMemo(() => {
    const q = schoolSearch.trim().toLowerCase();
    return compact(schools).filter((sc) => !q || sc.name.toLowerCase().includes(q));
  }, [schools, schoolSearch]);

  const coordsOk = (lat: unknown, lng: unknown) =>
    Number.isFinite(Number(lat)) && Number.isFinite(Number(lng)) && !(Number(lat) === 0 && Number(lng) === 0);

  const loadStaffParentsClasses = async (sid: string) => {
    const [pr, cr] = await Promise.all([
      api(`/api/schools/${encodeURIComponent(sid)}/parents`),
      api(`/api/schools/${encodeURIComponent(sid)}/classes`),
    ]);
    const pj = (await readJsonLoose(pr)) as Array<{ id: string; name?: string; email?: string }>;
    const cj = (await readJsonLoose(cr)) as Array<{ id: string; name: string }>;
    if (pr.ok) setStaffParents(Array.isArray(pj) ? pj : []);
    else setStaffParents([]);
    if (cr.ok) setStaffClasses(Array.isArray(cj) ? cj : []);
    else setStaffClasses([]);
  };

  const openStaffEnrollModal = () => {
    if (!staffSchoolId) {
      alert(t('students.staffEnrollNoSchool'));
      return;
    }
    setStaffParentMode('new');
    setStaffForm({
      name: '',
      lat: 33.312805,
      lng: 44.361488,
      address_line1: '',
      address_city: '',
      parent_id: '',
      parent_name: '',
      parent_email: '',
      parent_phone: '',
      parent_password: '',
      class_id: '',
      child_email: '',
      child_password: '',
      status: 'active',
    });
    void loadStaffParentsClasses(staffSchoolId);
    setStaffAddOpen(true);
  };

  const handleStaffAdd = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!staffSchoolId) return;
    if (!staffForm.name.trim()) {
      alert(t('students.childName'));
      return;
    }
    if (!coordsOk(staffForm.lat, staffForm.lng)) {
      alert(t('students.pickupRequired'));
      return;
    }
    const body: Record<string, unknown> = {
      name: staffForm.name.trim(),
      school_id: staffSchoolId,
      lat: staffForm.lat,
      lng: staffForm.lng,
      address_line1: staffForm.address_line1.trim() || null,
      address_city: staffForm.address_city.trim() || null,
      status: staffForm.status,
    };
    if (staffForm.class_id.trim()) body.class_id = staffForm.class_id.trim();
    if (staffParentMode === 'existing') {
      if (!staffForm.parent_id.trim()) {
        alert(t('students.parentRequired'));
        return;
      }
      body.parent_id = staffForm.parent_id.trim();
    } else {
      if (!staffForm.parent_name.trim() || !staffForm.parent_email.trim()) {
        alert(t('students.parentNewRequired'));
        return;
      }
      if (staffForm.parent_password.length > 0 && staffForm.parent_password.length < 8) {
        alert(t('students.parentPasswordShort'));
        return;
      }
      if (!staffForm.parent_password.trim() && !staffForm.parent_phone.trim()) {
        alert(t('students.parentPhoneOrPassword'));
        return;
      }
      body.parent_name = staffForm.parent_name.trim();
      body.parent_email = staffForm.parent_email.trim();
      if (staffForm.parent_phone.trim()) body.parent_phone = staffForm.parent_phone.trim();
      if (staffForm.parent_password.trim()) body.parent_password = staffForm.parent_password;
    }
    const ce = staffForm.child_email.trim();
    if (ce && staffForm.child_password.length < 8) {
      alert(t('students.childPasswordRequired'));
      return;
    }
    if (ce) {
      body.child_email = ce;
      body.child_password = staffForm.child_password;
    }
    try {
      await apiJson('/api/students', body, { method: 'POST' });
      setStaffAddOpen(false);
      onRefresh();
    } catch (err) {
      alert(err instanceof ApiError ? err.message : err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const openEnrollModal = () => {
    const ex = firstExistingChildPickup(compact(students), user.id);
    const firstId = schools[0]?.id || '';
    setNewStudent({
      name: '',
      school_id: firstId,
      lat: ex.lat,
      lng: ex.lng,
      address_line1: ex.line1,
      address_city: ex.city,
      child_email: '',
      child_password: '',
    });
    const sn = firstId ? compact(schools).find((s) => s.id === firstId)?.name || '' : '';
    setSchoolSearch(sn);
    setShowAddModal(true);
  };

  const openStudentEdit = (s: Record<string, unknown>) => {
    setEditStudent(s);
    setEditSt({
      name: String(s.name ?? ''),
      lat: Number(s.lat ?? (s.address as { lat?: number } | undefined)?.lat ?? 33.312805),
      lng: Number(s.lng ?? (s.address as { lng?: number } | undefined)?.lng ?? 44.361488),
      address_line1: String(s.address_line1 ?? (s.address as { line1?: string } | undefined)?.line1 ?? ''),
      address_city: String(s.address_city ?? (s.address as { city?: string } | undefined)?.city ?? ''),
      class_id: String(s.class_id ?? '').trim(),
    });
    const sid = String(s.school_id ?? '').trim();
    if (sid && (isSchoolStaffRole(user.role) || userHas(user, 'map_global_view'))) {
      void api(`/api/schools/${encodeURIComponent(sid)}/classes`).then(async (r) => {
        const j = (await readJsonLoose(r)) as Array<{ id: string; name: string }>;
        if (r.ok) setEditClassOptions(Array.isArray(j) ? j : []);
        else setEditClassOptions([]);
      });
    } else {
      setEditClassOptions([]);
    }
  };

  const saveStudentEdit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!editStudent) return;
    try {
      const payload: Record<string, unknown> = {
        name: editSt.name.trim(),
        lat: editSt.lat,
        lng: editSt.lng,
        address_line1: editSt.address_line1.trim(),
        address_city: editSt.address_city.trim(),
      };
      if (isSchoolStaffRole(user.role) || userHas(user, 'map_global_view')) {
        payload.class_id = editSt.class_id.trim() || null;
      }
      await apiJson(`/api/students/${editStudent.id}`, payload, { method: 'PUT' });
      setEditStudent(null);
      onRefresh();
    } catch (err) {
      alert(err instanceof ApiError ? err.message : err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const handleUpdateStatus = async (id: string, status: string) => {
    await api('/api/students/' + encodeURIComponent(id), {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ status }),
    });
    onRefresh();
  };
  const handleTransfer = async (id: string, school_id: string) => {
    await api('/api/students/' + encodeURIComponent(id), {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ school_id, status: 'pending_transfer' }),
    });
    onRefresh();
  };
  const handleSick = async (studentId: string) => {
    await api('/api/student/sick', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ studentId }),
    });
    alert(t('students.sickOk'));
    onRefresh();
  };

  const handleAdd = async (e: React.FormEvent) => {
    e.preventDefault();
    const emailT = newStudent.child_email.trim();
    if (emailT && newStudent.child_password.length < 8) {
      alert(t('students.childPasswordRequired'));
      return;
    }
    if (!coordsOk(newStudent.lat, newStudent.lng)) {
      alert(t('students.pickupRequired'));
      return;
    }
    if (!compact(schools).some((sc) => sc.id === newStudent.school_id)) {
      alert(t('students.schoolRequired'));
      return;
    }
    try {
      await apiJson('/api/students', {
        name: newStudent.name.trim(),
        school_id: newStudent.school_id,
        lat: newStudent.lat,
        lng: newStudent.lng,
        address_line1: newStudent.address_line1.trim() || null,
        address_city: newStudent.address_city.trim() || null,
        ...(emailT ? { child_email: emailT, child_password: newStudent.child_password } : {}),
      }, { method: 'POST' });
      setShowAddModal(false);
      const ex = firstExistingChildPickup(compact(students), user.id);
      const firstId = schools[0]?.id || '';
      setNewStudent({
        name: '',
        school_id: firstId,
        lat: ex.lat,
        lng: ex.lng,
        address_line1: ex.line1,
        address_city: ex.city,
        child_email: '',
        child_password: '',
      });
      setSchoolSearch(firstId ? compact(schools).find((s) => s.id === firstId)?.name || '' : '');
      onRefresh();
    } catch (err) {
      alert(err instanceof ApiError ? err.message : err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  return (
    <div className="relative flex-1 overflow-y-auto overscroll-y-contain p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4 md:p-6">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3 sm:mb-6">
        <h2 className="text-lg font-bold sm:text-xl">{t('students.title')}</h2>
        <div className="flex flex-wrap items-center gap-2">
          <button
            type="button"
            onClick={() => onRefresh()}
            className="flex min-h-10 items-center gap-2 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50"
            title={t('common.refresh')}
            aria-label={t('common.refresh')}
          >
            <RefreshCw className="h-4 w-4 shrink-0" aria-hidden />
            <span className="hidden sm:inline">{t('common.refresh')}</span>
          </button>
          {userHas(user, 'students_enroll_own') && isParentRole(user.role) && (
            <button
              type="button"
              onClick={() => openEnrollModal()}
              className="flex min-h-10 items-center gap-2 rounded-lg bg-blue-500 px-3 py-2 text-sm text-white"
              aria-label={t('students.enroll')}
            >
              <PlusCircle className="h-4 w-4 shrink-0" />
              <span className="hidden sm:inline">{t('students.enroll')}</span>
            </button>
          )}
          {userHas(user, 'students_enroll_school') && isSchoolStaffRole(user.role) && (
            <button
              type="button"
              onClick={() => openStaffEnrollModal()}
              className="flex min-h-10 items-center gap-2 rounded-lg bg-indigo-600 px-3 py-2 text-sm text-white"
            >
              <PlusCircle className="h-4 w-4 shrink-0" />
              <span className="hidden sm:inline">{t('students.staffAddStudent')}</span>
            </button>
          )}
        </div>
      </div>
      <div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
        <div className="-mx-px overflow-x-auto overscroll-x-contain">
        <table className="w-full min-w-[480px] text-left text-sm">
          <thead className="border-b border-slate-200 bg-slate-50">
            <tr>
              <th className="p-2 text-xs font-bold uppercase tracking-wide text-slate-500 sm:p-4 sm:normal-case sm:tracking-normal">{t('students.name')}</th>
              <th className="hidden p-2 text-xs font-bold uppercase text-slate-500 lg:table-cell lg:p-4 lg:normal-case">{t('students.address')}</th>
              <th className="hidden p-2 text-xs font-bold uppercase text-slate-500 sm:table-cell sm:p-4 sm:normal-case">{t('students.school')}</th>
              <th className="hidden p-2 text-xs font-bold uppercase text-slate-500 md:table-cell md:p-4 md:normal-case">{t('students.classLabel')}</th>
              <th className="p-2 text-xs font-bold uppercase text-slate-500 sm:p-4 sm:normal-case">{t('students.status')}</th>
              <th className="p-2 text-xs font-bold uppercase text-slate-500 sm:p-4 sm:normal-case">{t('students.actions')}</th>
            </tr>
          </thead>
          <tbody>
            {compact(students).map((s) => {
              const school = schools.find((sch) => sch.id === s.school_id);
              const addr = s.address as { line1?: string; city?: string; lat?: number; lng?: number } | undefined;
              const line1 = String(s.address_line1 ?? addr?.line1 ?? '');
              const city = String(s.address_city ?? addr?.city ?? '');
              const ok = coordsOk(s.lat, s.lng);
              const canEdit =
                (userHas(user, 'students_update') &&
                  (userHas(user, 'map_global_view') ||
                    (isSchoolStaffRole(user.role) &&
                      (!user.school_id || String(user.school_id) === '' || String(s.school_id) === String(user.school_id))))) ||
                (isParentRole(user.role) && s.parent_id === user.id) ||
                (isStudentRole(user.role) && s.child_login_user_id === user.id);
              return (
                <tr key={s.id} className="border-b border-slate-100 hover:bg-slate-50">
                  <td className="p-2 align-top font-semibold sm:p-4">
                    <div className="flex flex-wrap items-center gap-2">
                      <span className="max-w-[11rem] truncate sm:max-w-none">{s.name}</span>
                      {!ok ? (
                        <span className="rounded bg-red-100 px-1.5 py-0.5 text-[10px] font-bold uppercase text-red-800">
                          {t('students.missingCoords')}
                        </span>
                      ) : null}
                    </div>
                    <div className="mt-0.5 text-[11px] text-slate-500 sm:hidden">{school?.name}</div>
                  </td>
                  <td className="hidden max-w-[14rem] p-2 text-xs text-slate-600 lg:table-cell lg:p-4">
                    <div className="truncate">{line1 || '—'}</div>
                    <div className="truncate text-slate-500">{city || '—'}</div>
                  </td>
                  <td className="hidden p-2 sm:table-cell sm:p-4">{school?.name}</td>
                  <td className="hidden max-w-[8rem] truncate p-2 text-xs text-slate-600 md:table-cell md:p-4">
                    {String((s as { class_name?: unknown }).class_name ?? '') || '—'}
                  </td>
                  <td className="p-2 sm:p-4">
                    {s.status === 'active' ? (
                      <span className="text-green-600 bg-green-50 px-2 rounded font-bold">{t('students.active')}</span>
                    ) : (
                      <span className="text-orange-600 bg-orange-50 px-2 rounded font-bold">{t('students.pending')}</span>
                    )}
                  </td>
                  <td className="p-2 sm:p-4">
                    <div className="flex max-w-[10rem] flex-col flex-wrap gap-2 sm:max-w-none sm:flex-row sm:items-center">
                      {canEdit && (
                        <button
                          type="button"
                          onClick={() => openStudentEdit(s as Record<string, unknown>)}
                          className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded border border-slate-200 bg-white text-slate-700 hover:bg-slate-50"
                          title={t('students.edit')}
                          aria-label={t('students.edit')}
                        >
                          <Pencil className="h-4 w-4" />
                        </button>
                      )}
                      {(userHas(user, 'students_approve') &&
                        ((isSchoolStaffRole(user.role) &&
                          (!user.school_id || String(user.school_id) === '' || String(s.school_id) === String(user.school_id))) ||
                          userHas(user, 'map_global_view'))) &&
                        s.status !== 'active' && (
                        <button
                          type="button"
                          onClick={() => handleUpdateStatus(s.id, 'active')}
                          className="flex h-9 w-9 shrink-0 items-center justify-center rounded bg-green-100 text-green-700"
                          aria-label={t('students.active')}
                        >
                          <Check className="h-4 w-4" />
                        </button>
                      )}
                      {userHas(user, 'students_reassign_school') && (
                        <select
                          onChange={(e) => e.target.value && handleTransfer(s.id, e.target.value)}
                          value={s.school_id}
                          className="max-w-full rounded border px-1 py-2 text-xs sm:max-w-[180px]"
                        >
                          <option value="">{t('students.transfer')}</option>
                          {compact(schools).map((sch) => (
                            <option key={sch.id} value={sch.id}>
                              {sch.name}
                            </option>
                          ))}
                        </select>
                      )}
                      {isParentRole(user.role) && (
                        <button
                          type="button"
                          onClick={() => void handleSick(s.id)}
                          className="min-h-9 rounded border border-amber-200 bg-amber-100 px-2 py-2 text-xs text-amber-900"
                        >
                          {t('students.sick')}
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        </div>
      </div>
      {staffAddOpen && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,720px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-xl sm:rounded-2xl sm:p-6">
            <h3 className="mb-2 text-lg font-bold">{t('students.staffEnrollTitle')}</h3>
            <p className="mb-4 text-xs text-slate-500">{t('students.staffEnrollHint', { school: schools.find((x) => x.id === staffSchoolId)?.name || staffSchoolId })}</p>
            <form onSubmit={(e) => void handleStaffAdd(e)} className="space-y-3">
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.childName')}</label>
                <input
                  required
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  value={staffForm.name}
                  onChange={(e) => setStaffForm({ ...staffForm, name: e.target.value })}
                />
              </div>
              <div className="rounded-lg border border-slate-100 bg-slate-50/90 p-3 space-y-2">
                <div className="text-xs font-bold text-slate-600">{t('students.parentSection')}</div>
                <div className="flex gap-2">
                  <button
                    type="button"
                    className={`rounded px-2 py-1 text-xs font-semibold ${staffParentMode === 'new' ? 'bg-indigo-600 text-white' : 'bg-white border'}`}
                    onClick={() => setStaffParentMode('new')}
                  >
                    {t('students.parentNew')}
                  </button>
                  <button
                    type="button"
                    className={`rounded px-2 py-1 text-xs font-semibold ${staffParentMode === 'existing' ? 'bg-indigo-600 text-white' : 'bg-white border'}`}
                    onClick={() => setStaffParentMode('existing')}
                  >
                    {t('students.parentExisting')}
                  </button>
                </div>
                {staffParentMode === 'existing' ? (
                  <select
                    required
                    className="min-h-11 w-full rounded border p-2 text-sm"
                    value={staffForm.parent_id}
                    onChange={(e) => setStaffForm({ ...staffForm, parent_id: e.target.value })}
                  >
                    <option value="">{t('students.pickParent')}</option>
                    {staffParents.map((p) => (
                      <option key={p.id} value={p.id}>
                        {(p.name || '—') + (p.email ? ` · ${p.email}` : '')}
                      </option>
                    ))}
                  </select>
                ) : (
                  <div className="space-y-2">
                    <input
                      className="min-h-10 w-full rounded border p-2 text-sm"
                      placeholder={t('students.parentNameField')}
                      value={staffForm.parent_name}
                      onChange={(e) => setStaffForm({ ...staffForm, parent_name: e.target.value })}
                    />
                    <input
                      type="email"
                      className="min-h-10 w-full rounded border p-2 text-sm"
                      placeholder={t('users.email')}
                      value={staffForm.parent_email}
                      onChange={(e) => setStaffForm({ ...staffForm, parent_email: e.target.value })}
                    />
                    <input
                      type="tel"
                      className="min-h-10 w-full rounded border p-2 text-sm"
                      placeholder={t('students.parentPhoneField')}
                      value={staffForm.parent_phone}
                      onChange={(e) => setStaffForm({ ...staffForm, parent_phone: e.target.value })}
                    />
                    <p className="text-[11px] text-slate-500">{t('students.parentPhoneOrPassword')}</p>
                    <input
                      type="password"
                      minLength={8}
                      className="min-h-10 w-full rounded border p-2 text-sm"
                      placeholder={t('users.passwordOptional')}
                      value={staffForm.parent_password}
                      onChange={(e) => setStaffForm({ ...staffForm, parent_password: e.target.value })}
                    />
                  </div>
                )}
              </div>
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.pickupLocation')}</label>
                <button
                  type="button"
                  onClick={() => {
                    setPickupMapContext('staff');
                    setPickupMapOpen(true);
                  }}
                  className="flex min-h-11 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white px-3 py-2 text-sm font-semibold text-slate-800 hover:bg-slate-50"
                >
                  <MapPin className="h-4 w-4 shrink-0 text-blue-600" aria-hidden />
                  {t('students.openPickupMap')}
                </button>
              </div>
              {staffClasses.length > 0 ? (
                <div>
                  <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.classLabel')}</label>
                  <select
                    className="min-h-11 w-full rounded border p-2 text-sm"
                    value={staffForm.class_id}
                    onChange={(e) => setStaffForm({ ...staffForm, class_id: e.target.value })}
                  >
                    <option value="">{t('students.classNone')}</option>
                    {staffClasses.map((c) => (
                      <option key={c.id} value={c.id}>
                        {c.name}
                      </option>
                    ))}
                  </select>
                </div>
              ) : null}
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.staffInitialStatus')}</label>
                <select
                  className="min-h-11 w-full rounded border p-2 text-sm"
                  value={staffForm.status}
                  onChange={(e) =>
                    setStaffForm({
                      ...staffForm,
                      status: e.target.value === 'pending_approval' ? 'pending_approval' : 'active',
                    })
                  }
                >
                  <option value="active">{t('students.active')}</option>
                  <option value="pending_approval">{t('students.pending')}</option>
                </select>
              </div>
              <div className="rounded-lg border border-slate-200 bg-slate-50/80 p-3 space-y-2">
                <p className="text-xs font-semibold text-slate-700">{t('students.childLoginOptional')}</p>
                <input
                  type="email"
                  className="min-h-10 w-full rounded border bg-white p-2 text-sm"
                  placeholder={t('users.email')}
                  value={staffForm.child_email}
                  onChange={(e) => setStaffForm({ ...staffForm, child_email: e.target.value })}
                />
                <input
                  type="password"
                  minLength={8}
                  className="min-h-10 w-full rounded border bg-white p-2 text-sm"
                  placeholder={t('students.childPasswordPlaceholder')}
                  value={staffForm.child_password}
                  onChange={(e) => setStaffForm({ ...staffForm, child_password: e.target.value })}
                />
              </div>
              <div className="flex gap-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" className="min-h-11 flex-1 rounded bg-slate-100 p-3" onClick={() => setStaffAddOpen(false)}>
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-indigo-600 p-3 text-white">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}
      {showAddModal && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,720px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-xl sm:rounded-2xl sm:p-6">
            <h3 className="mb-4 text-lg font-bold">{t('students.enrollTitle')}</h3>
            <form onSubmit={(e) => void handleAdd(e)} className="space-y-4">
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.childName')}</label>
                <input
                  required
                  type="text"
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('students.childName')}
                  value={newStudent.name}
                  onChange={(e) => setNewStudent({ ...newStudent, name: e.target.value })}
                />
              </div>
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.school')}</label>
                <input
                  type="search"
                  autoComplete="off"
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('students.schoolSearchPlaceholder')}
                  value={schoolSearch}
                  onChange={(e) => {
                    const v = e.target.value;
                    setSchoolSearch(v);
                    const exact = compact(schools).find((sc) => sc.name.toLowerCase() === v.trim().toLowerCase());
                    if (exact) setNewStudent((prev) => ({ ...prev, school_id: exact.id }));
                  }}
                />
                <ul className="mt-1 max-h-36 overflow-y-auto overscroll-y-contain rounded border border-slate-200 bg-slate-50/80 text-sm">
                  {filteredSchoolsForEnroll.length === 0 ? (
                    <li className="px-3 py-2 text-slate-500">{t('students.schoolNoMatch')}</li>
                  ) : (
                    filteredSchoolsForEnroll.map((sc) => (
                      <li key={sc.id}>
                        <button
                          type="button"
                          className={`w-full px-3 py-2 text-start hover:bg-white ${newStudent.school_id === sc.id ? 'bg-blue-50 font-semibold text-blue-800' : ''}`}
                          onClick={() => {
                            setNewStudent((prev) => ({ ...prev, school_id: sc.id }));
                            setSchoolSearch(sc.name);
                          }}
                        >
                          {sc.name}
                        </button>
                      </li>
                    ))
                  )}
                </ul>
              </div>
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.pickupLocation')}</label>
                <button
                  type="button"
                  onClick={() => {
                    setPickupMapContext('enroll');
                    setPickupMapOpen(true);
                  }}
                  className="flex min-h-11 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white px-3 py-2 text-sm font-semibold text-slate-800 hover:bg-slate-50"
                >
                  <MapPin className="h-4 w-4 shrink-0 text-blue-600" aria-hidden />
                  {t('students.openPickupMap')}
                </button>
                {(newStudent.address_line1 || newStudent.address_city) && coordsOk(newStudent.lat, newStudent.lng) ? (
                  <p className="mt-2 rounded-lg bg-slate-50 px-3 py-2 text-xs text-slate-700">
                    <span className="font-semibold text-slate-800">{t('students.pickupSummary')}:</span>{' '}
                    {newStudent.address_line1 || t('students.pickupPinFallback')}
                    {newStudent.address_city ? ` · ${newStudent.address_city}` : ''}
                  </p>
                ) : (
                  <p className="mt-1 text-xs text-amber-700">{t('students.pickupNotChosenYet')}</p>
                )}
              </div>
              <div className="rounded-lg border border-slate-200 bg-slate-50/80 p-3 space-y-2">
                <p className="text-xs font-semibold text-slate-700">{t('students.childLoginOptional')}</p>
                <p className="text-[11px] text-slate-500">{t('students.childLoginHint')}</p>
                <input
                  type="email"
                  autoComplete="off"
                  className="min-h-11 w-full rounded border bg-white p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('users.email')}
                  value={newStudent.child_email}
                  onChange={(e) => setNewStudent({ ...newStudent, child_email: e.target.value })}
                />
                <input
                  type="password"
                  minLength={8}
                  autoComplete="new-password"
                  className="min-h-11 w-full rounded border bg-white p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('students.childPasswordPlaceholder')}
                  value={newStudent.child_password}
                  onChange={(e) => setNewStudent({ ...newStudent, child_password: e.target.value })}
                />
              </div>
              <div className="flex gap-3 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" onClick={() => setShowAddModal(false)} className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2">
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-500 p-3 text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}
      {editStudent && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,720px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-xl sm:rounded-2xl sm:p-6">
            <h3 className="mb-4 text-lg font-bold">{t('students.editTitle')}</h3>
            <form onSubmit={(e) => void saveStudentEdit(e)} className="space-y-3">
              <input
                required
                type="text"
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                value={editSt.name}
                onChange={(e) => setEditSt({ ...editSt, name: e.target.value })}
              />
              {(isSchoolStaffRole(user.role) || userHas(user, 'map_global_view')) && editClassOptions.length > 0 ? (
                <div>
                  <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.classLabel')}</label>
                  <select
                    className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                    value={editSt.class_id}
                    onChange={(e) => setEditSt({ ...editSt, class_id: e.target.value })}
                  >
                    <option value="">{t('students.classNone')}</option>
                    {editClassOptions.map((c) => (
                      <option key={c.id} value={c.id}>
                        {c.name}
                      </option>
                    ))}
                  </select>
                </div>
              ) : null}
              <div>
                <label className="mb-1 block text-xs font-semibold text-slate-600">{t('students.pickupLocation')}</label>
                <button
                  type="button"
                  onClick={() => {
                    setPickupMapContext('edit');
                    setPickupMapOpen(true);
                  }}
                  className="flex min-h-11 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white px-3 py-2 text-sm font-semibold text-slate-800 hover:bg-slate-50"
                >
                  <MapPin className="h-4 w-4 shrink-0 text-blue-600" aria-hidden />
                  {t('students.openPickupMap')}
                </button>
                {coordsOk(editSt.lat, editSt.lng) ? (
                  <p className="mt-2 rounded-lg bg-slate-50 px-3 py-2 text-xs text-slate-700">
                    <span className="font-semibold text-slate-800">{t('students.pickupSummary')}:</span>{' '}
                    {editSt.address_line1 || t('students.pickupPinFallback')}
                    {editSt.address_city ? ` · ${editSt.address_city}` : ''}
                  </p>
                ) : (
                  <p className="mt-1 text-xs text-amber-700">{t('students.pickupNotChosenYet')}</p>
                )}
              </div>
              <div className="flex gap-2 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2" onClick={() => setEditStudent(null)}>
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-600 p-3 text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}
      <PickupLocationMapModal
        t={t}
        open={pickupMapOpen}
        initialLat={pickupMapContext === 'enroll' ? newStudent.lat : pickupMapContext === 'staff' ? staffForm.lat : editSt.lat}
        initialLng={pickupMapContext === 'enroll' ? newStudent.lng : pickupMapContext === 'staff' ? staffForm.lng : editSt.lng}
        onClose={() => setPickupMapOpen(false)}
        onConfirm={(la, ln, line1, city) => {
          if (pickupMapContext === 'enroll') {
            setNewStudent((p) => ({ ...p, lat: la, lng: ln, address_line1: line1, address_city: city }));
          } else if (pickupMapContext === 'staff') {
            setStaffForm((p) => ({ ...p, lat: la, lng: ln, address_line1: line1, address_city: city }));
          } else {
            setEditSt((p) => ({ ...p, lat: la, lng: ln, address_line1: line1, address_city: city }));
          }
          setPickupMapOpen(false);
        }}
      />
    </div>
  );
}

function roleBadgeClass(role: string): string {
  switch (roleBadgeTone(role)) {
    case 'indigo':
      return 'bg-indigo-100 text-indigo-700';
    case 'blue':
      return 'bg-blue-100 text-blue-700';
    case 'orange':
      return 'bg-orange-100 text-orange-700';
    case 'green':
      return 'bg-green-100 text-green-700';
    case 'amber':
      return 'bg-amber-100 text-amber-800';
    default:
      return 'bg-slate-100 text-slate-700';
  }
}

function SchoolManagement({
  user,
  schools,
  onRefresh,
  onShowSchoolOnMap,
}: {
  user: User;
  schools: School[];
  onRefresh: () => void;
  onShowSchoolOnMap?: (lat: number, lng: number, label: string) => void;
}) {
  const { t } = useTranslation();
  const [showAdd, setShowAdd] = useState(false);
  const [newName, setNewName] = useState('');
  const [formErr, setFormErr] = useState('');
  const [detailSchool, setDetailSchool] = useState<School | null>(null);
  const [editName, setEditName] = useState('');
  const [editLine1, setEditLine1] = useState('');
  const [editCity, setEditCity] = useState('');
  const [editLat, setEditLat] = useState<number | null>(null);
  const [editLng, setEditLng] = useState<number | null>(null);
  const [campusMapOpen, setCampusMapOpen] = useState(false);
  const [classes, setClasses] = useState<Array<{ id: string; name: string }>>([]);
  const [classesErr, setClassesErr] = useState('');
  const [newClassName, setNewClassName] = useState('');
  const [classesBusy, setClassesBusy] = useState(false);

  const canEditSchools = userHas(user, 'schools_update');
  const canCreateSchools = userHas(user, 'schools_create');

  const openSchoolDetail = (s: School) => {
    setDetailSchool(s);
    setEditName(s.name || '');
    setEditLine1(String(s.address_line1 ?? '').trim());
    setEditCity(String(s.address_city ?? '').trim());
    const la = typeof s.lat === 'number' && Number.isFinite(s.lat) ? s.lat : null;
    const ln = typeof s.lng === 'number' && Number.isFinite(s.lng) ? s.lng : null;
    setEditLat(la);
    setEditLng(ln);
    setClassesErr('');
    setNewClassName('');
    void (async () => {
      setClassesBusy(true);
      try {
        const r = await api(`/api/schools/${encodeURIComponent(s.id)}/classes`);
        const j = (await readJsonLoose(r)) as Array<{ id: string; name: string }>;
        if (r.ok) setClasses(Array.isArray(j) ? j : []);
        else setClasses([]);
      } catch {
        setClasses([]);
      } finally {
        setClassesBusy(false);
      }
    })();
  };

  const saveSchoolDetail = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!detailSchool || !canEditSchools) return;
    const name = editName.trim();
    if (!name) {
      alert(t('schoolAdmin.nameRequired'));
      return;
    }
    const payload: Record<string, unknown> = { name };
    if (editLine1.trim()) payload.address_line1 = editLine1.trim();
    if (editCity.trim()) payload.address_city = editCity.trim();
    if (editLat != null && editLng != null && Number.isFinite(editLat) && Number.isFinite(editLng)) {
      payload.lat = editLat;
      payload.lng = editLng;
    }
    try {
      await apiJson(`/api/schools/${encodeURIComponent(detailSchool.id)}`, payload, { method: 'PATCH' });
      alert(t('schoolAdmin.saved'));
      setDetailSchool(null);
      onRefresh();
    } catch (err) {
      alert(err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const addClassRow = async () => {
    if (!detailSchool || !canEditSchools) return;
    const nm = newClassName.trim().slice(0, 120);
    if (!nm) return;
    setClassesErr('');
    try {
      await apiJson(`/api/schools/${encodeURIComponent(detailSchool.id)}/classes`, { name: nm }, { method: 'POST' });
      setNewClassName('');
      const r = await api(`/api/schools/${encodeURIComponent(detailSchool.id)}/classes`);
      const j = (await readJsonLoose(r)) as Array<{ id: string; name: string }>;
      if (r.ok) setClasses(Array.isArray(j) ? j : []);
      onRefresh();
    } catch (err) {
      setClassesErr(err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const deleteClass = async (classId: string) => {
    if (!detailSchool || !canEditSchools) return;
    if (!window.confirm(t('schoolAdmin.deleteClassConfirm'))) return;
    setClassesErr('');
    try {
      await api(`/api/schools/${encodeURIComponent(detailSchool.id)}/classes/${encodeURIComponent(classId)}`, {
        method: 'DELETE',
      });
      setClasses((prev) => prev.filter((c) => c.id !== classId));
      onRefresh();
    } catch (err) {
      setClassesErr(err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const createSchool = async (e: React.FormEvent) => {
    e.preventDefault();
    setFormErr('');
    const name = newName.trim();
    if (!name) {
      setFormErr(t('schoolAdmin.nameRequired'));
      return;
    }
    try {
      await apiJson('/api/schools', { name });
      alert(t('schoolAdmin.created'));
      setShowAdd(false);
      setNewName('');
      onRefresh();
    } catch (err) {
      setFormErr(err instanceof Error ? err.message : 'Error');
    }
  };

  const canOpenSchoolDetail =
    canEditSchools || (userHas(user, 'map_global_view') && userHas(user, 'schools_read'));

  return (
    <div className="relative flex-1 overflow-y-auto overscroll-y-contain p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4 md:p-6">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3 sm:mb-6">
        <div className="min-w-0">
          <h2 className="text-lg font-bold sm:text-xl">{t('schoolAdmin.title')}</h2>
          <p className="mt-1 text-sm text-slate-500">{t('schoolAdmin.subtitle')}</p>
        </div>
        {canCreateSchools ? (
        <button
          type="button"
          onClick={() => {
            setFormErr('');
            setNewName('');
            setShowAdd(true);
          }}
          className="min-h-10 shrink-0 rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white"
        >
          {t('schoolAdmin.add')}
        </button>
        ) : null}
      </div>

      <div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
        <div className="overflow-x-auto overscroll-x-contain">
        <table className="w-full min-w-[640px] text-left text-sm">
          <thead className="border-b border-slate-200 bg-slate-50 text-slate-500">
            <tr>
              <th className="p-2 sm:p-4">{t('schoolAdmin.id')}</th>
              <th className="p-2 sm:p-4">{t('schoolAdmin.name')}</th>
              <th className="hidden p-2 lg:table-cell lg:p-4">{t('schoolAdmin.address')}</th>
              <th className="hidden p-2 md:table-cell md:p-4">{t('schoolAdmin.city')}</th>
              <th className="p-2 text-end sm:p-4">{t('schoolAdmin.colStudents')}</th>
              <th className="hidden p-2 text-end sm:table-cell sm:p-4">{t('schoolAdmin.colClasses')}</th>
              <th className="hidden p-2 text-end lg:table-cell lg:p-4">{t('schoolAdmin.colBuses')}</th>
              <th className="p-2 sm:p-4">{t('schoolAdmin.colMap')}</th>
            </tr>
          </thead>
          <tbody>
            {compact(schools).length === 0 ? (
              <tr>
                <td colSpan={8} className="p-4 text-center text-slate-500 sm:p-6">
                  {t('schoolAdmin.empty')}
                </td>
              </tr>
            ) : (
              compact(schools).map((s) => (
                <tr
                  key={s.id}
                  role={canOpenSchoolDetail ? 'button' : undefined}
                  tabIndex={canOpenSchoolDetail ? 0 : undefined}
                  onClick={() => {
                    if (canOpenSchoolDetail) openSchoolDetail(s);
                  }}
                  onKeyDown={(e) => {
                    if (!canOpenSchoolDetail) return;
                    if (e.key === 'Enter' || e.key === ' ') {
                      e.preventDefault();
                      openSchoolDetail(s);
                    }
                  }}
                  className={`border-b border-slate-100 last:border-0 ${canOpenSchoolDetail ? 'cursor-pointer hover:bg-slate-100' : 'hover:bg-slate-50'}`}
                >
                  <td className="p-2 font-mono text-xs text-slate-600 sm:p-4">{s.id}</td>
                  <td className="p-2 font-semibold text-slate-800 sm:p-4">{s.name}</td>
                  <td className="hidden max-w-[10rem] truncate p-2 text-slate-600 lg:table-cell lg:p-4">
                    {s.address_line1 || '—'}
                  </td>
                  <td className="hidden p-2 text-slate-600 md:table-cell md:p-4">{s.address_city || '—'}</td>
                  <td className="p-2 text-end tabular-nums sm:p-4">{s.student_count ?? '—'}</td>
                  <td className="hidden p-2 text-end tabular-nums sm:table-cell sm:p-4">{s.class_count ?? '—'}</td>
                  <td className="hidden p-2 text-end tabular-nums lg:table-cell lg:p-4">{s.bus_count ?? '—'}</td>
                  <td className="p-2 sm:p-4">
                    {schoolHasMapCoords(s) && onShowSchoolOnMap ? (
                      <button
                        type="button"
                        className="text-xs font-semibold text-indigo-600 hover:underline"
                        onClick={(e) => {
                          e.stopPropagation();
                          onShowSchoolOnMap(s.lat as number, s.lng as number, s.name);
                        }}
                      >
                        {t('schoolAdmin.showOnMap')}
                      </button>
                    ) : (
                      <span className="text-xs text-slate-400">—</span>
                    )}
                  </td>
                </tr>
              ))
            )}
          </tbody>
        </table>
        </div>
      </div>

      {showAdd && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="max-h-[min(88dvh,560px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl border border-slate-200 bg-white p-4 shadow-xl sm:rounded-xl sm:p-6">
            <h3 className="font-bold text-lg mb-4">{t('schoolAdmin.newTitle')}</h3>
            {formErr ? <div className="mb-3 text-sm text-red-600 bg-red-50 p-2 rounded">{formErr}</div> : null}
            <form onSubmit={(e) => void createSchool(e)} className="space-y-3">
              <input
                required
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                placeholder={t('schoolAdmin.namePlaceholder')}
                value={newName}
                maxLength={200}
                onChange={(e) => setNewName(e.target.value)}
              />
              <div className="flex gap-2 pt-2 pb-[max(0.25rem,env(safe-area-inset-bottom))]">
                <button type="button" className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2" onClick={() => setShowAdd(false)}>
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-600 p-3 text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {detailSchool && canOpenSchoolDetail && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div
            className="max-h-[min(88dvh,640px)] w-full max-w-lg overflow-y-auto overscroll-y-contain rounded-t-2xl border border-slate-200 bg-white p-4 shadow-xl sm:rounded-xl sm:p-6"
            role="dialog"
            aria-modal="true"
            aria-labelledby="school-detail-title"
          >
            <h3 id="school-detail-title" className="mb-1 text-lg font-bold">
              {t('schoolAdmin.detailTitle')}
            </h3>
            <p className="mb-1 font-mono text-xs text-slate-500">{detailSchool.id}</p>
            <p className="mb-4 text-xs text-slate-500">
              {canEditSchools ? t('schoolAdmin.detailHint') : t('schoolAdmin.detailReadOnly')}
            </p>

            {canEditSchools ? (
              <form onSubmit={(e) => void saveSchoolDetail(e)} className="space-y-3">
                <label className="block text-xs font-semibold text-slate-600">{t('schoolAdmin.name')}</label>
                <input
                  required
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('schoolAdmin.namePlaceholder')}
                  value={editName}
                  maxLength={200}
                  onChange={(e) => setEditName(e.target.value)}
                />
                <label className="block text-xs font-semibold text-slate-600">{t('schoolAdmin.address')}</label>
                <input
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('schoolAdmin.addressPlaceholder')}
                  value={editLine1}
                  maxLength={300}
                  onChange={(e) => setEditLine1(e.target.value)}
                />
                <label className="block text-xs font-semibold text-slate-600">{t('schoolAdmin.city')}</label>
                <input
                  className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                  placeholder={t('schoolAdmin.cityPlaceholder')}
                  value={editCity}
                  maxLength={120}
                  onChange={(e) => setEditCity(e.target.value)}
                />
                <div className="flex flex-wrap gap-2">
                  <button
                    type="button"
                    className="min-h-10 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm font-medium text-slate-800"
                    onClick={() => setCampusMapOpen(true)}
                  >
                    {t('schoolAdmin.openCampusMap')}
                  </button>
                  {editLat != null && editLng != null && Number.isFinite(editLat) && Number.isFinite(editLng) ? (
                    <span className="self-center text-xs text-slate-500">
                      {t('schoolAdmin.coordsSummary', { lat: editLat.toFixed(5), lng: editLng.toFixed(5) })}
                    </span>
                  ) : (
                    <span className="self-center text-xs text-amber-700">{t('schoolAdmin.coordsMissing')}</span>
                  )}
                </div>

                <div className="rounded-lg border border-slate-100 bg-slate-50/80 p-3">
                  <div className="mb-2 text-xs font-bold uppercase tracking-wide text-slate-500">
                    {t('schoolAdmin.classesTitle')}
                  </div>
                  {classesErr ? <div className="mb-2 text-xs text-red-600">{classesErr}</div> : null}
                  {classesBusy ? (
                    <p className="text-xs text-slate-500">{t('common.loading')}</p>
                  ) : classes.length === 0 ? (
                    <p className="text-xs text-slate-500">{t('schoolAdmin.classesEmpty')}</p>
                  ) : (
                    <ul className="mb-2 max-h-32 space-y-1 overflow-y-auto text-sm">
                      {classes.map((c) => (
                        <li key={c.id} className="flex items-center justify-between gap-2 rounded border border-white bg-white px-2 py-1">
                          <span className="font-medium text-slate-800">{c.name}</span>
                          <button
                            type="button"
                            className="text-xs text-red-600 hover:underline"
                            onClick={() => void deleteClass(c.id)}
                          >
                            {t('schoolAdmin.deleteClass')}
                          </button>
                        </li>
                      ))}
                    </ul>
                  )}
                  <div className="flex flex-wrap gap-2">
                    <input
                      className="min-h-10 min-w-0 flex-1 rounded border px-2 py-2 text-sm"
                      placeholder={t('schoolAdmin.newClassPlaceholder')}
                      value={newClassName}
                      maxLength={120}
                      onChange={(e) => setNewClassName(e.target.value)}
                    />
                    <button
                      type="button"
                      className="min-h-10 rounded-lg bg-indigo-600 px-3 text-sm font-medium text-white"
                      onClick={() => void addClassRow()}
                    >
                      {t('schoolAdmin.addClass')}
                    </button>
                  </div>
                </div>

                <div className="flex gap-2 pt-2 pb-[max(0.25rem,env(safe-area-inset-bottom))]">
                  <button
                    type="button"
                    className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2"
                    onClick={() => setDetailSchool(null)}
                  >
                    {t('common.cancel')}
                  </button>
                  <button type="submit" className="min-h-11 flex-1 rounded bg-blue-600 p-3 text-white sm:min-h-0 sm:p-2">
                    {t('common.save')}
                  </button>
                </div>
              </form>
            ) : (
              <div className="space-y-3 text-sm text-slate-700">
                <div>
                  <span className="font-semibold text-slate-500">{t('schoolAdmin.address')}: </span>
                  {detailSchool.address_line1 || '—'}
                </div>
                <div>
                  <span className="font-semibold text-slate-500">{t('schoolAdmin.city')}: </span>
                  {detailSchool.address_city || '—'}
                </div>
                <div className="flex flex-wrap gap-3 text-xs">
                  <span>
                    {t('schoolAdmin.colStudents')}: <strong>{detailSchool.student_count ?? '—'}</strong>
                  </span>
                  <span>
                    {t('schoolAdmin.colClasses')}: <strong>{detailSchool.class_count ?? '—'}</strong>
                  </span>
                  <span>
                    {t('schoolAdmin.colBuses')}: <strong>{detailSchool.bus_count ?? '—'}</strong>
                  </span>
                </div>
                {classesBusy ? (
                  <p className="text-xs text-slate-500">{t('common.loading')}</p>
                ) : (
                  <ul className="max-h-36 space-y-1 overflow-y-auto rounded border border-slate-100 bg-slate-50 p-2 text-sm">
                    {classes.map((c) => (
                      <li key={c.id} className="text-slate-800">
                        {c.name}
                      </li>
                    ))}
                  </ul>
                )}
                <button
                  type="button"
                  className="min-h-11 w-full rounded bg-slate-100 p-3 text-sm sm:min-h-0 sm:p-2"
                  onClick={() => setDetailSchool(null)}
                >
                  {t('common.cancel')}
                </button>
              </div>
            )}

            {canEditSchools ? (
              <PickupLocationMapModal
                t={t}
                open={campusMapOpen}
                initialLat={editLat ?? 33.312805}
                initialLng={editLng ?? 44.361488}
                onClose={() => setCampusMapOpen(false)}
                onConfirm={(la, ln, line1, city) => {
                  setEditLat(la);
                  setEditLng(ln);
                  if (!editLine1.trim()) setEditLine1(line1);
                  if (!editCity.trim()) setEditCity(city);
                  setCampusMapOpen(false);
                }}
              />
            ) : null}
          </div>
        </div>
      )}
    </div>
  );
}

function UserManagement({
  user,
  schools,
  onRefresh,
  dataRefreshTick,
}: {
  user: User;
  schools: School[];
  onRefresh: () => void;
  dataRefreshTick: number;
}) {
  const { t } = useTranslation();
  const [allUsers, setAllUsers] = useState<User[]>([]);
  const [userToDelete, setUserToDelete] = useState<User | null>(null);
  const [detailUser, setDetailUser] = useState<User | null>(null);
  const [editForm, setEditForm] = useState({
    name: '',
    email: '',
    phone: '',
    password: '',
    clearPassword: false,
    role: 'parent' as Role,
    school_id: '',
    bus_id: '',
  });
  const [showAdd, setShowAdd] = useState(false);
  const [newUser, setNewUser] = useState({
    name: '',
    email: '',
    phone: '',
    password: '',
    role: 'parent' as Role,
    school_id: '',
    bus_id: '',
  });
  const [editPerms, setEditPerms] = useState<string[]>([]);
  const [editScopes, setEditScopes] = useState<ScopeRow[]>([]);
  const lastToolbarRefreshTick = useRef(0);

  const load = () => {
    void api('/api/users')
      .then((r) => parseFetchJson<User[]>(r))
      .then(setAllUsers)
      .catch(() => {});
  };
  useEffect(() => {
    load();
  }, []);

  useEffect(() => {
    if (dataRefreshTick === lastToolbarRefreshTick.current) return;
    lastToolbarRefreshTick.current = dataRefreshTick;
    if (dataRefreshTick > 0) {
      load();
      onRefresh();
    }
  }, [dataRefreshTick, onRefresh]);

  const confirmDelete = async () => {
    if (!userToDelete) return;
    await api(`/api/users/${userToDelete.id}`, { method: 'DELETE' });
    setUserToDelete(null);
    load();
    onRefresh();
  };

  const openUserDetail = (u: User) => {
    setDetailUser(u);
    setEditForm({
      name: u.name || '',
      email: u.email || '',
      phone: String(u.phone ?? ''),
      password: '',
      clearPassword: false,
      role: u.role as Role,
      school_id: u.school_id || '',
      bus_id: u.bus_id || '',
    });
    setEditPerms([...(u.permissions ?? [])]);
    setEditScopes((u.scopes ?? []).map((r) => ({ scope_type: r.scope_type, scope_id: r.scope_id ?? null })));
  };

  const saveUserDetail = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!detailUser) return;
    try {
      const body: Record<string, unknown> = {
        name: editForm.name.trim(),
        email: editForm.email.trim(),
        phone: editForm.phone.trim(),
        role: editForm.role,
        school_id: editForm.school_id.trim() || null,
        bus_id: editForm.bus_id.trim() || null,
        permissions: editPerms,
        scopes: editScopes.map((s) => ({ scope_type: s.scope_type, scope_id: s.scope_id ?? '' })),
      };
      if (editForm.password.trim()) body.password = editForm.password;
      else if (editForm.clearPassword) body.password = '';
      await apiJson<{ user?: User }>(`/api/users/${detailUser.id}`, body, { method: 'PATCH' });
      alert(t('users.saved'));
      setDetailUser(null);
      load();
      onRefresh();
    } catch (err) {
      alert(err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  const createUser = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      if (!newUser.password.trim() && !newUser.phone.trim()) {
        alert(t('users.phoneHint'));
        return;
      }
      await apiJson('/api/users', {
        name: newUser.name,
        email: newUser.email,
        phone: newUser.phone.trim() || undefined,
        password: newUser.password.trim() || undefined,
        role: newUser.role,
        school_id: newUser.school_id || null,
        bus_id: newUser.bus_id || null,
      });
      alert(t('users.created'));
      setShowAdd(false);
      setNewUser({ name: '', email: '', phone: '', password: '', role: 'parent', school_id: '', bus_id: '' });
      load();
      onRefresh();
    } catch (err) {
      alert(err instanceof Error ? err.message : t('common.unexpectedError'));
    }
  };

  return (
    <div className="relative flex-1 overflow-y-auto overscroll-y-contain p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4 md:p-6">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3 sm:mb-6">
        <h2 className="text-lg font-bold sm:text-xl">{t('users.title')}</h2>
        <div className="flex flex-wrap items-center gap-2">
          <button
            type="button"
            onClick={() => {
              load();
              onRefresh();
            }}
            className="flex min-h-10 items-center gap-2 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50"
            title={t('common.refresh')}
            aria-label={t('common.refresh')}
          >
            <RefreshCw className="h-4 w-4 shrink-0" aria-hidden />
            <span className="hidden sm:inline">{t('common.refresh')}</span>
          </button>
          {userHas(user, 'users_create') ? (
          <button type="button" onClick={() => setShowAdd(true)} className="min-h-10 rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white">
            {t('users.add')}
          </button>
          ) : null}
        </div>
      </div>
      <div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
        <div className="overflow-x-auto overscroll-x-contain">
        <table className="w-full min-w-[520px] text-left text-sm">
          <thead className="border-b border-slate-200 bg-slate-50">
            <tr>
              <th className="p-2 sm:p-4">{t('students.name')}</th>
              <th className="hidden p-2 md:table-cell md:p-4">{t('users.email')}</th>
              <th className="hidden p-2 sm:table-cell sm:p-4">{t('users.phone')}</th>
              <th className="p-2 sm:p-4">{t('users.role')}</th>
              <th className="p-2 text-end sm:p-4">{t('users.actions')}</th>
            </tr>
          </thead>
          <tbody>
            {compact(allUsers).map((u) => (
              <tr
                key={u.id}
                role="button"
                tabIndex={0}
                onClick={() => openUserDetail(u)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    openUserDetail(u);
                  }
                }}
                className="cursor-pointer border-b border-slate-100 hover:bg-slate-100"
              >
                <td className="p-2 align-top sm:p-4">
                  <div className="flex flex-wrap items-center gap-2">
                    <span className="font-semibold">{u.name}</span>
                    {u.is_bootstrap_admin ? (
                      <span className="rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-bold uppercase text-amber-800">
                        {t('users.bootstrap')}
                      </span>
                    ) : null}
                  </div>
                  <div className="mt-1 break-all font-mono text-[11px] text-slate-500 md:hidden">{u.email ?? '—'}</div>
                </td>
                <td className="hidden p-2 text-xs md:table-cell md:p-4">{u.email ?? '—'}</td>
                <td className="hidden p-2 text-xs sm:table-cell sm:p-4">{u.phone ?? '—'}</td>
                <td className="p-2 sm:p-4">
                  <span className={`px-2 py-1 rounded text-xs font-bold ${roleBadgeClass(u.role)}`}>
                    {t(`roles.${roleLabelKey(u.role)}`)}
                  </span>
                </td>
                <td className="p-2 text-end sm:p-4">
                  {u.id !== user.id && userHas(user, 'users_delete') && (
                    <button
                      type="button"
                      onClick={(e) => {
                        e.stopPropagation();
                        setUserToDelete(u);
                      }}
                      className="inline-flex h-10 w-10 items-center justify-center rounded border border-red-100 text-red-500 hover:bg-red-50"
                      title={t('users.delete')}
                      aria-label={t('users.delete')}
                    >
                      <XCircle className="h-4 w-4" />
                    </button>
                  )}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        </div>
      </div>

      {detailUser && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div
            className="max-h-[min(92dvh,720px)] w-full max-w-lg overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-xl sm:rounded-xl sm:p-6"
            role="dialog"
            aria-modal="true"
            aria-labelledby="user-detail-title"
          >
            <h3 id="user-detail-title" className="mb-1 text-lg font-bold">
              {t('users.detailTitle')}
            </h3>
            {detailUser.phone ? (
              <p className="mb-4 text-xs text-slate-500">{t('users.phone')}: {detailUser.phone}</p>
            ) : null}
            <form onSubmit={(e) => void saveUserDetail(e)} className="space-y-3">
              <input
                required
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                placeholder={t('students.name')}
                value={editForm.name}
                onChange={(e) => setEditForm({ ...editForm, name: e.target.value })}
              />
              <input
                required
                type="email"
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                placeholder={t('users.email')}
                value={editForm.email}
                onChange={(e) => setEditForm({ ...editForm, email: e.target.value })}
              />
              <input
                type="tel"
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                placeholder={t('users.phone')}
                value={editForm.phone}
                onChange={(e) => setEditForm({ ...editForm, phone: e.target.value })}
              />
              <p className="text-xs text-slate-500">{t('users.phoneHint')}</p>
              <select
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                value={editForm.role}
                disabled={detailUser.id === user.id}
                onChange={(e) => setEditForm({ ...editForm, role: e.target.value as Role })}
              >
                {ALL_MANAGEABLE_ROLES.map((r) => (
                  <option key={r} value={r}>
                    {t(`roles.${r}`)}
                  </option>
                ))}
              </select>
              <label className="block text-xs font-semibold text-slate-600">{t('users.schoolPick')}</label>
              <select
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                value={editForm.school_id}
                onChange={(e) => setEditForm({ ...editForm, school_id: e.target.value })}
              >
                <option value="">{t('users.schoolNone')}</option>
                {compact(schools).map((s) => (
                  <option key={s.id} value={s.id}>
                    {s.name}
                  </option>
                ))}
              </select>
              <input
                className="min-h-11 w-full rounded border p-3 text-sm sm:min-h-0 sm:p-2"
                placeholder={t('users.busId')}
                value={editForm.bus_id}
                onChange={(e) => setEditForm({ ...editForm, bus_id: e.target.value })}
              />
              <div className="max-h-44 space-y-1 overflow-y-auto rounded-lg border border-slate-200 p-2">
                <div className="text-xs font-bold text-slate-700">{t('users.permissionsHeading')}</div>
                {ALL_PERMISSION_STRINGS.map((p) => (
                  <label key={p} className="flex cursor-pointer items-start gap-2 text-[11px] leading-tight">
                    <input
                      type="checkbox"
                      className="mt-0.5"
                      checked={editPerms.includes(p)}
                      onChange={() =>
                        setEditPerms((prev) => (prev.includes(p) ? prev.filter((x) => x !== p) : [...prev, p]))
                      }
                    />
                    <span>{t(`perm.${p}`)}</span>
                  </label>
                ))}
              </div>
              <div className="space-y-2 rounded-lg border border-slate-200 p-2">
                <div className="text-xs font-bold text-slate-700">{t('users.scopesHeading')}</div>
                <p className="text-[10px] text-slate-500">{t('users.scopeRowsHint')}</p>
                {editScopes.map((row, idx) => (
                  <div key={idx} className="flex flex-col gap-1 sm:flex-row sm:items-center">
                    <select
                      className="min-h-9 flex-1 rounded border px-2 py-1 text-xs"
                      value={row.scope_type}
                      onChange={(e) =>
                        setEditScopes((prev) =>
                          prev.map((x, i) => (i === idx ? { ...x, scope_type: e.target.value } : x))
                        )
                      }
                    >
                      {[
                        'global',
                        'government_readonly',
                        'schools_all',
                        'school_single',
                        'fleet_all',
                        'fleet_school',
                        'own_children',
                        'own_bus',
                      ].map((st) => (
                        <option key={st} value={st}>
                          {t(`users.scopes.${st}`)}
                        </option>
                      ))}
                    </select>
                    <input
                      className="min-h-9 flex-1 rounded border px-2 py-1 font-mono text-xs"
                      placeholder={t('users.scopeId')}
                      value={row.scope_id ?? ''}
                      onChange={(e) =>
                        setEditScopes((prev) =>
                          prev.map((x, i) => (i === idx ? { ...x, scope_id: e.target.value || null } : x))
                        )
                      }
                    />
                    <button
                      type="button"
                      className="shrink-0 text-xs text-red-600"
                      onClick={() => setEditScopes((prev) => prev.filter((_, i) => i !== idx))}
                    >
                      {t('users.removeScopeRow')}
                    </button>
                  </div>
                ))}
                <button
                  type="button"
                  className="text-xs font-semibold text-blue-600"
                  onClick={() =>
                    setEditScopes((prev) => [...prev, { scope_type: 'school_single', scope_id: '' }])
                  }
                >
                  {t('users.addScopeRow')}
                </button>
              </div>
              <input
                type="password"
                minLength={8}
                className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2"
                placeholder={t('users.newPasswordOptional')}
                autoComplete="new-password"
                value={editForm.password}
                onChange={(e) => setEditForm({ ...editForm, password: e.target.value, clearPassword: false })}
              />
              <p className="text-xs text-slate-500">{t('users.passwordOtpHint')}</p>
              <label className="flex items-center gap-2 text-sm text-slate-700">
                <input
                  type="checkbox"
                  checked={editForm.clearPassword}
                  onChange={(e) =>
                    setEditForm({ ...editForm, clearPassword: e.target.checked, password: e.target.checked ? '' : editForm.password })
                  }
                />
                {t('users.clearPasswordOtp')}
              </label>
              <p className="text-xs text-slate-500">{t('users.detailHint')}</p>
              <div className="flex gap-2 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2" onClick={() => setDetailUser(null)}>
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-600 p-3 text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {showAdd && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,720px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-xl sm:rounded-xl sm:p-6">
            <h3 className="mb-4 text-lg font-bold">{t('users.newTitle')}</h3>
            <form onSubmit={createUser} className="space-y-3">
              <input required className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2" placeholder={t('students.name')} value={newUser.name} onChange={(e) => setNewUser({ ...newUser, name: e.target.value })} />
              <input required type="email" className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2" placeholder={t('users.email')} value={newUser.email} onChange={(e) => setNewUser({ ...newUser, email: e.target.value })} />
              <input type="tel" className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2" placeholder={t('users.phone')} value={newUser.phone} onChange={(e) => setNewUser({ ...newUser, phone: e.target.value })} />
              <p className="text-xs text-slate-500">{t('users.phoneHint')}</p>
              <input type="password" minLength={8} className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2" placeholder={t('users.passwordOptional')} value={newUser.password} onChange={(e) => setNewUser({ ...newUser, password: e.target.value })} />
              <p className="text-xs text-slate-500">{t('users.passwordOtpHint')}</p>
              <select className="min-h-11 w-full rounded border p-3 sm:min-h-0 sm:p-2" value={newUser.role} onChange={(e) => setNewUser({ ...newUser, role: e.target.value as Role })}>
                {ALL_MANAGEABLE_ROLES.map((r) => (
                  <option key={r} value={r}>
                    {t(`roles.${r}`)}
                  </option>
                ))}
              </select>
              <input className="min-h-11 w-full rounded border p-3 text-sm sm:min-h-0 sm:p-2" placeholder={t('users.schoolId')} value={newUser.school_id} onChange={(e) => setNewUser({ ...newUser, school_id: e.target.value })} />
              <input className="min-h-11 w-full rounded border p-3 text-sm sm:min-h-0 sm:p-2" placeholder={t('users.busId')} value={newUser.bus_id} onChange={(e) => setNewUser({ ...newUser, bus_id: e.target.value })} />
              <div className="flex gap-2 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" className="min-h-11 flex-1 rounded bg-slate-100 p-3 sm:min-h-0 sm:p-2" onClick={() => setShowAdd(false)}>
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-600 p-3 text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {userToDelete && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 sm:items-center sm:p-4">
          <div className="w-full max-w-md rounded-t-2xl border border-slate-200 bg-white p-4 shadow-xl sm:rounded-xl sm:p-6">
            <div className="flex justify-center mb-4">
              <div className="bg-red-100 p-3 rounded-full text-red-500">
                <AlertTriangle className="w-8 h-8" />
              </div>
            </div>
            <h3 className="font-bold text-lg text-center mb-2">{t('users.deleteTitle')}</h3>
            <p className="text-slate-500 text-sm text-center mb-6">
              <Trans i18nKey="users.deleteBody" values={{ name: userToDelete.name }} />
            </p>
            <div className="flex gap-3 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
              <button type="button" onClick={() => setUserToDelete(null)} className="min-h-11 flex-1 rounded-lg bg-slate-100 p-3 sm:min-h-0 sm:p-2">
                {t('users.cancel')}
              </button>
              <button type="button" onClick={() => void confirmDelete()} className="min-h-11 flex-1 rounded-lg bg-red-500 p-3 text-white sm:min-h-0 sm:p-2">
                {t('users.delete')}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

type FleetDetailState = { kind: 'bus'; id: string } | { kind: 'device'; imei: string };

function FleetFullDetailOverlay({
  detail,
  schools,
  buses,
  detailNonce,
  onClose,
  onNavigate,
  onFleetMutate,
  onOpenActivatePrefill,
}: {
  detail: FleetDetailState;
  schools: School[];
  buses: { id: string; license_plate?: string; school_id?: string; imei?: string | null }[];
  detailNonce: number;
  onClose: () => void;
  onNavigate: (d: FleetDetailState) => void;
  onFleetMutate: () => void;
  /** Open the Register device modal with fields filled from this device (z-index above overlay). */
  onOpenActivatePrefill?: (device: Record<string, unknown>) => void;
}) {
  const { t } = useTranslation();
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState('');
  const [payload, setPayload] = useState<any>(null);

  const detailKey = detail.kind === 'bus' ? `bus:${detail.id}` : `device:${detail.imei}`;

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setErr('');
    setPayload(null);
    const url =
      detail.kind === 'bus'
        ? `/api/fleet/buses/${encodeURIComponent(detail.id)}/detail`
        : `/api/fleet/devices/${encodeURIComponent(detail.imei)}/detail`;
    void api(url)
      .then((r) => parseFetchJson(r))
      .then((d) => {
        if (!cancelled) setPayload(d);
      })
      .catch((e) => {
        if (!cancelled) setErr(e instanceof Error ? e.message : 'Error');
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [detailKey, detailNonce]);

  return (
    <div className="fixed inset-0 z-[1000] flex flex-col bg-slate-950/60 backdrop-blur-sm pt-[env(safe-area-inset-top)]">
      <div className="flex shrink-0 items-center gap-2 bg-slate-900 px-3 py-2 text-white sm:gap-3 sm:px-4 sm:py-3">
        <button type="button" onClick={onClose} className="flex min-h-10 min-w-0 flex-1 items-center gap-2 rounded-lg px-2 py-2 text-sm font-bold hover:bg-white/10 sm:flex-none sm:px-3">
          <ArrowLeft className="h-4 w-4 shrink-0" /> <span className="truncate">{t('fleet.detailClose')}</span>
        </button>
        <span className="hidden min-w-0 truncate text-sm font-bold sm:block sm:max-w-[50%]">
          {detail.kind === 'bus' ? t('fleet.detailTitleBus') : t('fleet.detailTitleDevice')}
        </span>
      </div>
      <div className="flex-1 overflow-y-auto overscroll-y-contain bg-slate-50 p-3 pb-[max(1rem,env(safe-area-inset-bottom))] md:p-8">
        {loading ? <div className="text-center text-slate-500 py-20">{t('common.loading')}</div> : null}
        {err ? <div className="max-w-3xl mx-auto text-red-600 bg-red-50 border border-red-100 rounded-xl p-4">{err}</div> : null}
        {!loading && !err && payload && detail.kind === 'bus' ? (
          <BusDetailBody payload={payload} schools={schools} onNavigate={onNavigate} t={t} />
        ) : null}
        {!loading && !err && payload && detail.kind === 'device' ? (
          <DeviceDetailBody
            payload={payload}
            buses={buses}
            schools={schools}
            onNavigate={onNavigate}
            onFleetMutate={onFleetMutate}
            onOpenActivatePrefill={onOpenActivatePrefill}
          />
        ) : null}
      </div>
    </div>
  );
}

function BusDetailBody({ payload, schools, onNavigate, t }: { payload: any; schools: School[]; onNavigate: (d: FleetDetailState) => void; t: TFunction }) {
  const b = payload?.bus;
  if (!b || typeof b !== 'object') {
    return (
      <div className="max-w-3xl mx-auto text-amber-900 bg-amber-50 border border-amber-100 rounded-xl p-4 text-sm">
        {t('fleet.busPayloadMissing')}
      </div>
    );
  }
  const school = payload.school || schools.find((s) => s.id === b.school_id);
  const trip = payload.trip || { current_stop: 0, stops: [] };
  const routePts = Array.isArray(b.route) ? b.route : [];
  const tripStops = Array.isArray(trip.stops) ? trip.stops : [];
  return (
    <div className="mx-auto max-w-5xl space-y-4 pb-12 sm:space-y-6 sm:pb-16">
      <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-6">
        <div className="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between">
          <div className="min-w-0">
            <h2 className="text-xl font-black text-slate-900 sm:text-2xl">{b.license_plate}</h2>
            <p className="mt-1 text-sm text-slate-500">{b.make_model || '—'}</p>
            <p className="mt-2 font-mono text-xs text-slate-400">ID: {b.id}</p>
          </div>
          <div className="text-start sm:text-end">
            <span className="inline-block bg-indigo-100 text-indigo-800 text-xs font-bold px-3 py-1 rounded-full">{school?.name || '—'}</span>
            <p className="text-sm mt-2">
              <span className="text-slate-500">{t('fleet.capacity')}:</span> <strong>{b.occupancy ?? 0}</strong> / {b.capacity ?? '—'}
            </p>
            <p className="text-xs text-slate-500 mt-1">
              {t('students.status')}: <strong>{b.status}</strong>
            </p>
          </div>
        </div>
        <dl className="mt-6 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm border-t border-slate-100 pt-6">
          <div>
            <dt className="text-slate-400 font-medium">{t('fleet.vin')}</dt>
            <dd className="font-mono text-slate-800">{b.vin || '—'}</dd>
          </div>
          <div>
            <dt className="text-slate-400 font-medium">IMEI</dt>
            <dd>
              {b.imei ? (
                <button type="button" className="font-mono text-indigo-600 font-bold underline" onClick={() => onNavigate({ kind: 'device', imei: String(b.imei) })}>
                  {b.imei}
                </button>
              ) : (
                '—'
              )}
            </dd>
          </div>
        </dl>
      </div>
      <div className="grid gap-4 md:grid-cols-2 md:gap-6">
        <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-5">
          <h3 className="font-bold text-slate-800 flex items-center gap-2 mb-3">
            <MapPin className="w-4 h-4 text-emerald-600" /> {t('fleet.sectionLiveGps')}
          </h3>
          <p className="text-sm text-slate-600">
            lat {b.live?.lat ?? '—'}, lng {b.live?.lng ?? '—'}
          </p>
          <p className="text-sm text-slate-600 mt-1">
            {t('fleet.lastPing')}: {b.live?.last_ping ? new Date(b.live.last_ping).toLocaleString() : '—'} · {t('fleet.speedLabel')} {b.live?.speed ?? '—'}
          </p>
        </div>
        <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-5">
          <h3 className="font-bold text-slate-800 flex items-center gap-2 mb-3">
            <Layers className="w-4 h-4 text-amber-600" /> {t('fleet.sectionPlannedRoute')}
          </h3>
          <p className="text-sm text-slate-600">
            {tripStops.length > 0
              ? `${tripStops.length} ${t('fleet.routeStops')}`
              : routePts.length > 0
                ? t('fleet.routeGeometryOnly', { count: routePts.length })
                : t('fleet.routeEmpty')}
          </p>
          {tripStops.length > 0 ? (
            <ol className="mt-2 max-h-40 overflow-y-auto space-y-1.5 text-sm text-slate-800 list-decimal pl-6 [list-style-position:outside]">
              {tripStops.slice(0, 40).map((stop: { student?: { name?: string }; student_id?: string }, i: number) => (
                <li key={i} className="break-words pr-1">
                  {stop.student?.name || stop.student_id || t('fleet.routeStopUnnamed')}
                </li>
              ))}
              {tripStops.length > 40 ? <li className="text-slate-500">…</li> : null}
            </ol>
          ) : (
            <p className="mt-2 text-xs text-slate-500 leading-relaxed">{t('fleet.routeNoNamedStopsHint')}</p>
          )}
        </div>
      </div>
      {payload.device ? (
        <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-5">
          <h3 className="font-bold text-slate-800 flex items-center gap-2 mb-3">
            <Cpu className="w-4 h-4 text-blue-600" /> {t('fleet.sectionTracker')}
          </h3>
          <div className="grid sm:grid-cols-2 gap-2 text-sm">
            <div>
              <span className="text-slate-400">{t('fleet.deviceModel')}:</span> {payload.device.device_model || '—'}
            </div>
            <div>
              <span className="text-slate-400">{t('fleet.firmware')}:</span> {payload.device.firmware || '—'}
            </div>
            <div>
              <span className="text-slate-400">{t('fleet.profile')}:</span> {payload.device.config_profile || '—'}
            </div>
            <div>
              <span className="text-slate-400">{t('fleet.iccid')}:</span> <span className="font-mono text-xs">{payload.device.iccid || '—'}</span>
            </div>
            <div className="sm:col-span-2">
              <span className="text-slate-400">{t('fleet.phone')}:</span> {payload.device.phone_number || '—'}
            </div>
          </div>
        </div>
      ) : null}
      <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-5">
        <h3 className="font-bold text-slate-800 flex items-center gap-2 mb-2">
          <ListOrdered className="w-4 h-4 text-violet-600" /> {t('fleet.sectionActiveTrip')}
        </h3>
        <p className="text-xs text-amber-700 bg-amber-50 border border-amber-100 rounded-lg px-3 py-2 mb-3">{t('fleet.tripHistoryNote')}</p>
        <p className="text-sm text-slate-600 mb-3">
          {t('fleet.tripCurrentStop')}: <strong>{trip.current_stop}</strong>
        </p>
        <div className="overflow-x-auto border border-slate-100 rounded-lg">
          <table className="w-full text-left text-sm">
            <thead className="bg-slate-50 text-slate-500">
              <tr>
                <th className="p-2">#</th>
                <th className="p-2">{t('students.name')}</th>
                <th className="p-2">{t('driver.status')}</th>
              </tr>
            </thead>
            <tbody>
              {(trip.stops || []).map((stop: any, idx: number) => (
                <tr key={idx} className="border-t border-slate-100">
                  <td className="p-2 text-slate-400">{idx + 1}</td>
                  <td className="p-2 font-medium">{stop.student?.name || stop.student_id || '—'}</td>
                  <td className="p-2">{stop.status || '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:p-5">
        <h3 className="font-bold text-slate-800 mb-3">{t('fleet.sectionSchoolRoster')}</h3>
        <div className="overflow-x-auto max-h-64 overflow-y-auto border border-slate-100 rounded-lg">
          <table className="w-full text-left text-xs">
            <thead className="bg-slate-50 text-slate-500 sticky top-0">
              <tr>
                <th className="p-2">{t('students.name')}</th>
                <th className="p-2">{t('students.status')}</th>
                <th className="p-2">{t('fleet.sickCol')}</th>
              </tr>
            </thead>
            <tbody>
              {(payload.studentsAtSchool || []).map((s: any) => (
                <tr key={s.id} className="border-t border-slate-100">
                  <td className="p-2">{s.name}</td>
                  <td className="p-2">{s.status}</td>
                  <td className="p-2">{s.isSickStatus || '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

function DeviceDetailBody({
  payload,
  onNavigate,
  buses,
  schools,
  onFleetMutate,
  onOpenActivatePrefill,
}: {
  payload: any;
  onNavigate: (d: FleetDetailState) => void;
  buses: { id: string; license_plate?: string; school_id?: string; imei?: string | null }[];
  schools: School[];
  onFleetMutate: () => void;
  onOpenActivatePrefill?: (device: Record<string, unknown>) => void;
}) {
  const { t } = useTranslation();
  const d = payload.device;
  const [linkBusId, setLinkBusId] = useState('');
  const [linkErr, setLinkErr] = useState('');
  const [linkBusy, setLinkBusy] = useState(false);
  let desiredObj: Record<string, unknown> = {};
  const raw = d.desired_config;
  if (raw != null) {
    if (typeof raw === 'string') {
      try {
        desiredObj = JSON.parse(raw) as Record<string, unknown>;
      } catch {
        desiredObj = {};
      }
    } else if (typeof raw === 'object') {
      desiredObj = raw as Record<string, unknown>;
    }
  }
  let desiredPretty = '';
  try {
    desiredPretty = JSON.stringify(desiredObj, null, 2);
  } catch {
    desiredPretty = '{}';
  }
  const isUnknown = String(d.config_profile || '').toLowerCase() === 'unknown';
  const autoDiscoveredFlag = desiredObj.auto_discovered === true;
  const linked = compact((payload.linkedBuses || []) as { id: string; license_plate?: string }[] | null);
  const online = payload.device_online as
    | { last_seen_at?: string; last_lat?: number | null; last_lng?: number | null; last_speed?: number | null }
    | null
    | undefined;
  const recent = compact((payload.recent_positions || []) as Record<string, unknown>[] | null);
  const positionSource = String(payload.position_source || 'none');

  const formatRawIoPreview = (raw: unknown): string => {
    if (raw == null) return '—';
    if (typeof raw === 'string') return raw.length > 160 ? `${raw.slice(0, 160)}…` : raw;
    try {
      const s = JSON.stringify(raw);
      return s.length > 160 ? `${s.slice(0, 160)}…` : s;
    } catch {
      return '—';
    }
  };

  const linkToBus = async () => {
    if (!linkBusId) return;
    setLinkErr('');
    setLinkBusy(true);
    try {
      await apiJson(`/api/fleet/buses/${encodeURIComponent(linkBusId)}`, { imei: d.imei }, { method: 'PATCH' });
      setLinkBusId('');
      onFleetMutate();
    } catch (e) {
      setLinkErr(e instanceof ApiError ? e.message : e instanceof Error ? e.message : 'Error');
    } finally {
      setLinkBusy(false);
    }
  };

  const unlinkBus = async (busId: string) => {
    setLinkErr('');
    setLinkBusy(true);
    try {
      await apiJson(`/api/fleet/buses/${encodeURIComponent(busId)}`, { imei: null }, { method: 'PATCH' });
      onFleetMutate();
    } catch (e) {
      setLinkErr(e instanceof ApiError ? e.message : e instanceof Error ? e.message : 'Error');
    } finally {
      setLinkBusy(false);
    }
  };

  return (
    <div className="max-w-5xl mx-auto space-y-6 pb-16">
      <div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-6">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div className="flex flex-wrap items-center gap-2 min-w-0">
            <h2 className="text-xl font-black font-mono text-slate-900">{d.imei}</h2>
            {isUnknown ? (
              <span className="text-xs font-bold uppercase tracking-wide bg-amber-100 text-amber-900 px-2 py-0.5 rounded border border-amber-200">
                {t('fleet.discoveredBadge')}
              </span>
            ) : null}
          </div>
          {onOpenActivatePrefill ? (
            <button
              type="button"
              onClick={() => onOpenActivatePrefill(d as Record<string, unknown>)}
              className="shrink-0 inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-blue-600 text-white text-xs font-bold hover:bg-blue-700"
            >
              <PlusCircle className="w-3.5 h-3.5" aria-hidden />
              {t('fleet.openActivatePrefilledForm')}
            </button>
          ) : null}
        </div>
        <p className="text-sm text-slate-500 mt-2">
          {t('fleet.deviceModel')}: {d.device_model || '—'} · {t('fleet.firmware')}: {d.firmware || '—'}
        </p>
        {isUnknown || autoDiscoveredFlag ? (
          <p className="mt-3 text-xs text-amber-900 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2 leading-relaxed">
            {t('fleet.autoDiscoveredFieldsHint')}
          </p>
        ) : null}
        <div className="mt-4 grid sm:grid-cols-2 gap-3 text-sm">
          <div>
            <span className="text-slate-400">{t('fleet.profile')}:</span> {d.config_profile || '—'}
          </div>
          <div>
            <span className="text-slate-400">{t('students.status')}:</span> {d.status || '—'}
          </div>
          <div className="sm:col-span-2">
            <span className="text-slate-400">{t('fleet.iccid')}:</span> <span className="font-mono">{d.iccid || '—'}</span>
          </div>
          <div className="sm:col-span-2">
            <span className="text-slate-400">{t('fleet.phone')}:</span> {d.phone_number || '—'}
          </div>
          <div className="sm:col-span-2">
            <span className="text-slate-400">{t('fleet.lastPing')}:</span> {d.last_ping ? new Date(d.last_ping).toLocaleString() : '—'}
          </div>
          {d.notes ? (
            <div className="sm:col-span-2">
              <span className="text-slate-400">{t('fleet.notes')}:</span> {d.notes}
            </div>
          ) : null}
        </div>
        <pre className="mt-4 text-[11px] bg-slate-900 text-slate-100 p-4 rounded-xl overflow-x-auto">{desiredPretty}</pre>
      </div>

      <div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-5">
        <h3 className="font-bold text-slate-800 flex items-center gap-2 mb-3">
          <Radio className="w-4 h-4 text-sky-600 shrink-0" aria-hidden />
          {t('fleet.sectionTelemetryIngest')}
        </h3>
        {!online && recent.length === 0 ? (
          <p className="text-sm text-slate-600 leading-relaxed border border-slate-100 rounded-lg p-3 bg-slate-50">{t('fleet.telemetryNoData')}</p>
        ) : null}
        {online ? (
          <dl className="grid sm:grid-cols-2 gap-3 text-sm mb-4 border border-slate-100 rounded-lg p-3 bg-emerald-50/40">
            <div>
              <dt className="text-slate-500">{t('fleet.telemetryLastSeen')}</dt>
              <dd className="font-medium text-slate-900">
                {online.last_seen_at ? new Date(online.last_seen_at).toLocaleString() : '—'}
              </dd>
            </div>
            <div>
              <dt className="text-slate-500">{t('fleet.telemetryColLatLng')}</dt>
              <dd className="font-mono text-xs text-slate-800">
                {online.last_lat != null && online.last_lng != null ? `${online.last_lat}, ${online.last_lng}` : '—'}
              </dd>
            </div>
            <div className="sm:col-span-2">
              <dt className="text-slate-500">{t('fleet.telemetryColSpeed')}</dt>
              <dd>{online.last_speed != null ? String(online.last_speed) : '—'}</dd>
            </div>
          </dl>
        ) : null}
        {recent.length > 0 ? (
          <>
            <p className="text-xs text-slate-500 mb-2">
              {t('fleet.telemetryRecent')}
              {positionSource === 'clickhouse'
                ? ` · ${t('fleet.telemetrySourceCh')}`
                : positionSource === 'postgresql'
                  ? ` · ${t('fleet.telemetrySourcePg')}`
                  : null}
            </p>
            <div className="overflow-x-auto border border-slate-100 rounded-lg max-h-64 overflow-y-auto">
              <table className="w-full text-left text-xs">
                <thead className="bg-slate-50 text-slate-500 sticky top-0">
                  <tr>
                    <th className="p-2">{t('fleet.telemetryColRecorded')}</th>
                    <th className="p-2">{t('fleet.telemetryColLatLng')}</th>
                    <th className="p-2">{t('fleet.telemetryColSpeed')}</th>
                    <th className="p-2 min-w-[8rem]">{t('fleet.telemetryColIo')}</th>
                  </tr>
                </thead>
                <tbody>
                  {recent.map((row, idx) => {
                    const ts = row.recorded_at != null ? String(row.recorded_at) : '';
                    const lat = row.lat;
                    const lng = row.lng;
                    const sp = row.speed;
                    return (
                      <tr key={`${ts}-${idx}`} className="border-t border-slate-100 align-top">
                        <td className="p-2 whitespace-nowrap text-slate-700">{ts ? new Date(ts).toLocaleString() : '—'}</td>
                        <td className="p-2 font-mono text-[11px] text-slate-700">
                          {lat != null && lng != null ? `${lat}, ${lng}` : '—'}
                        </td>
                        <td className="p-2">{sp != null ? String(sp) : '—'}</td>
                        <td className="p-2 font-mono text-[10px] text-slate-600 break-all">{formatRawIoPreview(row.raw_io)}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </>
        ) : null}
      </div>

      <div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-5">
        <h3 className="font-bold text-slate-800 mb-3">{t('fleet.sectionLinkedVehicles')}</h3>
        {linked.length === 0 ? (
          <p className="text-sm text-slate-500">{t('fleet.noLinkedBus')}</p>
        ) : (
          <ul className="space-y-3">
            {linked.map((bus: any) => (
              <li key={bus.id} className="border border-slate-100 rounded-lg p-3 flex flex-wrap justify-between gap-2 items-center">
                <div>
                  <div className="font-bold">{bus.license_plate}</div>
                  <div className="text-xs text-slate-500">{bus.make_model}</div>
                  <div className="text-xs font-mono mt-1">{bus.id}</div>
                  {bus.trip ? (
                    <div className="text-xs text-violet-700 mt-1">
                      {t('fleet.tripSummary', {
                        stop: bus.trip.current_stop ?? 0,
                        count: Array.isArray(bus.trip.stops) ? bus.trip.stops.length : 0,
                      })}
                    </div>
                  ) : null}
                </div>
                <div className="flex flex-wrap gap-2 items-center">
                  <button type="button" className="text-sm font-bold text-indigo-600 underline" onClick={() => onNavigate({ kind: 'bus', id: bus.id })}>
                    {t('fleet.viewFullBus')}
                  </button>
                  <button
                    type="button"
                    disabled={linkBusy}
                    onClick={() => void unlinkBus(bus.id)}
                    className="text-sm font-bold text-red-600 border border-red-200 rounded-lg px-3 py-1 hover:bg-red-50 disabled:opacity-40"
                  >
                    {t('fleet.unlinkAction')}
                  </button>
                </div>
              </li>
            ))}
          </ul>
        )}
      </div>

      <div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-5">
        <h3 className="font-bold text-slate-800 mb-2 flex items-center gap-2">
          <Link2 className="w-4 h-4 text-indigo-600" /> {t('fleet.linkToVehicle')}
        </h3>
        <p className="text-sm text-slate-600 mb-4">{t('fleet.linkHelp')}</p>
        {linkErr ? <div className="text-sm text-red-600 bg-red-50 border border-red-100 rounded-lg px-3 py-2 mb-3">{linkErr}</div> : null}
        <div className="flex flex-wrap gap-2 items-end">
          <div className="min-w-[200px] flex-1">
            <label className="text-xs text-slate-500 block mb-1">{t('fleet.selectVehicle')}</label>
            <select
              className="w-full border rounded-lg px-3 py-2 text-sm"
              value={linkBusId}
              onChange={(e) => setLinkBusId(e.target.value)}
              disabled={linkBusy}
            >
              <option value="">{t('fleet.pickVehiclePlaceholder')}</option>
              {compact(buses).map((b) => {
                const school = schools.find((s) => s.id === b.school_id);
                const busy = b.imei && b.imei !== d.imei;
                return (
                  <option key={b.id} value={b.id}>
                    {b.license_plate || b.id}
                    {school ? ` · ${school.name}` : ''}
                    {busy ? ` (${t('fleet.busHasOtherImei')})` : ''}
                  </option>
                );
              })}
            </select>
          </div>
          <button
            type="button"
            disabled={!linkBusId || linkBusy}
            onClick={() => void linkToBus()}
            className="px-4 py-2 bg-indigo-600 text-white text-sm font-bold rounded-lg disabled:opacity-40"
          >
            {t('fleet.linkAction')}
          </button>
        </div>
      </div>
    </div>
  );
}

function FleetManagement({
  schools,
  onRefresh,
  dataRefreshTick,
  onShowBusOnMap,
  onShowDeviceGpsOnMap,
}: {
  schools: School[];
  onRefresh: () => void;
  dataRefreshTick: number;
  onShowBusOnMap: (busId: string, lat?: number | null, lng?: number | null) => void;
  onShowDeviceGpsOnMap: (lat: number, lng: number, label: string) => void;
}) {
  const { t } = useTranslation();
  const lastToolbarRefreshTick = useRef(0);
  const [activeTab, setActiveTab] = useState<'vehicles' | 'devices'>('vehicles');
  const [buses, setBuses] = useState<any[]>([]);
  const [devices, setDevices] = useState<any[]>([]);
  const [deviceTotal, setDeviceTotal] = useState(0);
  const [devicePageSize, setDevicePageSize] = useState(100);
  const [deviceOffset, setDeviceOffset] = useState(0);
  const [deviceSearchInput, setDeviceSearchInput] = useState('');
  const [deviceSearchDebounced, setDeviceSearchDebounced] = useState('');
  const [linkableDevices, setLinkableDevices] = useState<any[]>([]);
  const [linkableFilter, setLinkableFilter] = useState('');
  const [selectedImeis, setSelectedImeis] = useState<string[]>([]);
  const [showBulkImport, setShowBulkImport] = useState(false);
  const [bulkCsv, setBulkCsv] = useState('');
  const [bulkPreview, setBulkPreview] = useState<string>('');
  const [editDevice, setEditDevice] = useState<any | null>(null);
  const [bulkProfile, setBulkProfile] = useState('');
  const [fleetMsg, setFleetMsg] = useState('');
  const [fleetMsgSuccess, setFleetMsgSuccess] = useState(false);
  const [showAddDevice, setShowAddDevice] = useState(false);
  const [activatePrefilled, setActivatePrefilled] = useState(false);
  const [newDevice, setNewDevice] = useState({
    imei: '',
    iccid: '',
    phone_number: '',
    device_model: '',
    notes: '',
    desired_config_json: '',
    firmware: '',
    config_profile: 'Standard',
  });
  const [showAddVehicle, setShowAddVehicle] = useState(false);
  const [fleetDetail, setFleetDetail] = useState<FleetDetailState | null>(null);
  const [fleetDetailNonce, setFleetDetailNonce] = useState(0);
  const [newVehicle, setNewVehicle] = useState({
    license_plate: '',
    vin: '',
    make_model: '',
    capacity: 50,
    school_id: schools[0]?.id || '',
    imei: '',
  });

  const reloadFleet = useCallback(() => {
    void api('/api/buses')
      .then((r) => parseFetchJson(r))
      .then(setBuses)
      .catch(() => {});
    const params = new URLSearchParams({
      limit: String(devicePageSize),
      offset: String(deviceOffset),
      q: deviceSearchDebounced,
    });
    void api(`/api/fleet/devices?${params}`)
      .then((r) => parseFetchJson<{ items?: unknown[]; total?: number }>(r))
      .then((data) => {
        const items = Array.isArray(data.items) ? data.items : [];
        const total = typeof data.total === 'number' ? data.total : 0;
        setDevices(items);
        setDeviceTotal(total);
        if (total > 0 && deviceOffset >= total) {
          setDeviceOffset(Math.max(0, Math.floor((total - 1) / devicePageSize) * devicePageSize));
        }
        if (total === 0) setDeviceOffset(0);
      })
      .catch(() => {});
  }, [devicePageSize, deviceOffset, deviceSearchDebounced]);

  useEffect(() => {
    const t = window.setTimeout(() => setDeviceSearchDebounced(deviceSearchInput.trim()), 300);
    return () => window.clearTimeout(t);
  }, [deviceSearchInput]);

  useEffect(() => {
    setDeviceOffset(0);
  }, [deviceSearchDebounced]);

  useEffect(() => {
    reloadFleet();
    const socket = getSocket();
    socket.on('fleetUpdate', reloadFleet);
    return () => {
      socket.off('fleetUpdate', reloadFleet);
    };
  }, [reloadFleet]);

  useEffect(() => {
    if (!showAddVehicle) return;
    const t = window.setTimeout(() => {
      const params = new URLSearchParams({ limit: '400', q: linkableFilter.trim() });
      void api(`/api/fleet/devices/linkable?${params}`)
        .then((r) => parseFetchJson<unknown[]>(r))
        .then((rows) => setLinkableDevices(Array.isArray(rows) ? rows : []))
        .catch(() => setLinkableDevices([]));
    }, 250);
    return () => window.clearTimeout(t);
  }, [showAddVehicle, linkableFilter]);

  useEffect(() => {
    setDeviceOffset(0);
  }, [devicePageSize]);

  useEffect(() => {
    if (dataRefreshTick === lastToolbarRefreshTick.current) return;
    lastToolbarRefreshTick.current = dataRefreshTick;
    if (dataRefreshTick > 0) reloadFleet();
  }, [dataRefreshTick, reloadFleet]);

  const emptyNewDevice = () => ({
    imei: '',
    iccid: '',
    phone_number: '',
    device_model: '',
    notes: '',
    desired_config_json: '',
    firmware: '',
    config_profile: 'Standard',
  });

  const openActivateDeviceModal = async () => {
    setFleetMsg('');
    setFleetMsgSuccess(false);
    let row: (typeof devices)[number] | null = null;
    if (fleetDetail?.kind === 'device') {
      row = compact(devices).find((x) => x.imei === fleetDetail.imei) ?? null;
      if (!row) {
        const res = await api(`/api/fleet/devices/${encodeURIComponent(fleetDetail.imei)}/detail`);
        if (res.ok) {
          const j = await parseFetchJson<{ device?: Record<string, unknown> }>(res);
          row = (j.device ?? null) as (typeof devices)[number] | null;
        }
      }
    }
    if (!row && selectedImeis.length === 1) {
      const one = selectedImeis[0]!;
      row = compact(devices).find((x) => x.imei === one) ?? null;
      if (!row) {
        const res = await api(`/api/fleet/devices/${encodeURIComponent(one)}/detail`);
        if (res.ok) {
          const j = await parseFetchJson<{ device?: Record<string, unknown> }>(res);
          row = (j.device ?? null) as (typeof devices)[number] | null;
        }
      }
    }
    setNewDevice(row ? fleetDeviceToActivateForm(row) : emptyNewDevice());
    setActivatePrefilled(!!row);
    setShowAddDevice(true);
  };

  const handleAddDevice = async (e: React.FormEvent) => {
    e.preventDefault();
    setFleetMsg('');
    setFleetMsgSuccess(false);
    let desired: Record<string, unknown> = {};
    if (newDevice.desired_config_json.trim()) {
      try {
        desired = JSON.parse(newDevice.desired_config_json) as Record<string, unknown>;
      } catch {
        setFleetMsg(t('fleet.invalidDesiredJson'));
        setFleetMsgSuccess(false);
        return;
      }
    }
    const res = await api('/api/fleet/devices', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        imei: newDevice.imei,
        iccid: newDevice.iccid,
        phone_number: newDevice.phone_number,
        config_profile: newDevice.config_profile,
        device_model: newDevice.device_model,
        notes: newDevice.notes,
        firmware: newDevice.firmware || undefined,
        desired_config: Object.keys(desired).length ? desired : undefined,
      }),
    });
    if (!res.ok) {
      const d = await readJsonLoose<{ error?: string }>(res);
      const apiErr = (d as { error?: string }).error;
      if (apiErr) setFleetMsg(apiErr);
      else if (res.status === 502) setFleetMsg(t('apiErrors.badGateway'));
      else if (res.status === 503) setFleetMsg(t('apiErrors.serviceUnavailable'));
      else if (res.status === 504) setFleetMsg(t('apiErrors.gatewayTimeout'));
      else if (res.status >= 500) setFleetMsg(t('apiErrors.serverError'));
      else setFleetMsg(res.statusText);
      setFleetMsgSuccess(false);
      return;
    }
    setShowAddDevice(false);
    setActivatePrefilled(false);
    reloadFleet();
    setNewDevice(emptyNewDevice());
  };

  const runBulkPreview = async () => {
    setFleetMsg('');
    setFleetMsgSuccess(false);
    try {
      const r = await apiJson<{ rows?: unknown[]; parseErrors?: string[]; warnings?: string[] }>(
        '/api/fleet/devices/import-csv',
        { csv: bulkCsv, dryRun: true }
      );
      setBulkPreview(JSON.stringify(r, null, 2));
    } catch (e) {
      setBulkPreview(e instanceof Error ? e.message : 'Error');
    }
  };

  const runBulkImport = async () => {
    setFleetMsg('');
    setFleetMsgSuccess(false);
    try {
      await apiJson('/api/fleet/devices/import-csv', { csv: bulkCsv });
      setShowBulkImport(false);
      setBulkCsv('');
      setBulkPreview('');
      reloadFleet();
    } catch (e) {
      setFleetMsg(e instanceof Error ? e.message : 'Error');
      setFleetMsgSuccess(false);
    }
  };

  const applyBulkProfile = async () => {
    if (!bulkProfile || selectedImeis.length === 0) return;
    setFleetMsg('');
    setFleetMsgSuccess(false);
    try {
      await apiJson(
        '/api/fleet/devices/bulk-profile',
        { imeis: selectedImeis, config_profile: bulkProfile },
        { method: 'PATCH' }
      );
      reloadFleet();
    } catch (e) {
      setFleetMsg(e instanceof Error ? e.message : 'Error');
      setFleetMsgSuccess(false);
    }
  };

  const bulkDeleteSelected = async () => {
    if (selectedImeis.length === 0) return;
    const n = selectedImeis.length;
    if (!window.confirm(t('fleet.bulkDeleteConfirm', { count: n }))) return;
    setFleetMsg('');
    setFleetMsgSuccess(false);
    try {
      const r = await apiJson<{ deleted?: number }>('/api/fleet/devices/bulk-delete', { imeis: selectedImeis }, { method: 'POST' });
      setSelectedImeis([]);
      setFleetMsg(t('fleet.bulkDeleteSuccess', { count: r.deleted ?? n }));
      setFleetMsgSuccess(true);
      reloadFleet();
    } catch (e) {
      setFleetMsg(e instanceof Error ? e.message : 'Error');
      setFleetMsgSuccess(false);
    }
  };

  const exportInstructions = async () => {
    if (selectedImeis.length === 0) return;
    setFleetMsg('');
    setFleetMsgSuccess(false);
    const res = await api('/api/fleet/devices/export-instructions', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ imeis: selectedImeis }),
    });
    if (!res.ok) {
      setFleetMsg(await res.text());
      setFleetMsgSuccess(false);
      return;
    }
    const blob = await res.blob();
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'teltonika-operator-instructions.txt';
    a.click();
    URL.revokeObjectURL(url);
  };

  const saveEditDevice = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!editDevice) return;
    setFleetMsg('');
    setFleetMsgSuccess(false);
    let desired: Record<string, unknown> = {};
    if (String(editDevice.desired_config_json ?? '').trim()) {
      try {
        desired = JSON.parse(editDevice.desired_config_json) as Record<string, unknown>;
      } catch {
        setFleetMsg(t('fleet.invalidDesiredJson'));
        setFleetMsgSuccess(false);
        return;
      }
    }
    try {
      await apiJson(
        `/api/fleet/devices/${encodeURIComponent(editDevice.imei)}`,
        {
          iccid: editDevice.iccid,
          phone_number: editDevice.phone_number,
          firmware: editDevice.firmware,
          config_profile: editDevice.config_profile,
          device_model: editDevice.device_model,
          notes: editDevice.notes,
          desired_config: desired,
        },
        { method: 'PUT' }
      );
      setEditDevice(null);
      reloadFleet();
    } catch (e) {
      setFleetMsg(e instanceof Error ? e.message : 'Error');
      setFleetMsgSuccess(false);
    }
  };

  const handleAddVehicle = async (e: React.FormEvent) => {
    e.preventDefault();
    await api('/api/fleet/buses', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(newVehicle),
    });
    setShowAddVehicle(false);
    setLinkableFilter('');
    reloadFleet();
    setNewVehicle({ license_plate: '', vin: '', make_model: '', capacity: 50, school_id: schools[0]?.id || '', imei: '' });
  };

  const toggleSelect = (imei: string) => {
    setSelectedImeis((s) => (s.includes(imei) ? s.filter((x) => x !== imei) : [...s, imei]));
  };

  const selectAllDevices = () => {
    const devs = compact(devices);
    if (devs.length === 0) return;
    if (fleetPageFullySelected(selectedImeis, devices)) {
      const pageImeis = new Set(devs.map((d) => String(d.imei ?? '').trim()).filter(Boolean));
      setSelectedImeis((prev) => prev.filter((imei) => !pageImeis.has(imei)));
      setFleetMsg('');
      return;
    }
    setSelectedImeis((prev) => {
      const next = new Set(prev);
      for (const d of devs) {
        const im = String(d.imei ?? '').trim();
        if (im) next.add(im);
      }
      return Array.from(next);
    });
    setFleetMsg('');
    setFleetMsgSuccess(false);
  };

  return (
    <div className="relative flex-1 overflow-y-auto overscroll-y-contain bg-slate-50 p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4 md:p-6">
      {fleetDetail ? (
        <FleetFullDetailOverlay
          detail={fleetDetail}
          schools={schools}
          buses={buses}
          detailNonce={fleetDetailNonce}
          onClose={() => setFleetDetail(null)}
          onNavigate={(d) => setFleetDetail(d)}
          onFleetMutate={() => {
            reloadFleet();
            setFleetDetailNonce((n) => n + 1);
          }}
          onOpenActivatePrefill={(device) => {
            setFleetMsg('');
            setFleetMsgSuccess(false);
            setNewDevice(fleetDeviceToActivateForm(device));
            setActivatePrefilled(true);
            setFleetDetail(null);
            setShowAddDevice(true);
          }}
        />
      ) : null}
      <div className="mb-4 flex flex-col gap-3 sm:mb-6 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between">
        <h2 className="flex items-center gap-2 text-lg font-bold sm:text-xl">
          <Truck className="h-6 w-6 shrink-0 text-indigo-600" /> {t('fleet.title')}
        </h2>
        <div className="flex flex-wrap items-center gap-2">
          <button
            type="button"
            onClick={() => {
              reloadFleet();
              onRefresh();
            }}
            className="flex min-h-10 items-center gap-2 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50"
            title={t('common.refresh')}
            aria-label={t('common.refresh')}
          >
            <RefreshCw className="h-4 w-4 shrink-0" aria-hidden />
            <span className="hidden sm:inline">{t('common.refresh')}</span>
          </button>
          <div className="flex rounded-lg bg-slate-200 p-1">
          <button
            type="button"
            onClick={() => setActiveTab('vehicles')}
            className={`min-h-9 rounded-md px-3 py-2 text-xs font-bold transition-all sm:px-4 sm:py-1.5 sm:text-sm ${activeTab === 'vehicles' ? 'bg-white text-slate-800 shadow-sm' : 'text-slate-500'}`}
          >
            {t('fleet.vehicles')}
          </button>
          <button
            type="button"
            onClick={() => setActiveTab('devices')}
            className={`min-h-9 rounded-md px-3 py-2 text-xs font-bold transition-all sm:px-4 sm:py-1.5 sm:text-sm ${activeTab === 'devices' ? 'bg-white text-slate-800 shadow-sm' : 'text-slate-500'}`}
          >
            {t('fleet.devices')}
          </button>
          </div>
        </div>
      </div>

      {SHOW_FLEET_TELEMATICS_BANNER ? (
        <div className="mb-4 rounded-xl border border-sky-200 bg-sky-50/90 p-3 text-sm text-slate-700 shadow-sm sm:mb-6 sm:p-4">
          <h3 className="font-bold text-slate-900 flex gap-2 items-center mb-2">
            <Radio className="w-5 h-5 text-sky-700 shrink-0" aria-hidden />
            {t('fleet.telematicsInfoTitle')}
          </h3>
          <p className="mb-2 leading-relaxed">{t('fleet.telematicsInfoP1')}</p>
          <p className="mb-2 leading-relaxed">{t('fleet.telematicsInfoP2')}</p>
          <p className="text-xs text-slate-600 leading-relaxed border-t border-sky-200/80 pt-2 mt-2">{t('fleet.telematicsInfoP3')}</p>
          <p className="text-xs text-slate-600 leading-relaxed mt-2">{t('fleet.telematicsInfoP4')}</p>
        </div>
      ) : null}

      {activeTab === 'devices' && (
        <div className="space-y-4">
          {fleetMsg ? (
            <div
              className={`text-sm rounded-lg px-3 py-2 border ${
                fleetMsgSuccess ? 'text-emerald-800 bg-emerald-50 border-emerald-100' : 'text-red-600 bg-red-50 border-red-100'
              }`}
            >
              {fleetMsg}
            </div>
          ) : null}
          <div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
            <div className="p-4 border-b border-slate-100 flex flex-wrap justify-between items-center gap-2 bg-slate-50">
              <h3 className="font-bold text-slate-700 flex gap-2 items-center">
                <Cpu className="w-4 h-4" /> {t('fleet.inventory')}
              </h3>
              <div className="flex flex-wrap gap-2">
                <button
                  type="button"
                  onClick={() => {
                    setFleetMsg('');
                    setFleetMsgSuccess(false);
                    setShowBulkImport(true);
                  }}
                  className="px-3 py-1.5 bg-slate-700 text-white text-xs font-bold rounded flex gap-1 items-center"
                >
                  <FileUp className="w-3 h-3" /> {t('fleet.bulkImport')}
                </button>
                <button
                  type="button"
                  onClick={() => void exportInstructions()}
                  disabled={selectedImeis.length === 0}
                  className="px-3 py-1.5 bg-emerald-600 text-white text-xs font-bold rounded flex gap-1 items-center disabled:opacity-40"
                >
                  <Download className="w-3 h-3" /> {t('fleet.exportInstructions')}
                </button>
                <button type="button" onClick={() => void openActivateDeviceModal()} className="px-3 py-1.5 bg-blue-500 text-white text-xs font-bold rounded flex gap-1 items-center">
                  <PlusCircle className="w-3 h-3" /> {t('fleet.activateDevice')}
                </button>
              </div>
            </div>
            <div className="p-3 border-b border-slate-100 flex flex-wrap items-center gap-2 bg-white text-xs">
              <span className="text-slate-500 font-medium">{t('fleet.bulkProfile')}</span>
              <select
                className="border rounded px-2 py-1 text-xs"
                value={bulkProfile}
                onChange={(e) => setBulkProfile(e.target.value)}
              >
                <option value="">{t('fleet.pickProfile')}</option>
                <option value="Standard">Standard</option>
                <option value="EcoDrive_v2">EcoDrive v2</option>
                <option value="HeavyDuty">HeavyDuty</option>
                <option value="unknown">{t('fleet.profileUnknown')}</option>
              </select>
              <button
                type="button"
                disabled={selectedImeis.length === 0 || !bulkProfile}
                onClick={() => void applyBulkProfile()}
                className="px-2 py-1 bg-indigo-600 text-white rounded font-bold disabled:opacity-40"
              >
                {t('fleet.applyToSelected')}
              </button>
              <button
                type="button"
                disabled={selectedImeis.length === 0}
                onClick={() => void bulkDeleteSelected()}
                className="px-2 py-1 bg-red-600 text-white rounded font-bold flex items-center gap-1 disabled:opacity-40"
              >
                <Trash2 className="w-3 h-3 shrink-0" aria-hidden />
                {t('fleet.bulkDeleteSelected')}
              </button>
              <button type="button" onClick={selectAllDevices} className="text-indigo-600 font-bold underline">
                {fleetPageFullySelected(selectedImeis, devices) ? t('fleet.deselectAll') : t('fleet.selectAll')}
              </button>
            </div>
            <div className="px-3 py-2 border-b border-slate-100 flex flex-wrap items-end gap-3 bg-slate-50/90">
              <div className="flex-1 min-w-[12rem]">
                <label className="block text-[10px] font-bold text-slate-500 uppercase mb-0.5">{t('fleet.inventorySearch')}</label>
                <input
                  type="search"
                  className="w-full border border-slate-200 rounded px-2 py-1.5 text-xs"
                  placeholder={t('fleet.inventorySearchPlaceholder')}
                  value={deviceSearchInput}
                  onChange={(e) => setDeviceSearchInput(e.target.value)}
                  autoComplete="off"
                />
              </div>
              <div>
                <label className="block text-[10px] font-bold text-slate-500 uppercase mb-0.5">{t('fleet.inventoryPageSize')}</label>
                <select
                  className="border border-slate-200 rounded px-2 py-1.5 text-xs"
                  value={devicePageSize}
                  onChange={(e) => setDevicePageSize(parseInt(e.target.value, 10) || 100)}
                >
                  <option value={50}>50</option>
                  <option value={100}>100</option>
                  <option value={150}>150</option>
                  <option value={250}>250</option>
                </select>
              </div>
              <div className="text-xs text-slate-600 ms-auto flex flex-wrap items-center gap-2">
                <span>
                  {t('fleet.inventoryPaginationSummary', {
                    start: deviceTotal === 0 ? 0 : deviceOffset + 1,
                    end: deviceOffset + compact(devices).length,
                    total: deviceTotal,
                  })}
                </span>
                <button
                  type="button"
                  disabled={deviceOffset === 0}
                  onClick={() => setDeviceOffset(Math.max(0, deviceOffset - devicePageSize))}
                  className="px-2 py-1 rounded border border-slate-200 bg-white disabled:opacity-40"
                >
                  {t('fleet.inventoryPrev')}
                </button>
                <button
                  type="button"
                  disabled={deviceOffset + devicePageSize >= deviceTotal}
                  onClick={() => setDeviceOffset(deviceOffset + devicePageSize)}
                  className="px-2 py-1 rounded border border-slate-200 bg-white disabled:opacity-40"
                >
                  {t('fleet.inventoryNext')}
                </button>
              </div>
            </div>
            <div className="max-h-[min(70dvh,720px)] overflow-x-auto overflow-y-auto overscroll-contain">
              <table className="w-full min-w-[720px] text-left text-sm">
              <thead className="bg-slate-50 text-slate-500 border-b border-slate-200">
                <tr>
                  <th className="p-2 w-8">
                    <input
                      type="checkbox"
                      aria-label={t('fleet.selectAll')}
                      checked={compact(devices).length > 0 && fleetPageFullySelected(selectedImeis, devices)}
                      onChange={selectAllDevices}
                    />
                  </th>
                  <th className="p-3">{t('fleet.imei')}</th>
                  <th className="p-3">{t('fleet.linkedVehicleCol')}</th>
                  <th className="p-3">{t('fleet.deviceModel')}</th>
                  <th className="p-3">{t('fleet.iccid')} / {t('fleet.phone')}</th>
                  <th className="p-3">{t('fleet.profile')}</th>
                  <th className="p-3">{t('students.status')}</th>
                  <th className="p-3">{t('fleet.lastPing')}</th>
                  <th className="p-2 w-12 text-center" title={t('fleet.showOnMap')}>
                    <MapPin className="w-4 h-4 inline text-slate-500" aria-hidden />
                    <span className="sr-only">{t('fleet.showOnMap')}</span>
                  </th>
                  <th className="p-3 w-10" />
                </tr>
              </thead>
              <tbody>
                {compact(devices).map((d) => (
                  <tr
                    key={d.imei}
                    className={`border-b border-slate-100 last:border-0 hover:bg-slate-50 text-xs cursor-pointer ${
                      String(d.config_profile || '').toLowerCase() === 'unknown' ? 'bg-amber-50/60' : ''
                    }`}
                    onClick={() => setFleetDetail({ kind: 'device', imei: d.imei })}
                  >
                    <td className="p-2" onClick={(e) => e.stopPropagation()}>
                      <input type="checkbox" checked={selectedImeis.includes(d.imei)} onChange={() => toggleSelect(d.imei)} />
                    </td>
                    <td className="p-3 font-mono text-slate-700">
                      {d.imei}
                      {String(d.config_profile || '').toLowerCase() === 'unknown' ? (
                        <span className="ml-2 text-[10px] font-bold uppercase align-middle bg-amber-100 text-amber-900 px-1.5 py-0.5 rounded border border-amber-200">
                          {t('fleet.discoveredBadge')}
                        </span>
                      ) : null}
                    </td>
                    <td className="p-3 text-slate-600">
                      {d.linked_bus_id ? (
                        <button
                          type="button"
                          className="text-indigo-600 font-bold underline text-left"
                          onClick={(e) => {
                            e.stopPropagation();
                            setFleetDetail({ kind: 'bus', id: d.linked_bus_id });
                          }}
                        >
                          {d.linked_license_plate || d.linked_bus_id}
                        </button>
                      ) : (
                        '—'
                      )}
                    </td>
                    <td className="p-3 text-slate-600">{d.device_model || '—'}</td>
                    <td className="p-3 text-slate-600">
                      {d.iccid}
                      <br />
                      <span className="text-slate-400">{d.phone_number}</span>
                    </td>
                    <td className="p-3">
                      <span className="bg-slate-100 px-2 py-0.5 rounded text-slate-600 border border-slate-200">{d.config_profile}</span>
                      <span className="text-[10px] text-slate-400 block mt-1">FW: {d.firmware}</span>
                    </td>
                    <td className="p-3">
                      {d.status === 'online' ? (
                        <span className="text-green-600 font-bold flex gap-1 items-center">
                          <Activity className="w-3 h-3" /> {t('fleet.online')}
                        </span>
                      ) : (
                        <span className="text-orange-500 font-bold flex gap-1 items-center">
                          <XCircle className="w-3 h-3" /> {t('fleet.offline')}
                        </span>
                      )}
                    </td>
                    <td className="p-3 font-mono text-slate-500">{d.last_ping ? new Date(d.last_ping).toLocaleTimeString() : '—'}</td>
                    <td className="p-2 text-center" onClick={(e) => e.stopPropagation()}>
                      <button
                        type="button"
                        title={t('fleet.showOnMap')}
                        onClick={() => {
                          if (d.linked_bus_id) {
                            const bus = compact(buses).find((x) => x.id === d.linked_bus_id);
                            onShowBusOnMap(
                              String(d.linked_bus_id),
                              bus?.location?.lat ?? d.map_lat ?? null,
                              bus?.location?.lng ?? d.map_lng ?? null
                            );
                            return;
                          }
                          const la = Number(d.map_lat);
                          const ln = Number(d.map_lng);
                          if (!Number.isFinite(la) || !Number.isFinite(ln)) {
                            window.alert(t('fleet.showOnMapNoPosition'));
                            return;
                          }
                          onShowDeviceGpsOnMap(la, ln, `${t('fleet.imei')}: ${d.imei}`);
                        }}
                        className="p-1.5 rounded hover:bg-slate-200 text-indigo-600"
                      >
                        <MapPin className="w-4 h-4" />
                      </button>
                    </td>
                    <td className="p-2" onClick={(e) => e.stopPropagation()}>
                      <button
                        type="button"
                        onClick={() =>
                          setEditDevice({
                            ...d,
                            desired_config_json: (() => {
                              try {
                                const dc = d.desired_config;
                                if (dc == null) return '{}';
                                if (typeof dc === 'string') return JSON.stringify(JSON.parse(dc), null, 2);
                                if (typeof dc === 'object') return JSON.stringify(dc, null, 2);
                                return '{}';
                              } catch {
                                return '{}';
                              }
                            })(),
                          })
                        }
                        className="p-1.5 rounded hover:bg-slate-200 text-slate-600"
                        title={t('fleet.editDevice')}
                      >
                        <Pencil className="w-4 h-4" />
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
            </div>
          </div>
        </div>
      )}

      {activeTab === 'vehicles' && (
        <div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
          <div className="flex flex-wrap items-center justify-between gap-2 border-b border-slate-100 bg-slate-50 p-3 sm:p-4">
            <h3 className="font-bold text-slate-700 flex gap-2 items-center">
              <Truck className="w-4 h-4" /> {t('fleet.vehicles')}
            </h3>
            <button
              type="button"
              onClick={() => {
                setLinkableFilter('');
                setShowAddVehicle(true);
              }}
              className="flex min-h-9 items-center gap-1 rounded bg-blue-500 px-2 py-2 text-xs font-bold text-white sm:px-3 sm:py-1.5"
            >
              <PlusCircle className="h-3 w-3 shrink-0" /> {t('fleet.addVehicle')}
            </button>
          </div>
          <div className="overflow-x-auto overscroll-x-contain">
          <table className="w-full min-w-[560px] text-left text-sm">
            <thead className="bg-slate-50 text-slate-500 border-b border-slate-200">
              <tr>
                <th className="p-3">{t('fleet.plate')}</th>
                <th className="p-3">{t('fleet.vin')}</th>
                <th className="p-3">IMEI</th>
                <th className="p-3">{t('students.school')}</th>
                <th className="p-3">{t('fleet.capacity')}</th>
                <th className="p-2 w-12 text-center" title={t('fleet.showOnMap')}>
                  <MapPin className="w-4 h-4 inline text-slate-500" aria-hidden />
                  <span className="sr-only">{t('fleet.showOnMap')}</span>
                </th>
              </tr>
            </thead>
            <tbody>
              {compact(buses).map((b) => {
                const school = schools.find((s) => s.id === b.school_id);
                return (
                  <tr
                    key={b.id}
                    className="border-b border-slate-100 last:border-0 hover:bg-slate-50 text-xs cursor-pointer"
                    onClick={() => setFleetDetail({ kind: 'bus', id: b.id })}
                  >
                    <td className="p-3">
                      <div className="font-bold text-slate-800">{b.license_plate}</div>
                      <div className="text-[10px] text-slate-500">{b.make_model}</div>
                    </td>
                    <td className="p-3 font-mono text-slate-500">{b.vin}</td>
                    <td className="p-3">
                      <span className="bg-indigo-50 text-indigo-700 px-2 py-0.5 rounded font-mono border border-indigo-100 inline-flex items-center gap-1">
                        <Database className="w-3 h-3" /> {b.imei}
                      </span>
                    </td>
                    <td className="p-3 text-slate-600 font-medium">{school?.name}</td>
                    <td className="p-3">{b.capacity}</td>
                    <td className="p-2 text-center" onClick={(e) => e.stopPropagation()}>
                      <button
                        type="button"
                        title={t('fleet.showOnMap')}
                        onClick={() =>
                          onShowBusOnMap(String(b.id), b.location?.lat ?? b.lat ?? null, b.location?.lng ?? b.lng ?? null)
                        }
                        className="p-1.5 rounded hover:bg-slate-200 text-indigo-600"
                      >
                        <MapPin className="w-4 h-4" />
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          </div>
        </div>
      )}

      {showBulkImport && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 backdrop-blur-sm sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,900px)] w-full max-w-2xl overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-2xl sm:rounded-xl sm:p-6">
            <h3 className="font-bold text-lg mb-2 flex gap-2 items-center">
              <FileUp className="w-5 h-5 text-slate-700" /> {t('fleet.bulkImportTitle')}
            </h3>
            <p className="text-xs text-slate-500 mb-3">{t('fleet.bulkImportHint')}</p>
            <textarea
              className="w-full border rounded p-2 font-mono text-xs min-h-[140px]"
              placeholder="imei,iccid,phone,model,firmware,profile"
              value={bulkCsv}
              onChange={(e) => setBulkCsv(e.target.value)}
            />
            <div className="flex flex-wrap gap-2 mt-3">
              <button type="button" onClick={() => void runBulkPreview()} className="px-3 py-2 bg-slate-200 rounded text-sm font-bold">
                {t('fleet.preview')}
              </button>
              <button type="button" onClick={() => void runBulkImport()} className="px-3 py-2 bg-blue-600 text-white rounded text-sm font-bold">
                {t('fleet.importRun')}
              </button>
              <button
                type="button"
                onClick={() => {
                  setShowBulkImport(false);
                  setBulkCsv('');
                  setBulkPreview('');
                }}
                className="px-3 py-2 bg-slate-100 rounded text-sm font-bold"
              >
                {t('common.cancel')}
              </button>
            </div>
            {bulkPreview ? (
              <pre className="mt-4 text-[11px] bg-slate-900 text-slate-100 p-3 rounded overflow-x-auto max-h-48 overflow-y-auto">{bulkPreview}</pre>
            ) : null}
          </div>
        </div>
      )}

      {editDevice && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 backdrop-blur-sm sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,880px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-2xl sm:rounded-xl sm:p-6">
            <h3 className="font-bold text-lg mb-4 flex gap-2 items-center">
              <Pencil className="w-5 h-5 text-indigo-500" /> {t('fleet.editDevice')} — {editDevice.imei}
            </h3>
            <form onSubmit={(e) => void saveEditDevice(e)} className="space-y-3">
              <input className="w-full border rounded p-2 font-mono text-sm" placeholder={t('fleet.iccid')} value={editDevice.iccid || ''} onChange={(e) => setEditDevice({ ...editDevice, iccid: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.phone')} value={editDevice.phone_number || ''} onChange={(e) => setEditDevice({ ...editDevice, phone_number: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.deviceModel')} value={editDevice.device_model || ''} onChange={(e) => setEditDevice({ ...editDevice, device_model: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.firmware')} value={editDevice.firmware || ''} onChange={(e) => setEditDevice({ ...editDevice, firmware: e.target.value })} />
              <select className="w-full border rounded p-2 text-sm" value={editDevice.config_profile || 'Standard'} onChange={(e) => setEditDevice({ ...editDevice, config_profile: e.target.value })}>
                <option value="Standard">Standard</option>
                <option value="EcoDrive_v2">EcoDrive v2</option>
                <option value="HeavyDuty">HeavyDuty</option>
              </select>
              <textarea className="w-full border rounded p-2 text-xs min-h-[60px]" placeholder={t('fleet.notes')} value={editDevice.notes || ''} onChange={(e) => setEditDevice({ ...editDevice, notes: e.target.value })} />
              <textarea
                className="w-full border rounded p-2 font-mono text-[11px] min-h-[100px]"
                placeholder={t('fleet.desiredConfigPlaceholder')}
                value={editDevice.desired_config_json}
                onChange={(e) => setEditDevice({ ...editDevice, desired_config_json: e.target.value })}
              />
              <div className="flex gap-3 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button type="button" onClick={() => setEditDevice(null)} className="min-h-11 flex-1 rounded bg-slate-100 p-3 text-sm font-bold sm:min-h-0 sm:p-2">
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-indigo-600 p-3 text-sm font-bold text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {showAddDevice && (
        <div className="absolute inset-0 z-[1100] flex items-end justify-center bg-slate-900/40 p-0 backdrop-blur-sm sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,880px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-2xl sm:rounded-xl sm:p-6">
            <div className="mb-4">
              <h3 className="font-bold text-lg flex gap-2 items-center">
                <Cpu className="w-5 h-5 text-blue-500" /> {t('fleet.registerDevice')}
              </h3>
              {activatePrefilled ? (
                <p className="text-xs text-slate-500 mt-2 leading-relaxed">{t('fleet.activatePrefilledHint')}</p>
              ) : null}
            </div>
            <form onSubmit={handleAddDevice} className="space-y-3">
              <input required className="w-full border rounded p-2 font-mono text-sm" placeholder={t('fleet.imei')} value={newDevice.imei} onChange={(e) => setNewDevice({ ...newDevice, imei: e.target.value })} />
              <input required className="w-full border rounded p-2 font-mono text-sm" placeholder={t('fleet.iccid')} value={newDevice.iccid} onChange={(e) => setNewDevice({ ...newDevice, iccid: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.phone')} value={newDevice.phone_number} onChange={(e) => setNewDevice({ ...newDevice, phone_number: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.deviceModel')} value={newDevice.device_model} onChange={(e) => setNewDevice({ ...newDevice, device_model: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.firmware')} value={newDevice.firmware} onChange={(e) => setNewDevice({ ...newDevice, firmware: e.target.value })} />
              <select className="w-full border rounded p-2 text-sm" value={newDevice.config_profile} onChange={(e) => setNewDevice({ ...newDevice, config_profile: e.target.value })}>
                <option value="Standard">Standard</option>
                <option value="EcoDrive_v2">EcoDrive v2</option>
                <option value="HeavyDuty">HeavyDuty</option>
                <option value="unknown">{t('fleet.profileUnknown')}</option>
              </select>
              <textarea className="w-full border rounded p-2 text-xs min-h-[50px]" placeholder={t('fleet.notes')} value={newDevice.notes} onChange={(e) => setNewDevice({ ...newDevice, notes: e.target.value })} />
              <textarea
                className="w-full border rounded p-2 font-mono text-[11px] min-h-[80px]"
                placeholder={t('fleet.desiredConfigPlaceholder')}
                value={newDevice.desired_config_json}
                onChange={(e) => setNewDevice({ ...newDevice, desired_config_json: e.target.value })}
              />
              <div className="flex gap-3 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button
                  type="button"
                  onClick={() => {
                    setShowAddDevice(false);
                    setActivatePrefilled(false);
                    setNewDevice(emptyNewDevice());
                  }}
                  className="min-h-11 flex-1 rounded bg-slate-100 p-3 text-sm font-bold sm:min-h-0 sm:p-2"
                >
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-blue-500 p-3 text-sm font-bold text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {showAddVehicle && (
        <div className="absolute inset-0 z-[999] flex items-end justify-center bg-slate-900/40 p-0 backdrop-blur-sm sm:items-center sm:p-4">
          <div className="max-h-[min(92dvh,800px)] w-full max-w-md overflow-y-auto overscroll-y-contain rounded-t-2xl bg-white p-4 shadow-2xl sm:rounded-xl sm:p-6">
            <h3 className="font-bold text-lg mb-4 flex gap-2 items-center">
              <Truck className="w-5 h-5 text-indigo-500" /> {t('fleet.vehicleTitle')}
            </h3>
            <form onSubmit={handleAddVehicle} className="space-y-4">
              <input required className="w-full border rounded p-2 text-sm" placeholder={t('fleet.plate')} value={newVehicle.license_plate} onChange={(e) => setNewVehicle({ ...newVehicle, license_plate: e.target.value })} />
              <input className="w-full border rounded p-2 text-sm" placeholder={t('fleet.model')} value={newVehicle.make_model} onChange={(e) => setNewVehicle({ ...newVehicle, make_model: e.target.value })} />
              <input required className="w-full border rounded p-2 font-mono text-sm" placeholder={t('fleet.vin')} value={newVehicle.vin} onChange={(e) => setNewVehicle({ ...newVehicle, vin: e.target.value })} />
              <div className="flex gap-2">
                <input required type="number" className="w-1/2 border rounded p-2 text-sm" placeholder={t('fleet.capacity')} value={newVehicle.capacity} onChange={(e) => setNewVehicle({ ...newVehicle, capacity: parseInt(e.target.value, 10) || 0 })} />
                <select className="w-1/2 border rounded p-2 text-sm" value={newVehicle.school_id} onChange={(e) => setNewVehicle({ ...newVehicle, school_id: e.target.value })}>
                  {compact(schools).map((s) => (
                    <option key={s.id} value={s.id}>
                      {s.name}
                    </option>
                  ))}
                </select>
              </div>
              <div className="p-3 bg-indigo-50 border border-indigo-100 rounded-lg space-y-2">
                <label className="block text-xs font-bold text-indigo-800">{t('fleet.linkTracker')}</label>
                <input
                  type="search"
                  className="w-full border border-indigo-200 rounded p-2 text-xs font-mono bg-white"
                  placeholder={t('fleet.linkableFilterPlaceholder')}
                  value={linkableFilter}
                  onChange={(e) => setLinkableFilter(e.target.value)}
                />
                <p className="text-[10px] text-indigo-800/90 leading-snug">{t('fleet.linkableHint')}</p>
                <select required className="w-full border border-indigo-200 rounded p-2 text-xs font-mono bg-white" value={newVehicle.imei} onChange={(e) => setNewVehicle({ ...newVehicle, imei: e.target.value })}>
                  <option value="">— {t('fleet.selectImei')} —</option>
                  {compact(linkableDevices).map((d) => (
                    <option key={d.imei} value={d.imei}>
                      {d.imei}
                      {d.device_model ? ` · ${d.device_model}` : ''}
                    </option>
                  ))}
                </select>
              </div>
              <div className="flex gap-3 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]">
                <button
                  type="button"
                  onClick={() => {
                    setShowAddVehicle(false);
                    setLinkableFilter('');
                  }}
                  className="min-h-11 flex-1 rounded bg-slate-100 p-3 text-sm font-bold sm:min-h-0 sm:p-2"
                >
                  {t('common.cancel')}
                </button>
                <button type="submit" className="min-h-11 flex-1 rounded bg-indigo-600 p-3 text-sm font-bold text-white sm:min-h-0 sm:p-2">
                  {t('common.save')}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}
    </div>
  );
}

async function requestDeleteMyAccount(t: TFunction, onDeleted: () => void) {
  if (!window.confirm(t('legal.deleteAccountConfirm'))) return;
  try {
    const res = await api('/api/auth/me', { method: 'DELETE' });
    const data = (await readJsonLoose(res)) as { code?: string };
    if (!res.ok) {
      if (data.code === 'BOOTSTRAP_ACCOUNT') alert(t('legal.deleteAccountBootstrapBlocked'));
      else if (data.code === 'PROTECTED_ACCOUNT') alert(t('legal.deleteAccountProtected'));
      else alert(t('legal.deleteAccountFailed'));
      return;
    }
    onDeleted();
    alert(t('legal.deleteAccountSuccess'));
  } catch {
    alert(t('legal.deleteAccountFailed'));
  }
}

function Dashboard({ user, onLogout }: { user: User; onLogout: () => void }) {
  const { t } = useTranslation();
  const [activeTab, setActiveTab] = useState<
    | 'map'
    | 'students'
    | 'fleet'
    | 'users'
    | 'schools'
    | 'support'
    | 'supportdesk'
    | 'features'
    | 'parentWallet'
    | 'parentLine'
    | 'parentNotifs'
  >('map');
  const [buses, setBuses] = useState<any[]>([]);
  const busesRef = React.useRef<any[]>([]);
  const [activeRouteBusId, setActiveRouteBusId] = useState<string | null>(null);
  const [followLiveBusId, setFollowLiveBusId] = useState<string | null>(null);
  const [detailedRoutes, setDetailedRoutes] = useState<Record<string, [number, number][]>>({});
  const [notifications, setNotifications] = useState<any[]>([]);
  const [showNotif, setShowNotif] = useState(false);
  const [tpNotices, setTpNotices] = useState<any[]>([]);
  const [pwStudentId, setPwStudentId] = useState('');
  const [pwAmount, setPwAmount] = useState('');
  const [plSchoolId, setPlSchoolId] = useState('');
  const [plStudentId, setPlStudentId] = useState('');
  const [plBusId, setPlBusId] = useState('');
  const [plNote, setPlNote] = useState('');
  const [walletUiTick, setWalletUiTick] = useState(0);
  const [parentWalletByStudent, setParentWalletByStudent] = useState<Record<string, unknown>>({});
  const [parentWalletLoading, setParentWalletLoading] = useState(false);
  const [myStudents, setMyStudents] = useState<any[]>([]);
  const [schools, setSchools] = useState<School[]>([]);
  const [mapShowSchools, setMapShowSchools] = useState(true);
  const [mapShowBuses, setMapShowBuses] = useState(true);
  const [mapShowStops, setMapShowStops] = useState(true);
  const [passengersModalBus, setPassengersModalBus] = useState<any | null>(null);
  const [mapFlyTo, setMapFlyTo] = useState<{ lat: number; lng: number; seq: number; zoom?: number } | null>(null);
  const [mapHighlightStudent, setMapHighlightStudent] = useState<{ lat: number; lng: number; name: string } | null>(null);
  const [mapSpotHighlight, setMapSpotHighlight] = useState<{ lat: number; lng: number; label: string } | null>(null);
  const [globalSearchQ, setGlobalSearchQ] = useState('');
  const [globalSearchResults, setGlobalSearchResults] = useState<GlobalSearchResult | null>(null);
  const [globalSearchLoading, setGlobalSearchLoading] = useState(false);
  const [nationalSearchOpen, setNationalSearchOpen] = useState(false);
  const nationalSearchBlurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const [dataRefreshTick, setDataRefreshTick] = useState(0);
  const [mobileNavOpen, setMobileNavOpen] = useState(false);

  const showUsersNav =
    !isGovernmentViewer(user.role) &&
    (userHas(user, 'users_update') || userHas(user, 'users_create') || userHas(user, 'users_delete'));
  const showSchoolsNav =
    userHas(user, 'schools_read') &&
    (!isGovernmentViewer(user.role)
      ? userHas(user, 'schools_update') || userHas(user, 'schools_create')
      : userHas(user, 'map_global_view'));
  const showFleetNav = !isGovernmentViewer(user.role) && userHas(user, 'fleet_read');
  const showSupportDeskNav = userHas(user, 'feedback_support_agent') && userHas(user, 'feedback_support_read_all');

  useEffect(() => {
    if (!showIdeasNav() && activeTab === 'features') setActiveTab('map');
  }, [activeTab]);

  const mapSchoolsWithCoords = useMemo(() => compact(schools).filter((sch) => schoolHasMapCoords(sch)), [schools]);

  const followLiveBus = useMemo(
    () => (followLiveBusId ? buses.find((b) => b.id === followLiveBusId) ?? null : null),
    [buses, followLiveBusId],
  );

  useEffect(() => {
    if (!followLiveBusId) return;
    if (!buses.some((b) => b.id === followLiveBusId)) setFollowLiveBusId(null);
  }, [buses, followLiveBusId]);

  useEffect(() => {
    if (!followLiveBusId) return;
    setActiveRouteBusId(followLiveBusId);
    setMapHighlightStudent(null);
    setMapSpotHighlight(null);
  }, [followLiveBusId]);

  const toggleFollowLiveBus = useCallback((busId: string) => {
    setFollowLiveBusId((current) => (current === busId ? null : busId));
  }, []);

  const canViewMapStops =
    isParentRole(user.role) || isStudentRole(user.role) || userHas(user, 'students_read');

  const mapActiveStudentStops = useMemo(
    () => myStudents.filter((s) => s.status === 'active' && studentPickupCoords(s) != null),
    [myStudents],
  );

  const showMapLayerPanel =
    activeTab === 'map' &&
    (mapSchoolsWithCoords.length > 0 || buses.length > 0 || mapActiveStudentStops.length > 0);

  const lineSchoolOptions = useMemo(() => {
    const ids = new Set(myStudents.map((s) => String(s.school_id)));
    return schools.filter((sch) => ids.has(String(sch.id)));
  }, [myStudents, schools]);

  const lineStudentsFiltered = useMemo(() => {
    if (!plSchoolId) return myStudents;
    return myStudents.filter((s) => String(s.school_id) === plSchoolId);
  }, [myStudents, plSchoolId]);

  const lineBusesFiltered = useMemo(() => {
    if (!plSchoolId) return [];
    return buses.filter((b) => String(b.school_id) === plSchoolId);
  }, [buses, plSchoolId]);

  React.useEffect(() => {
    busesRef.current = buses;
  }, [buses]);

  useEffect(() => {
    if (myStudents.length === 0) return;
    if (!pwStudentId || !myStudents.some((s) => String(s.id) === pwStudentId)) {
      setPwStudentId(String(myStudents[0].id));
    }
  }, [myStudents, pwStudentId]);

  useEffect(() => {
    if (myStudents.length === 0) return;
    if (!plSchoolId) setPlSchoolId(String(myStudents[0].school_id));
  }, [myStudents, plSchoolId]);

  useEffect(() => {
    if (!plSchoolId || myStudents.length === 0) return;
    const ok = myStudents.some((s) => String(s.school_id) === plSchoolId && String(s.id) === plStudentId);
    if (!ok) {
      const first = myStudents.find((s) => String(s.school_id) === plSchoolId);
      if (first) setPlStudentId(String(first.id));
    }
  }, [plSchoolId, plStudentId, myStudents]);

  useEffect(() => {
    if (activeTab !== 'parentWallet') return;
    if (!isParentRole(user.role) && !isStudentRole(user.role)) return;
    if (myStudents.length === 0) {
      setParentWalletByStudent({});
      setParentWalletLoading(false);
      return;
    }
    let alive = true;
    setParentWalletLoading(true);
    void Promise.all(
      myStudents.map((s) =>
        api(`/api/wallet/student/${encodeURIComponent(String(s.id))}`)
          .then((r) => parseFetchJson(r))
          .then((d) => [String(s.id), d] as const)
          .catch(() => null),
      ),
    ).then((rows) => {
      if (!alive) return;
      const m: Record<string, unknown> = {};
      for (const row of rows) {
        if (row) m[row[0]] = row[1];
      }
      setParentWalletByStudent(m);
      setParentWalletLoading(false);
    });
    return () => {
      alive = false;
    };
  }, [activeTab, myStudents, user.role, walletUiTick]);

  useEffect(() => {
    const mq = window.matchMedia('(min-width: 768px)');
    const onChange = () => {
      if (mq.matches) setMobileNavOpen(false);
    };
    mq.addEventListener('change', onChange);
    return () => mq.removeEventListener('change', onChange);
  }, []);

  useEffect(() => {
    if (!userHas(user, 'map_global_view') || activeTab !== 'map') return;
    const q = globalSearchQ.trim();
    if (q.length < 2) {
      setGlobalSearchResults(null);
      setGlobalSearchLoading(false);
      return;
    }
    setGlobalSearchLoading(true);
    const t = window.setTimeout(() => {
      api('/api/fleet/global-search?q=' + encodeURIComponent(q))
        .then((r) => parseFetchJson<GlobalSearchResult>(r))
        .then((data) => setGlobalSearchResults(data))
        .catch(() => setGlobalSearchResults(null))
        .finally(() => setGlobalSearchLoading(false));
    }, 320);
    return () => window.clearTimeout(t);
  }, [globalSearchQ, user.permissions, activeTab]);

  const loadData = () => {
    void api('/api/buses')
      .then((r) => parseFetchJson(r))
      .then(setBuses)
      .catch(() => {});
    void api('/api/schools')
      .then((r) => parseFetchJson(r))
      .then(setSchools)
      .catch(() => {});
    void api('/api/students')
      .then((r) => parseFetchJson(r))
      .then(setMyStudents)
      .catch(() => {});
    if (isParentRole(user.role) || isStudentRole(user.role)) {
      void api('/api/transport/notices')
        .then((r) => parseFetchJson(r))
        .then(setTpNotices)
        .catch(() => {});
    }
  };

  const handleToolbarRefresh = () => {
    loadData();
    setDataRefreshTick((n) => n + 1);
  };

  useEffect(() => {
    if (!activeRouteBusId) return;
    if (detailedRoutes[activeRouteBusId]) return;
    const bus = busesRef.current.find((b) => b.id === activeRouteBusId);
    if (!bus || !bus.route || bus.route.length < 2) return;
    const coordString = bus.route.map((p: { lng: number; lat: number }) => `${p.lng},${p.lat}`).join(';');
    fetch(`https://router.project-osrm.org/route/v1/driving/${coordString}?overview=full&geometries=geojson`)
      .then((res) => readJsonLoose(res))
      .then((data: { routes?: { geometry?: { coordinates?: [number, number][] } }[] }) => {
        if (data.routes?.[0]) {
          const coords = data.routes[0].geometry!.coordinates!.map(
            (c: [number, number]) => [c[1], c[0]] as [number, number],
          );
          setDetailedRoutes((prev) => ({ ...prev, [activeRouteBusId]: coords }));
        }
      })
      .catch(console.error);
  }, [activeRouteBusId, detailedRoutes]);

  useEffect(() => {
    loadData();
    const socket = getSocket();
    const onBus = (updatedBus: any) => {
      setBuses((current) => {
        const index = current.findIndex((b) => b.id === updatedBus.id);
        if (index > -1) {
          const next = [...current];
          next[index] = { ...next[index], ...updatedBus };
          return next;
        }
        return current;
      });
    };
    const onNotif = (notif: any) => {
      if (userHas(user, 'map_global_view') || user.id === notif.target_parent_id || notif.target_parent_id == null) {
        setNotifications((prev) => [notif, ...prev].slice(0, 20));
      }
    };
    const onTp = () => {
      if (isParentRole(user.role) || isStudentRole(user.role)) {
        void api('/api/transport/notices')
          .then((r) => parseFetchJson(r))
          .then(setTpNotices)
          .catch(() => {});
      }
    };
    const onWallet = () => {
      loadData();
      setWalletUiTick((n) => n + 1);
    };
    socket.on('transportNotice', onTp);
    socket.on('walletUpdated', onWallet);
    socket.on('busUpdate', onBus);
    socket.on('busNotification', onNotif);
    socket.on('studentUpdate', loadData);
    socket.on('studentListUpdate', loadData);
    const onTripUpdate = ({ busId, trip }: { busId: string; trip: unknown }) => {
      setBuses((current) => {
        const ix = current.findIndex((b) => b.id === busId);
        if (ix === -1) return current;
        const next = [...current];
        next[ix] = { ...next[ix], trip };
        return next;
      });
    };
    socket.on('tripUpdate', onTripUpdate);
    return () => {
      socket.off('transportNotice', onTp);
      socket.off('walletUpdated', onWallet);
      socket.off('busUpdate', onBus);
      socket.off('busNotification', onNotif);
      socket.off('studentUpdate', loadData);
      socket.off('studentListUpdate', loadData);
      socket.off('tripUpdate', onTripUpdate);
    };
  }, [user.id, user.permissions]);

  useEffect(() => {
    const p = new URLSearchParams(window.location.search);
    const w = p.get('walletIntent');
    if (!w) return;
    void api('/api/wallet/top-up/mollie/sync', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ intentId: w }),
    })
      .then((r) => parseFetchJson(r))
      .then(() => {
        window.history.replaceState({}, '', window.location.pathname);
        loadData();
        setWalletUiTick((n) => n + 1);
      })
      .catch(console.error);
  }, []);

  const mapFlyToBus = useCallback((busId: string, lat?: number | null, lng?: number | null) => {
    setActiveTab('map');
    setMobileNavOpen(false);
    setMapHighlightStudent(null);
    setMapSpotHighlight(null);
    const fromList = buses.find((b) => b.id === busId)?.location;
    const la = typeof lat === 'number' && !Number.isNaN(lat) ? lat : Number(fromList?.lat) || 33.312805;
    const ln = typeof lng === 'number' && !Number.isNaN(lng) ? lng : Number(fromList?.lng) || 44.361488;
    setMapFlyTo({ lat: la, lng: ln, seq: Date.now() });
    setActiveRouteBusId(busId);
    setNationalSearchOpen(false);
    setGlobalSearchQ('');
    setGlobalSearchResults(null);
    if (nationalSearchBlurTimer.current) clearTimeout(nationalSearchBlurTimer.current);
  }, [buses]);

  const openFleetBusOnMap = useCallback(
    (busId: string, lat?: number | null, lng?: number | null) => {
      mapFlyToBus(busId, lat, lng);
    },
    [mapFlyToBus]
  );

  const openFleetDeviceGpsOnMap = useCallback((lat: number, lng: number, label: string) => {
    setActiveTab('map');
    setMobileNavOpen(false);
    setMapHighlightStudent(null);
    setActiveRouteBusId(null);
    setMapSpotHighlight({ lat, lng, label });
    setMapFlyTo({ lat, lng, seq: Date.now() });
    setNationalSearchOpen(false);
    setGlobalSearchQ('');
    setGlobalSearchResults(null);
    if (nationalSearchBlurTimer.current) clearTimeout(nationalSearchBlurTimer.current);
  }, []);

  const openSchoolCampusOnMap = useCallback((lat: number, lng: number, _label: string) => {
    setActiveTab('map');
    setMobileNavOpen(false);
    setMapHighlightStudent(null);
    setActiveRouteBusId(null);
    setMapSpotHighlight(null);
    setMapFlyTo({ lat, lng, seq: Date.now() });
    setNationalSearchOpen(false);
    setGlobalSearchQ('');
    setGlobalSearchResults(null);
    if (nationalSearchBlurTimer.current) clearTimeout(nationalSearchBlurTimer.current);
  }, []);

  const title =
    activeTab === 'support'
      ? t('feedback.supportPageTitle')
      : activeTab === 'supportdesk'
        ? t('feedback.supportDeskPageTitle')
        : activeTab === 'features' && showIdeasNav()
          ? t('feedback.featuresPageTitle')
          : activeTab === 'parentWallet'
            ? t('parentUi.walletTitle')
            : activeTab === 'parentLine'
              ? t('parentUi.lineRequestTitle')
              : activeTab === 'parentNotifs'
                ? t('parentUi.inboxTitle')
                : userHas(user, 'map_global_view')
                  ? t('dashboard.national')
                  : isSchoolStaffRole(user.role)
                    ? t('dashboard.schoolFleet')
                    : t('dashboard.family');

  return (
    <div className="flex bg-slate-50 h-[100dvh] min-h-0 overflow-hidden font-sans text-slate-800">
      {mobileNavOpen ? (
        <button
          type="button"
          className="fixed inset-0 z-[55] bg-slate-950/55 backdrop-blur-[1px] md:hidden"
          aria-label={t('common.closeMenu')}
          onClick={() => setMobileNavOpen(false)}
        />
      ) : null}
      <aside
        className={`fixed md:static inset-y-0 start-0 z-[60] flex w-[min(17.5rem,calc(100vw-1.25rem))] max-w-[90vw] shrink-0 flex-col bg-slate-900 text-white shadow-2xl transition-transform duration-200 ease-out md:w-[240px] md:max-w-none md:translate-x-0 md:shadow-none ${
          mobileNavOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'
        }`}
      >
        <div className="flex items-center justify-between gap-2 border-b border-slate-800 p-4 pt-[max(1rem,env(safe-area-inset-top))] md:p-6 md:pt-6">
          <div className="flex min-w-0 items-center gap-2 font-extrabold text-[1.05rem] tracking-tight md:text-[1.2rem]">
            <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-blue-500 md:h-6 md:w-6">
              <Bus className="h-5 w-5 text-white md:h-4 md:w-4" />
            </div>
            <span className="truncate">OmniTrack</span>
          </div>
          <button
            type="button"
            className="flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-white hover:bg-slate-800 md:hidden"
            aria-label={t('common.closeMenu')}
            onClick={() => setMobileNavOpen(false)}
          >
            <X className="h-6 w-6" />
          </button>
        </div>
        <nav className="flex-1 space-y-1 overflow-y-auto overscroll-y-contain py-3 md:py-5">
          <button
            type="button"
            onClick={() => {
              setActiveTab('map');
              setMobileNavOpen(false);
            }}
            className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'map' ? 'border-blue-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
          >
            <Search className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.liveMap')}
          </button>
          <button
            type="button"
            onClick={() => {
              setActiveTab('students');
              setMobileNavOpen(false);
            }}
            className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'students' ? 'border-blue-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
          >
            <Users className="h-5 w-5 shrink-0 md:h-4 md:w-4" />{' '}
            {isParentRole(user.role) ? t('dashboard.studentsParent') : isStudentRole(user.role) ? t('dashboard.studentsChild') : t('dashboard.students')}
          </button>
          {(isParentRole(user.role) || isStudentRole(user.role)) && (
            <>
              <button
                type="button"
                onClick={() => {
                  setActiveTab('parentWallet');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'parentWallet' ? 'border-emerald-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <Wallet className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('parentUi.walletNav')}
              </button>
              <button
                type="button"
                onClick={() => {
                  setActiveTab('parentLine');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'parentLine' ? 'border-violet-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <ListOrdered className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('parentUi.lineNav')}
              </button>
              <button
                type="button"
                onClick={() => {
                  setActiveTab('parentNotifs');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'parentNotifs' ? 'border-amber-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <Bell className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('parentUi.inboxNav')}
              </button>
            </>
          )}
          <button
            type="button"
            onClick={() => {
              setActiveTab('support');
              setMobileNavOpen(false);
            }}
            className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'support' ? 'border-teal-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
          >
            <LifeBuoy className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.supportNav')}
          </button>
          {showSupportDeskNav ? (
            <button
              type="button"
              onClick={() => {
                setActiveTab('supportdesk');
                setMobileNavOpen(false);
              }}
              className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'supportdesk' ? 'border-cyan-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
            >
              <Inbox className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.supportDeskNav')}
            </button>
          ) : null}
          {showIdeasNav() ? (
            <button
              type="button"
              onClick={() => {
                setActiveTab('features');
                setMobileNavOpen(false);
              }}
              className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'features' ? 'border-amber-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
            >
              <Lightbulb className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.featuresNav')}
            </button>
          ) : null}
          {(showUsersNav || showSchoolsNav || showFleetNav) && (
            <>
              {showUsersNav ? (
              <button
                type="button"
                onClick={() => {
                  setActiveTab('users');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'users' ? 'border-blue-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <Users className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.users')}
              </button>
              ) : null}
              {showSchoolsNav ? (
              <button
                type="button"
                onClick={() => {
                  setActiveTab('schools');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'schools' ? 'border-blue-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <Building2 className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.schools')}
              </button>
              ) : null}
              {showFleetNav ? (
              <button
                type="button"
                onClick={() => {
                  setActiveTab('fleet');
                  setMobileNavOpen(false);
                }}
                className={`flex min-h-11 w-full items-center gap-3 px-5 py-3 text-start text-[0.9rem] font-medium transition-all border-s-4 md:px-6 ${activeTab === 'fleet' ? 'border-indigo-500 bg-slate-800 text-white' : 'border-transparent text-slate-400 hover:bg-slate-800'}`}
              >
                <Truck className="h-5 w-5 shrink-0 md:h-4 md:w-4" /> {t('dashboard.fleet')}
              </button>
              ) : null}
            </>
          )}
        </nav>
        <div className="border-t border-slate-800 p-4 pb-[max(1rem,env(safe-area-inset-bottom))] md:p-4">
          <div className="mb-3 flex flex-wrap gap-x-3 gap-y-1 text-[11px]">
            <a href="/privacy" target="_blank" rel="noopener noreferrer" className="text-slate-400 hover:text-white hover:underline">
              {t('legal.privacyPolicy')}
            </a>
            <a href="/account-deletion" target="_blank" rel="noopener noreferrer" className="text-slate-400 hover:text-white hover:underline">
              {t('legal.accountDeletion')}
            </a>
            <button
              type="button"
              className="text-red-400 hover:text-red-300 hover:underline"
              onClick={() => void requestDeleteMyAccount(t, onLogout)}
            >
              {t('legal.deleteAccount')}
            </button>
          </div>
          <div className="cursor-pointer hover:bg-slate-800 rounded-lg -mx-2 px-2 py-1" onClick={onLogout} role="button" tabIndex={0}
            onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onLogout(); } }}>
            <div className="text-[10px] uppercase tracking-wider bg-blue-500/20 text-blue-500 px-2 py-1 rounded inline-block font-semibold mb-2">{t(`roles.${roleLabelKey(user.role)}`)}</div>
            <div className="text-[0.85rem] font-semibold">{user.name}</div>
            <div className="text-xs text-slate-500 mt-1">{t('common.logout')}</div>
          </div>
        </div>
      </aside>

      <main className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden pb-[env(safe-area-inset-bottom)]">
        <header className="shrink-0 border-b border-slate-200 bg-white px-3 py-2 pt-[max(0.5rem,env(safe-area-inset-top))] sm:px-4 md:px-8 md:py-3">
          <div className="flex flex-wrap items-center gap-2 sm:gap-3">
            <button
              type="button"
              className="flex h-11 w-11 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-slate-50 text-slate-800 hover:bg-slate-100 md:hidden"
              aria-label={t('common.openMenu')}
              onClick={() => setMobileNavOpen(true)}
            >
              <Menu className="h-6 w-6" />
            </button>
            <h1 className="min-w-0 max-w-[min(100%,14rem)] shrink truncate text-[0.95rem] font-bold text-slate-800 sm:max-w-[45%] md:text-[1rem]">
              {title}
            </h1>
            {userHas(user, 'map_global_view') && activeTab === 'map' && (
              <div className="flex w-full flex-wrap items-center gap-1.5 order-3 md:order-none">
                {IRAQ_MAP_CITY_PRESETS.map((city) => (
                  <button
                    key={city.id}
                    type="button"
                    className="rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-bold text-slate-700 hover:bg-white"
                    onClick={() => setMapFlyTo({ lat: city.lat, lng: city.lng, zoom: city.zoom, seq: Date.now() })}
                  >
                    {t(IRAQ_MAP_CITY_LABEL_KEYS[city.id])}
                  </button>
                ))}
              </div>
            )}
            {userHas(user, 'map_global_view') && activeTab === 'map' && (
              <div className="relative z-[100] order-4 w-full min-w-0 md:order-none md:max-w-2xl md:flex-1 md:min-w-[min(100%,280px)]">
                <div className="relative">
                  <Search className="absolute start-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 pointer-events-none" aria-hidden />
                  <input
                    type="search"
                    value={globalSearchQ}
                    onChange={(e) => setGlobalSearchQ(e.target.value)}
                    onFocus={() => {
                      if (nationalSearchBlurTimer.current) clearTimeout(nationalSearchBlurTimer.current);
                      setNationalSearchOpen(true);
                    }}
                    onBlur={() => {
                      nationalSearchBlurTimer.current = setTimeout(() => setNationalSearchOpen(false), 220);
                    }}
                    placeholder={t('dashboard.globalSearchPlaceholder')}
                    className="w-full border border-slate-200 rounded-lg ps-10 pe-3 py-2 text-sm bg-slate-50 focus:bg-white focus:ring-2 focus:ring-indigo-200 outline-none"
                    autoComplete="off"
                    aria-label={t('dashboard.globalSearchPlaceholder')}
                  />
                  {nationalSearchOpen && globalSearchQ.trim().length >= 2 && (globalSearchLoading || globalSearchResults) && (
                    <div className="absolute start-0 end-0 top-full mt-1 max-h-[min(70vh,22rem)] overflow-y-auto bg-white border border-slate-200 rounded-xl shadow-xl text-start">
                      {globalSearchLoading && (
                        <div className="px-3 py-4 text-sm text-slate-500">{t('dashboard.searchLoading')}</div>
                      )}
                      {!globalSearchLoading && globalSearchResults && (
                        <>
                          {(() => {
                            const r = globalSearchResults;
                            const n =
                              r.users.length + r.buses.length + r.devices.length + r.students.length + r.schools.length;
                            if (n === 0) {
                              return <div className="px-3 py-4 text-sm text-slate-500">{t('dashboard.searchNoResults')}</div>;
                            }
                            return (
                              <>
                                {r.users.length > 0 && (
                                  <div className="border-b border-slate-100">
                                    <div className="text-[10px] font-bold text-slate-500 uppercase px-3 py-1.5 bg-slate-50">
                                      {t('dashboard.searchSectionUsers')}
                                    </div>
                                    {compact(r.users).map((u) => (
                                      <div
                                        key={u.id}
                                        className="px-3 py-2 hover:bg-slate-50 flex flex-wrap items-start justify-between gap-2 border-b border-slate-50 last:border-0"
                                      >
                                        <div className="min-w-0">
                                          <div className="font-semibold text-sm text-slate-900">{u.name}</div>
                                          <div className="text-[11px] text-slate-500 break-all">
                                            {u.email || '—'} · {t(`roles.${roleLabelKey(u.role)}`)}
                                          </div>
                                          {(u.school_name || u.bus_license_plate) && (
                                            <div className="text-[10px] text-slate-400 mt-0.5">
                                              {[u.school_name, u.bus_license_plate].filter(Boolean).join(' · ')}
                                            </div>
                                          )}
                                        </div>
                                        <div className="flex flex-col gap-1 shrink-0">
                                          {u.bus_id && (
                                            <button
                                              type="button"
                                              className="text-xs font-semibold text-indigo-600 hover:underline"
                                              onMouseDown={(e) => e.preventDefault()}
                                              onClick={() => {
                                                const bl = buses.find((b) => b.id === u.bus_id);
                                                mapFlyToBus(u.bus_id!, bl?.location?.lat, bl?.location?.lng);
                                              }}
                                            >
                                              {t('dashboard.searchShowOnMap')}
                                            </button>
                                          )}
                                          <button
                                            type="button"
                                            className="text-xs font-semibold text-slate-600 hover:underline"
                                            onMouseDown={(e) => e.preventDefault()}
                                            onClick={() => {
                                              setActiveTab('users');
                                              setMobileNavOpen(false);
                                              setNationalSearchOpen(false);
                                              setGlobalSearchQ('');
                                              setGlobalSearchResults(null);
                                            }}
                                          >
                                            {t('dashboard.searchOpenUsers')}
                                          </button>
                                        </div>
                                      </div>
                                    ))}
                                  </div>
                                )}
                                {r.buses.length > 0 && (
                                  <div className="border-b border-slate-100">
                                    <div className="text-[10px] font-bold text-slate-500 uppercase px-3 py-1.5 bg-slate-50">
                                      {t('dashboard.searchSectionBuses')}
                                    </div>
                                    {compact(r.buses).map((b) => (
                                      <div
                                        key={b.id}
                                        className="px-3 py-2 hover:bg-slate-50 flex flex-wrap items-start justify-between gap-2 border-b border-slate-50 last:border-0"
                                      >
                                        <div className="min-w-0">
                                          <div className="font-semibold text-sm text-slate-900">{b.license_plate || b.imei || b.id}</div>
                                          <div className="text-[11px] text-slate-500 font-mono">IMEI {b.imei || '—'}</div>
                                          {b.driver_name && (
                                            <div className="text-[11px] text-slate-600">
                                              {t('dashboard.searchDriver')}: {b.driver_name}
                                            </div>
                                          )}
                                          {b.school_name && (
                                            <div className="text-[10px] text-slate-400">
                                              {t('dashboard.searchSchool')}: {b.school_name}
                                            </div>
                                          )}
                                        </div>
                                        <button
                                          type="button"
                                          className="text-xs font-semibold text-indigo-600 hover:underline shrink-0"
                                          onMouseDown={(e) => e.preventDefault()}
                                          onClick={() => mapFlyToBus(b.id, b.lat, b.lng)}
                                        >
                                          {t('dashboard.searchShowOnMap')}
                                        </button>
                                      </div>
                                    ))}
                                  </div>
                                )}
                                {r.devices.length > 0 && (
                                  <div className="border-b border-slate-100">
                                    <div className="text-[10px] font-bold text-slate-500 uppercase px-3 py-1.5 bg-slate-50">
                                      {t('dashboard.searchSectionDevices')}
                                    </div>
                                    {compact(r.devices).map((d) => (
                                      <div
                                        key={d.imei}
                                        className="px-3 py-2 hover:bg-slate-50 flex flex-wrap items-start justify-between gap-2 border-b border-slate-50 last:border-0"
                                      >
                                        <div className="min-w-0">
                                          <div className="font-mono text-xs font-semibold text-slate-900">{d.imei}</div>
                                          {d.phone_number && (
                                            <div className="text-[11px] text-slate-600 flex items-center gap-1 mt-0.5">
                                              <Phone className="w-3 h-3 shrink-0" /> {d.phone_number}
                                            </div>
                                          )}
                                          {d.device_model && (
                                            <div className="text-[10px] text-slate-500">{d.device_model}</div>
                                          )}
                                          {(d.bus_license_plate || d.school_name) && (
                                            <div className="text-[10px] text-slate-400 mt-0.5">
                                              {[d.bus_license_plate, d.school_name].filter(Boolean).join(' · ')}
                                            </div>
                                          )}
                                        </div>
                                        {d.bus_id && (
                                          <button
                                            type="button"
                                            className="text-xs font-semibold text-indigo-600 hover:underline shrink-0"
                                            onMouseDown={(e) => e.preventDefault()}
                                            onClick={() => {
                                              const bl = buses.find((b) => b.id === d.bus_id);
                                              mapFlyToBus(d.bus_id!, bl?.location?.lat, bl?.location?.lng);
                                            }}
                                          >
                                            {t('dashboard.searchShowOnMap')}
                                          </button>
                                        )}
                                      </div>
                                    ))}
                                  </div>
                                )}
                                {r.students.length > 0 && (
                                  <div className="border-b border-slate-100">
                                    <div className="text-[10px] font-bold text-slate-500 uppercase px-3 py-1.5 bg-slate-50">
                                      {t('dashboard.searchSectionStudents')}
                                    </div>
                                    {compact(r.students).map((s) => (
                                      <div
                                        key={s.id}
                                        className="px-3 py-2 hover:bg-slate-50 flex flex-wrap items-start justify-between gap-2 border-b border-slate-50 last:border-0"
                                      >
                                        <div className="min-w-0">
                                          <div className="font-semibold text-sm text-slate-900">{s.name}</div>
                                          {s.parent_name && (
                                            <div className="text-[11px] text-slate-500">
                                              {t('dashboard.searchParent')}: {s.parent_name}
                                            </div>
                                          )}
                                          {s.school_name && (
                                            <div className="text-[10px] text-slate-400">{s.school_name}</div>
                                          )}
                                        </div>
                                        {s.lat != null && s.lng != null && !Number.isNaN(Number(s.lat)) && !Number.isNaN(Number(s.lng)) && (
                                          <button
                                            type="button"
                                            className="text-xs font-semibold text-indigo-600 hover:underline shrink-0"
                                            onMouseDown={(e) => e.preventDefault()}
                                            onClick={() => {
                                              const la = Number(s.lat);
                                              const ln = Number(s.lng);
                                              setActiveTab('map');
                                              setMobileNavOpen(false);
                                              setMapSpotHighlight(null);
                                              setMapHighlightStudent({ lat: la, lng: ln, name: s.name });
                                              setMapFlyTo({ lat: la, lng: ln, seq: Date.now() });
                                              setNationalSearchOpen(false);
                                              setGlobalSearchQ('');
                                              setGlobalSearchResults(null);
                                            }}
                                          >
                                            {t('dashboard.searchShowOnMap')}
                                          </button>
                                        )}
                                      </div>
                                    ))}
                                  </div>
                                )}
                                {r.schools.length > 0 && (
                                  <div>
                                    <div className="text-[10px] font-bold text-slate-500 uppercase px-3 py-1.5 bg-slate-50 flex items-center gap-1">
                                      <Building2 className="w-3 h-3" /> {t('dashboard.searchSectionSchools')}
                                    </div>
                                    {compact(r.schools).map((sc) => {
                                      const la = Number(sc.lat);
                                      const ln = Number(sc.lng);
                                      const hasCoords =
                                        Number.isFinite(la) &&
                                        Number.isFinite(ln) &&
                                        !(la === 0 && ln === 0);
                                      return (
                                        <div
                                          key={sc.id}
                                          className="px-3 py-2 hover:bg-slate-50 flex flex-wrap items-start justify-between gap-2 border-b border-slate-50 last:border-0"
                                        >
                                          <div className="min-w-0 font-semibold text-sm text-slate-900">{sc.name}</div>
                                          {hasCoords ? (
                                            <button
                                              type="button"
                                              className="text-xs font-semibold text-indigo-600 hover:underline shrink-0"
                                              onMouseDown={(e) => e.preventDefault()}
                                              onClick={() => {
                                                setMapShowSchools(true);
                                                openSchoolCampusOnMap(la, ln, sc.name);
                                              }}
                                            >
                                              {t('dashboard.searchShowOnMap')}
                                            </button>
                                          ) : null}
                                        </div>
                                      );
                                    })}
                                  </div>
                                )}
                              </>
                            );
                          })()}
                        </>
                      )}
                    </div>
                  )}
                </div>
              </div>
            )}
            <div className="flex items-center gap-2 shrink-0 ms-auto">
              <button
                type="button"
                onClick={() => handleToolbarRefresh()}
                className="flex min-h-10 items-center gap-1.5 whitespace-nowrap rounded-lg border border-slate-200 bg-white px-2.5 py-2 text-xs font-semibold text-slate-700 shadow-sm hover:bg-slate-50 sm:py-1.5 sm:text-sm"
                title={t('common.refresh')}
                aria-label={t('common.refresh')}
              >
                <RefreshCw className="h-4 w-4 shrink-0" aria-hidden />
                <span className="hidden sm:inline">{t('common.refresh')}</span>
              </button>
              <LanguageSwitcher />
              <div className="relative">
                <button
                  type="button"
                  onClick={() => setShowNotif((v) => !v)}
                  className="relative flex h-11 w-11 items-center justify-center rounded-lg border border-slate-200 hover:bg-slate-50"
                  aria-label={t('dashboard.notifications')}
                >
                  <Bell className="w-5 h-5 text-slate-700" />
                  {notifications.length > 0 && (
                    <span className="absolute -top-0.5 -end-0.5 min-w-[18px] h-[18px] text-[10px] font-bold bg-red-500 text-white rounded-full flex items-center justify-center px-1">
                      {notifications.length > 9 ? '9+' : notifications.length}
                    </span>
                  )}
                </button>
                {showNotif && (
                  <div className="absolute end-0 z-50 mt-2 max-h-[min(18rem,70dvh)] w-[min(20rem,calc(100vw-1.5rem))] overflow-y-auto overscroll-y-contain rounded-xl border border-slate-200 bg-white p-2 shadow-xl sm:w-80">
                    <div className="text-xs font-bold text-slate-500 px-2 py-1">{t('dashboard.notifications')}</div>
                    {notifications.length === 0 ? (
                      <div className="text-sm text-slate-500 p-3">{t('dashboard.noNotifications')}</div>
                    ) : (
                      compact(notifications).map((n) => (
                        <div key={n.id} className="text-sm p-2 border-b border-slate-100 last:border-0">
                          {n.message}
                          <div className="text-[10px] text-slate-400 mt-1">{n.at ? new Date(n.at).toLocaleString() : ''}</div>
                        </div>
                      ))
                    )}
                  </div>
                )}
              </div>
              {(isSchoolStaffRole(user.role) || userHas(user, 'map_global_view')) && activeTab === 'map' && (
                <button
                  type="button"
                  onClick={() =>
                    void api('/api/school/generate-routes', { method: 'POST' })
                      .then((r) => parseFetchJson<{ message?: string }>(r))
                      .then((d) => alert(d.message || t('dashboard.routesOk')))
                      .catch((e) => alert(e instanceof Error ? e.message : t('apiErrors.serverError')))
                  }
                  className="flex min-h-10 items-center gap-2 whitespace-nowrap rounded border border-indigo-200 bg-indigo-50 px-3 py-2 text-[0.75rem] font-bold text-indigo-700 shadow-sm sm:py-1.5"
                >
                  <RefreshCw className="w-3 h-3" /> {t('dashboard.genRoutes')}
                </button>
              )}
            </div>
          </div>
        </header>

        {activeTab === 'support' ? (
          <FeedbackSupportTab user={user} />
        ) : activeTab === 'supportdesk' ? (
          <SupportAgentDeskTab user={user} />
        ) : activeTab === 'features' && showIdeasNav() ? (
          <FeedbackFeaturesTab user={user} />
        ) : activeTab === 'parentWallet' ? (
          <div className="mx-auto max-w-2xl space-y-5 p-4 md:p-6">
            {myStudents.length === 0 ? (
              <p className="text-sm text-slate-600">{t('parentUi.noStudents')}</p>
            ) : parentWalletLoading ? (
              <p className="text-sm text-slate-600">{t('parentUi.loadingWallet')}</p>
            ) : (
              <>
                <div>
                  <label className="text-xs font-bold uppercase tracking-wide text-slate-500" htmlFor="pw-student">
                    {t('parentUi.selectChild')}
                  </label>
                  <select
                    id="pw-student"
                    className="mt-1 w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm"
                    value={pwStudentId}
                    onChange={(e) => setPwStudentId(e.target.value)}
                  >
                    {myStudents.map((s) => (
                      <option key={s.id} value={s.id}>
                        {s.name}
                      </option>
                    ))}
                  </select>
                </div>
                {(() => {
                  const pack = parentWalletByStudent[pwStudentId] as
                    | { control?: string; wallet?: { balance_minor?: number }; ledger?: { id: string; reason: string; delta_minor: number }[] }
                    | undefined;
                  if (!pack) return <p className="text-sm text-slate-600">{t('parentUi.walletUnavailable')}</p>;
                  const ctrl = pack.control || 'parent_protected';
                  const canTopUp =
                    isParentRole(user.role) || (isStudentRole(user.role) && ctrl === 'student_self');
                  const ledger = Array.isArray(pack.ledger) ? pack.ledger : [];
                  return (
                    <>
                      <div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm">
                        <div className="text-xs font-bold uppercase text-slate-500">{t('parentUi.balance')}</div>
                        <div className="mt-1 text-2xl font-black text-slate-900">
                          {Number(pack.wallet?.balance_minor ?? 0).toLocaleString()} IQD
                        </div>
                        <div className="mt-2 text-xs text-slate-500">
                          {t('parentUi.controlMode')}: {t(`parentUi.control.${ctrl}`)}
                        </div>
                        {!canTopUp && isStudentRole(user.role) ? (
                          <p className="mt-3 text-sm text-amber-800">{t('parentUi.topUpParentOnly')}</p>
                        ) : null}
                      </div>
                      {canTopUp ? (
                        <div className="space-y-3 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm">
                          <div className="text-sm font-bold text-slate-800">{t('parentUi.topUpTitle')}</div>
                          <p className="text-xs text-slate-500">{t('wallet.mollieIqdDisclaimer')}</p>
                          <div>
                            <label className="text-xs font-semibold text-slate-600" htmlFor="pw-amt">
                              {t('parentUi.amountIqd')}
                            </label>
                            <input
                              id="pw-amt"
                              type="number"
                              min={100}
                              className="mt-1 w-full rounded-lg border border-slate-200 px-3 py-2 text-sm"
                              value={pwAmount}
                              onChange={(e) => setPwAmount(e.target.value)}
                              placeholder="5000"
                            />
                          </div>
                          <button
                            type="button"
                            className="w-full rounded-xl bg-emerald-600 py-3 text-sm font-bold text-white hover:bg-emerald-700 disabled:opacity-50"
                            disabled={!pwAmount || Number(pwAmount) < 100}
                            onClick={() => {
                              void api('/api/wallet/top-up/mollie', {
                                method: 'POST',
                                headers: { 'Content-Type': 'application/json' },
                                body: JSON.stringify({
                                  studentId: pwStudentId,
                                  amountIqdWhole: Math.round(Number(pwAmount)),
                                }),
                              })
                                .then((r) => parseFetchJson<{ checkoutUrl?: string }>(r))
                                .then((d) => {
                                  if (d.checkoutUrl) window.location.href = d.checkoutUrl;
                                  else alert(t('apiErrors.serverError'));
                                })
                                .catch((e) => alert(e instanceof Error ? e.message : t('apiErrors.serverError')));
                            }}
                          >
                            {t('parentUi.continueMollie')}
                          </button>
                        </div>
                      ) : null}
                      <div>
                        <div className="mb-2 text-xs font-bold uppercase text-slate-500">{t('parentUi.ledgerTitle')}</div>
                        <ul className="max-h-52 space-y-1 overflow-y-auto rounded-xl border border-slate-100 bg-slate-50 p-2 text-sm">
                          {ledger.length === 0 ? (
                            <li className="px-2 py-3 text-slate-500">{t('parentUi.noLedger')}</li>
                          ) : (
                            ledger.map((e) => (
                              <li key={e.id} className="flex justify-between gap-2 rounded-lg bg-white px-2 py-1.5">
                                <span className="text-slate-600">{e.reason}</span>
                                <span
                                  className={
                                    Number(e.delta_minor) >= 0
                                      ? 'font-semibold text-emerald-700'
                                      : 'font-semibold text-rose-700'
                                  }
                                >
                                  {Number(e.delta_minor) >= 0 ? '+' : ''}
                                  {Number(e.delta_minor).toLocaleString()}
                                </span>
                              </li>
                            ))
                          )}
                        </ul>
                      </div>
                    </>
                  );
                })()}
              </>
            )}
          </div>
        ) : activeTab === 'parentLine' ? (
          <div className="mx-auto max-w-2xl space-y-5 p-4 md:p-6">
            {!isParentRole(user.role) ? (
              <p className="text-sm text-slate-600">{t('parentUi.lineStudentHint')}</p>
            ) : myStudents.length === 0 ? (
              <p className="text-sm text-slate-600">{t('parentUi.noStudents')}</p>
            ) : (
              <>
                <p className="text-sm text-slate-600">{t('parentUi.lineIntro')}</p>
                <div>
                  <label className="text-xs font-bold uppercase tracking-wide text-slate-500" htmlFor="pl-school">
                    {t('parentUi.school')}
                  </label>
                  <select
                    id="pl-school"
                    className="mt-1 w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm"
                    value={plSchoolId}
                    onChange={(e) => {
                      const v = e.target.value;
                      setPlSchoolId(v);
                      setPlBusId('');
                      const first = myStudents.find((s) => String(s.school_id) === v);
                      if (first) setPlStudentId(String(first.id));
                    }}
                  >
                    {lineSchoolOptions.map((sch) => (
                      <option key={sch.id} value={sch.id}>
                        {sch.name}
                      </option>
                    ))}
                  </select>
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-wide text-slate-500" htmlFor="pl-stu">
                    {t('parentUi.child')}
                  </label>
                  <select
                    id="pl-stu"
                    className="mt-1 w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm"
                    value={plStudentId}
                    onChange={(e) => setPlStudentId(e.target.value)}
                  >
                    {lineStudentsFiltered.map((s) => (
                      <option key={s.id} value={s.id}>
                        {s.name}
                      </option>
                    ))}
                  </select>
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-wide text-slate-500" htmlFor="pl-bus-any">
                    {t('parentUi.preferredBus')}
                  </label>
                  <p className="mt-0.5 text-[11px] text-slate-500">{t('parentUi.availableBusesHint')}</p>
                  <div className="mt-2 space-y-2" id="pl-bus">
                    <button
                      type="button"
                      id="pl-bus-any"
                      className={`w-full rounded-xl border px-3 py-2.5 text-start text-sm transition-colors ${
                        !plBusId ? 'border-violet-400 bg-violet-50 font-semibold text-violet-900' : 'border-slate-200 bg-white hover:bg-slate-50'
                      }`}
                      onClick={() => setPlBusId('')}
                    >
                      {t('parentUi.anyBus')}
                    </button>
                    {lineBusesFiltered.map((b) => (
                      <button
                        key={String(b.id)}
                        type="button"
                        className={`w-full rounded-xl border px-3 py-2.5 text-start text-sm transition-colors ${
                          plBusId === String(b.id)
                            ? 'border-violet-400 bg-violet-50 font-semibold text-violet-900'
                            : 'border-slate-200 bg-white hover:bg-slate-50'
                        }`}
                        onClick={() => setPlBusId(String(b.id))}
                      >
                        {lineBusOptionLabel(b as Record<string, unknown>, t)}
                      </button>
                    ))}
                  </div>
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-wide text-slate-500" htmlFor="pl-note">
                    {t('parentUi.note')}
                  </label>
                  <textarea
                    id="pl-note"
                    rows={3}
                    className="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm"
                    value={plNote}
                    onChange={(e) => setPlNote(e.target.value)}
                    placeholder={t('parentUi.notePh')}
                  />
                </div>
                <button
                  type="button"
                  className="w-full rounded-xl bg-violet-600 py-3 text-sm font-bold text-white hover:bg-violet-700"
                  onClick={() => {
                    void api('/api/transport/requests', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({
                        studentId: plStudentId,
                        schoolId: plSchoolId,
                        targetBusId: plBusId || null,
                        note: plNote || null,
                      }),
                    })
                      .then((r) => parseFetchJson<{ id?: string }>(r))
                      .then(() => {
                        setPlNote('');
                        alert(t('parentUi.lineSubmitted'));
                      })
                      .catch((e) => alert(e instanceof Error ? e.message : t('apiErrors.serverError')));
                  }}
                >
                  {t('parentUi.submitRequest')}
                </button>
              </>
            )}
          </div>
        ) : activeTab === 'parentNotifs' ? (
          <div className="mx-auto max-w-2xl space-y-3 p-4 md:p-6">
            {tpNotices.length === 0 ? (
              <p className="text-sm text-slate-600">{t('parentUi.inboxEmpty')}</p>
            ) : (
              <ul className="space-y-2">
                {tpNotices.map((n: any) => (
                  <li key={n.id}>
                    <button
                      type="button"
                      className={`w-full rounded-xl border border-slate-200 bg-white p-3 text-start text-sm shadow-sm hover:bg-slate-50 ${n.read_at ? 'opacity-70' : 'border-amber-200 bg-amber-50/40'}`}
                      onClick={() => {
                        if (!n.read_at) {
                          void api(`/api/transport/notices/${encodeURIComponent(String(n.id))}/read`, {
                            method: 'PATCH',
                          })
                            .then(() =>
                              setTpNotices((prev) =>
                                prev.map((x: any) => (x.id === n.id ? { ...x, read_at: new Date().toISOString() } : x)),
                              ),
                            )
                            .catch(() => {});
                        }
                      }}
                    >
                      <div className="text-xs text-slate-500">
                        {n.from_name ? `${n.from_name} · ` : ''}
                        {n.created_at ? new Date(n.created_at).toLocaleString() : ''}
                      </div>
                      <div className="mt-1 text-slate-800">{n.body}</div>
                      {n.kind ? <div className="mt-1 text-[10px] uppercase text-slate-400">{n.kind}</div> : null}
                    </button>
                  </li>
                ))}
              </ul>
            )}
          </div>
        ) : activeTab === 'students' ? (
          <StudentManagement user={user} students={myStudents} schools={schools} onRefresh={loadData} />
        ) : activeTab === 'users' ? (
          <UserManagement user={user} schools={schools} onRefresh={loadData} dataRefreshTick={dataRefreshTick} />
        ) : activeTab === 'schools' ? (
          <SchoolManagement
            user={user}
            schools={schools}
            onRefresh={loadData}
            onShowSchoolOnMap={
              mapSchoolsWithCoords.length > 0 &&
              (userHas(user, 'map_global_view') ||
                isSchoolStaffRole(user.role) ||
                isParentRole(user.role) ||
                isStudentRole(user.role))
                ? openSchoolCampusOnMap
                : undefined
            }
          />
        ) : activeTab === 'fleet' ? (
          <FleetManagement
            schools={schools}
            onRefresh={loadData}
            dataRefreshTick={dataRefreshTick}
            onShowBusOnMap={openFleetBusOnMap}
            onShowDeviceGpsOnMap={openFleetDeviceGpsOnMap}
          />
        ) : (
          <>
            <div className="relative z-0 m-2 mt-2 flex min-h-[min(360px,55dvh)] flex-1 flex-col overflow-hidden rounded-xl border border-slate-200 bg-slate-200 shadow-sm sm:m-3 sm:mt-3 md:m-6 md:mt-6 md:min-h-[320px] md:rounded-2xl">
              {followLiveBusId && followLiveBus?.location ? (
                <div className="absolute top-3 left-1/2 z-[400] flex max-w-[min(calc(100%-1.5rem),20rem)] -translate-x-1/2 items-center gap-2 rounded-full border border-orange-200 bg-white/95 px-3 py-1.5 shadow-md backdrop-blur-sm">
                  <span className="relative flex h-2 w-2 shrink-0" aria-hidden>
                    <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-orange-400 opacity-75" />
                    <span className="relative inline-flex h-2 w-2 rounded-full bg-orange-500" />
                  </span>
                  <span className="min-w-0 truncate text-xs font-semibold text-slate-800">
                    {t('dashboard.followingBus', {
                      plate: followLiveBus.license_plate || followLiveBus.imei || followLiveBus.id,
                    })}
                  </span>
                  <button
                    type="button"
                    className="shrink-0 rounded-full p-0.5 text-slate-500 hover:bg-slate-100 hover:text-slate-800"
                    aria-label={t('dashboard.stopFollowLive')}
                    onClick={() => setFollowLiveBusId(null)}
                  >
                    <X className="h-3.5 w-3.5" aria-hidden />
                  </button>
                </div>
              ) : null}
              {showMapLayerPanel ? (
                <div
                  className="absolute bottom-3 start-3 z-[400] flex max-w-[min(100%,14rem)] flex-col gap-1.5 rounded-lg border border-slate-200 bg-white/95 p-2.5 shadow-md backdrop-blur-sm"
                  role="group"
                  aria-label={t('dashboard.mapLayerSchools')}
                >
                  <div className="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wide text-slate-500">
                    <Layers className="h-3 w-3 shrink-0" aria-hidden />
                    <span>{t('dashboard.liveMap')}</span>
                  </div>
                  {mapSchoolsWithCoords.length > 0 ? (
                    <label className="flex cursor-pointer items-center gap-2 text-xs font-medium text-slate-700">
                      <input
                        type="checkbox"
                        className="h-4 w-4 rounded border-slate-300"
                        checked={mapShowSchools}
                        onChange={(e) => setMapShowSchools(e.target.checked)}
                      />
                      <Building2 className="h-3.5 w-3.5 shrink-0 text-emerald-600" aria-hidden />
                      <span>{t('dashboard.mapLayerSchools')}</span>
                    </label>
                  ) : null}
                  {buses.length > 0 ? (
                    <label className="flex cursor-pointer items-center gap-2 text-xs font-medium text-slate-700">
                      <input
                        type="checkbox"
                        className="h-4 w-4 rounded border-slate-300"
                        checked={mapShowBuses}
                        onChange={(e) => setMapShowBuses(e.target.checked)}
                      />
                      <Bus className="h-3.5 w-3.5 shrink-0 text-orange-600" aria-hidden />
                      <span>{t('dashboard.mapLayerBuses')}</span>
                    </label>
                  ) : null}
                  {mapActiveStudentStops.length > 0 ? (
                    <label className="flex cursor-pointer items-center gap-2 text-xs font-medium text-slate-700">
                      <input
                        type="checkbox"
                        className="h-4 w-4 rounded border-slate-300"
                        checked={mapShowStops}
                        onChange={(e) => setMapShowStops(e.target.checked)}
                      />
                      <MapPin className="h-3.5 w-3.5 shrink-0 text-blue-600" aria-hidden />
                      <span>{t('dashboard.mapLayerStudents')}</span>
                    </label>
                  ) : null}
                </div>
              ) : null}
              <MapContainer
                center={[IRAQ_MAP_DEFAULT.lat, IRAQ_MAP_DEFAULT.lng]}
                zoom={IRAQ_MAP_DEFAULT.zoom}
                scrollWheelZoom
                className="touch-pan-x touch-pan-y"
                style={{ height: '100%', width: '100%', zIndex: 0 }}
              >
                <TileLayer url="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png" />
                {mapFlyTo && (
                  <MapFlyToTarget lat={mapFlyTo.lat} lng={mapFlyTo.lng} seq={mapFlyTo.seq} zoom={mapFlyTo.zoom} />
                )}
                {followLiveBusId && followLiveBus?.location ? (
                  <MapFollowLiveBus
                    busId={followLiveBusId}
                    lat={Number(followLiveBus.location.lat)}
                    lng={Number(followLiveBus.location.lng)}
                  />
                ) : null}
                {followLiveBusId ? <MapFollowStopOnUserPan onStop={() => setFollowLiveBusId(null)} /> : null}
                {mapHighlightStudent && userHas(user, 'map_global_view') && (
                  <Marker position={[mapHighlightStudent.lat, mapHighlightStudent.lng]} icon={stopMapIcon}>
                    <Popup>{mapHighlightStudent.name}</Popup>
                  </Marker>
                )}
                {mapSpotHighlight && (userHas(user, 'map_global_view') || isSchoolStaffRole(user.role)) && (
                  <Marker position={[mapSpotHighlight.lat, mapSpotHighlight.lng]} icon={gpsSpotIcon}>
                    <Popup>{mapSpotHighlight.label}</Popup>
                  </Marker>
                )}
                {mapShowSchools &&
                  mapSchoolsWithCoords.map((sch) => (
                    <Marker key={`school-${sch.id}`} position={[sch.lat as number, sch.lng as number]} icon={schoolMapIcon}>
                      <Popup>
                        <div className="text-sm max-w-[14rem]">
                          <div className="font-bold text-slate-900">{sch.name}</div>
                          {sch.address_line1 ? (
                            <div className="mt-1 text-xs text-slate-600">{String(sch.address_line1)}</div>
                          ) : null}
                          {sch.address_city ? (
                            <div className="text-xs text-slate-500">{String(sch.address_city)}</div>
                          ) : null}
                          {(userHas(user, 'map_global_view') || isSchoolStaffRole(user.role)) && (
                            <div className="mt-2 flex flex-wrap gap-2 text-[11px] text-slate-600">
                              <span>
                                {t('schoolAdmin.colStudents')}: {sch.student_count ?? '—'}
                              </span>
                              <span>
                                {t('schoolAdmin.colClasses')}: {sch.class_count ?? '—'}
                              </span>
                            </div>
                          )}
                        </div>
                      </Popup>
                    </Marker>
                  ))}
                {mapShowStops &&
                  canViewMapStops &&
                  mapActiveStudentStops.map((student) => {
                    const pickup = studentPickupCoords(student);
                    if (!pickup) return null;
                    const addr = student.address as { line1?: string; city?: string } | undefined;
                    return (
                      <Marker key={`stu-${student.id}`} position={[pickup.lat, pickup.lng]} icon={stopMapIcon}>
                        <Popup>
                          <div className="text-sm">
                            <div className="font-semibold">
                              {t('dashboard.stop')}: {student.name}
                            </div>
                            {addr?.line1 ? (
                              <div className="mt-1 text-xs text-slate-600">
                                {addr.line1}
                                {addr.city ? ` · ${addr.city}` : ''}
                              </div>
                            ) : null}
                          </div>
                        </Popup>
                      </Marker>
                    );
                  })}
                {mapShowBuses &&
                  buses.map((bus) => {
                  const nextStop = getNextStopForDriver(bus.trip);
                  const speedKmh = bus.telemetry?.speed ?? bus.speed;
                  return (
                    <React.Fragment key={bus.id}>
                      {activeRouteBusId === bus.id && bus.route?.length > 0 && (
                        <Polyline
                          positions={detailedRoutes[bus.id] || bus.route.map((p: { lat: number; lng: number }) => [p.lat, p.lng])}
                          pathOptions={{ color: '#3b82f6', weight: 5, opacity: 0.8 }}
                        />
                      )}
                      <Marker
                        position={[bus.location.lat, bus.location.lng]}
                        icon={busMapIcon}
                        eventHandlers={{
                          click: () => {
                            setMapHighlightStudent(null);
                            setMapSpotHighlight(null);
                            setActiveRouteBusId(null);
                          },
                        }}
                      >
                        <Popup>
                          <div className="font-sans min-w-0 max-w-[min(320px,calc(100vw-2rem))] text-start">
                            <div className="flex justify-between items-start gap-2 mb-2 border-b border-indigo-100 pb-2">
                              <h3 className="font-bold text-sm bg-blue-100 text-blue-800 px-2 py-1 rounded">
                                {t('dashboard.vehicle')}: {bus.license_plate || bus.imei || '—'}
                              </h3>
                              <div className="text-[9px] text-green-600 bg-green-50 border border-green-200 px-1.5 py-0.5 rounded flex items-center gap-1 font-bold shrink-0">
                                <div className="w-1.5 h-1.5 bg-green-500 rounded-full animate-pulse" /> {t('dashboard.live')}
                              </div>
                            </div>
                            {bus.school_name && (
                              <p className="text-xs text-slate-700 mb-1">
                                <span className="text-slate-500">{t('dashboard.school')}: </span>
                                {bus.school_name}
                              </p>
                            )}
                            <div className="text-[11px] space-y-1.5 mb-2 bg-slate-50 p-2 rounded border border-slate-100">
                              <div className="font-mono">
                                <span className="text-slate-500">IMEI: </span>
                                <span className="text-slate-900">{bus.imei || '—'}</span>
                              </div>
                              {(bus.capacity != null || bus.occupancy != null) && (
                                <div>
                                  <span className="text-slate-500">{t('dashboard.occupancy')}: </span>
                                  <span className="font-semibold text-slate-800">
                                    {bus.occupancy ?? '—'} / {bus.capacity ?? '—'}
                                  </span>
                                </div>
                              )}
                              <div>
                                <span className="text-slate-500">{t('fleet.speedLabel')}: </span>
                                <span className="font-mono">{speedKmh != null ? `${speedKmh} km/h` : '—'}</span>
                              </div>
                              <div>
                                <span className="text-slate-500">{t('dashboard.lastPing')}: </span>
                                <span className="font-mono text-[10px]">
                                  {bus.last_ping ? new Date(bus.last_ping).toLocaleString() : '—'}
                                </span>
                              </div>
                              <div className="pt-1 border-t border-slate-200">
                                <div className="text-[10px] font-bold text-indigo-700 uppercase tracking-wide mb-0.5">{t('dashboard.nextStopDriver')}</div>
                                {nextStop ? (
                                  <>
                                    <div className="font-semibold text-slate-900">{nextStop.name}</div>
                                    {nextStop.detail && <div className="text-[10px] text-slate-500 font-mono">{nextStop.detail}</div>}
                                  </>
                                ) : (
                                  <div className="text-slate-500 text-[11px]">{t('dashboard.nextStopNone')}</div>
                                )}
                              </div>
                              {bus.telemetry && (
                                <div className="flex justify-between pt-1 border-t border-slate-200 text-[10px] text-slate-600">
                                  <span>{bus.telemetry.voltage}</span>
                                  <span>{bus.telemetry.satellites} sat</span>
                                </div>
                              )}
                            </div>
                            <div className="flex flex-col gap-1.5">
                              <button
                                type="button"
                                onClick={(e) => {
                                  e.stopPropagation();
                                  toggleFollowLiveBus(bus.id);
                                }}
                                className={`w-full flex items-center justify-center gap-1.5 text-white text-xs font-semibold py-1.5 rounded transition ${
                                  followLiveBusId === bus.id
                                    ? 'bg-orange-600 hover:bg-orange-700'
                                    : 'bg-emerald-600 hover:bg-emerald-700'
                                }`}
                              >
                                <Navigation className="w-3.5 h-3.5" aria-hidden />
                                {followLiveBusId === bus.id ? t('dashboard.stopFollowLive') : t('dashboard.followLive')}
                              </button>
                              <button
                                type="button"
                                onClick={(e) => {
                                  e.stopPropagation();
                                  setPassengersModalBus(bus);
                                }}
                                className="w-full flex items-center justify-center gap-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-xs font-semibold py-1.5 rounded transition"
                              >
                                <Users className="w-3.5 h-3.5" /> {t('dashboard.viewPassengers')}
                              </button>
                              <button
                                type="button"
                                onClick={(e) => {
                                  e.stopPropagation();
                                  setActiveRouteBusId(bus.id === activeRouteBusId ? null : bus.id);
                                }}
                                className="w-full bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold py-1.5 rounded transition"
                              >
                                {activeRouteBusId === bus.id ? t('dashboard.closeRoute') : t('dashboard.viewRoute')}
                              </button>
                            </div>
                          </div>
                        </Popup>
                      </Marker>
                    </React.Fragment>
                  );
                })}
              </MapContainer>
            </div>
            {passengersModalBus && (
              <div
                className="fixed inset-0 z-[1000] flex items-end justify-center bg-slate-900/50 p-0 pt-[env(safe-area-inset-top)] sm:items-center sm:p-4"
                role="dialog"
                aria-modal="true"
                aria-labelledby="passengers-modal-title"
                onClick={() => setPassengersModalBus(null)}
              >
                <div
                  className="flex max-h-[min(85dvh,560px)] w-full max-w-md flex-col overflow-hidden rounded-t-2xl border border-slate-200 bg-white shadow-xl sm:rounded-2xl"
                  onClick={(e) => e.stopPropagation()}
                >
                  <div className="flex items-center justify-between gap-2 border-b border-slate-100 px-4 py-3">
                    <h2 id="passengers-modal-title" className="min-w-0 truncate text-sm font-bold text-slate-900">
                      {t('dashboard.passengersTitle')} — {passengersModalBus.license_plate || passengersModalBus.imei}
                    </h2>
                    <button
                      type="button"
                      className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-slate-500 hover:bg-slate-100 hover:text-slate-800"
                      onClick={() => setPassengersModalBus(null)}
                      aria-label={t('common.cancel')}
                    >
                      ×
                    </button>
                  </div>
                  <div className="overflow-y-auto overscroll-y-contain p-4 pb-[max(1rem,env(safe-area-inset-bottom))] text-sm">
                    {!passengersModalBus.trip?.stops?.length ? (
                      <p className="text-slate-500">{t('dashboard.nextStopNone')}</p>
                    ) : (
                      <ul className="space-y-2">
                        {passengersModalBus.trip.stops.map(
                          (
                            stop: {
                              student_id?: string;
                              status?: string;
                              student?: { name?: string } | null;
                            },
                            i: number
                          ) => (
                            <li key={`${stop.student_id}-${i}`} className="flex justify-between gap-2 border border-slate-100 rounded-lg px-3 py-2 bg-slate-50">
                              <span className="font-medium text-slate-800">{stop.student?.name || stop.student_id || '—'}</span>
                              <span className="text-xs text-slate-600 shrink-0">{tripStopStatusLabel(stop.status, t)}</span>
                            </li>
                          )
                        )}
                      </ul>
                    )}
                  </div>
                </div>
              </div>
            )}
          </>
        )}
      </main>
    </div>
  );
}

function Shell({
  user,
  needsBootstrap,
  onAuthChange,
}: {
  user: User | null;
  needsBootstrap: boolean;
  onAuthChange: (u: User | null, nb: boolean) => void;
}) {
  const logout = async () => {
    await api('/api/auth/logout', { method: 'POST' });
    disconnectSocket();
    onAuthChange(null, false);
  };

  if (!user) {
    return <Login onSuccess={(u, nb) => onAuthChange(u, nb)} />;
  }
  if (needsBootstrap) {
    return <BootstrapWizard onDone={() => onAuthChange(null, false)} />;
  }
  if (isDriverRole(user.role)) {
    return <DriverDashboard user={user} onLogout={() => void logout()} />;
  }
  return <Dashboard user={user} onLogout={() => void logout()} />;
}

function AuthenticatedApp() {
  const [user, setUser] = useState<User | null>(null);
  const [needsBootstrap, setNeedsBootstrap] = useState(false);
  const [checked, setChecked] = useState(false);

  useEffect(() => {
    void api('/api/auth/me')
      .then(async (r) => {
        if (r.status === 503) throw new Error('db');
        if (!r.ok) throw new Error();
        return parseFetchJson<{ user: User | null; needsBootstrap?: boolean }>(r);
      })
      .then((d) => {
        setUser(d.user ?? null);
        setNeedsBootstrap(!!d.needsBootstrap);
      })
      .catch(() => {
        setUser(null);
        setNeedsBootstrap(false);
      })
      .finally(() => setChecked(true));
  }, []);

  if (!checked) {
    return <BootLoading />;
  }

  return (
    <BrowserRouter>
      <Routes>
        <Route
          path="/"
          element={<Shell user={user} needsBootstrap={needsBootstrap} onAuthChange={(u, nb) => { setUser(u); setNeedsBootstrap(nb); }} />}
        />
      </Routes>
    </BrowserRouter>
  );
}

export default function App() {
  const [comingSoonUnlocked, setComingSoonUnlocked] = useState(
    () => typeof sessionStorage !== 'undefined' && sessionStorage.getItem(COMING_SOON_UNLOCK_STORAGE_KEY) === '1',
  );

  const unlockComingSoonLogin = () => {
    try {
      sessionStorage.setItem(COMING_SOON_UNLOCK_STORAGE_KEY, '1');
    } catch {
      /* private browsing / storage blocked */
    }
    setComingSoonUnlocked(true);
  };

  /* Web-only gate — Android/iOS native apps do not load this bundle for auth. */
  if (COMING_SOON_ENABLED && !comingSoonUnlocked) {
    return (
      <BrowserRouter>
        <Routes>
          <Route path="*" element={<ComingSoonPage onUnlock={unlockComingSoonLogin} />} />
        </Routes>
      </BrowserRouter>
    );
  }
  return <AuthenticatedApp />;
}
