Untitled

Anonymous
tsx
10/17/2026 8:52 PM
41.8 KB
5
Indexable
import { useState, useMemo, useEffect, useCallback, lazy, Suspense } from 'react';
import { Link } from 'react-router-dom';
import {
  Settings as SettingsIcon,
  Search,
  SlidersHorizontal,
  Star,
  Gauge,
  Zap,
  CircleDot,
  ArrowRight,
  ChevronDown,
  X,
  Heart,
  Trophy,
  CarFront,
  RotateCcw,
} from 'lucide-react';
import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
import { ALL_CARS } from '@/data/cars';
import CarSilhouette from '@/components/CarSilhouette';
import TuneModal from '@/components/TuneModal';

const DrivingGame = lazy(() => import('@/components/DrivingGame'));

const CLASS_FILTERS = ['All', 'Hyper', 'Super', 'Sports', 'Muscle', 'GT', 'Sedan', 'Hatch', 'SUV', 'Truck', 'Classic'];
const TUNES_KEY = 'vd-tunes';
const FAVORITES_KEY = 'vd-favorites';

const screenMotion = {
  initial: { opacity: 0, y: 12 },
  animate: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: -8 },
  transition: { duration: 0.2, ease: 'easeOut' },
};

const clamp = (value, min = 0, max = 100) => Math.max(min, Math.min(max, Number(value) || 0));

function readStorage(key, fallback) {
  if (typeof window === 'undefined') return fallback;
  try {
    const value = JSON.parse(window.localStorage.getItem(key) || 'null');
    return value ?? fallback;
  } catch {
    return fallback;
  }
}

function normalizeTunes(value) {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return {};
  return Object.fromEntries(
    Object.entries(value).filter(([, tune]) => tune && typeof tune === 'object' && !Array.isArray(tune)),
  );
}

function DriveLoading() {
  return (
    <div className="fixed inset-0 z-50 flex flex-col items-center justify-center gap-4 bg-[#05070c] text-white">
      <div className="relative flex h-14 w-14 items-center justify-center rounded-2xl border border-orange-400/30 bg-orange-400/10">
        <CarFront className="h-7 w-7 text-orange-300" />
        <span className="absolute -inset-1 animate-ping rounded-2xl border border-orange-400/20" />
      </div>
      <div className="text-center">
        <p className="text-xs font-black uppercase tracking-[0.28em] text-orange-300">Starting engine</p>
        <p className="mt-1 text-xs text-white/40">Loading the driving session…</p>
      </div>
    </div>
  );
}

function StatBar({ label, value, color, icon: Icon }) {
  const safeValue = clamp(value);
  return (
    <div className="grid grid-cols-[82px_minmax(0,1fr)_30px] items-center gap-2.5">
      <span className="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-[0.15em] text-white/45">
        {Icon ? <Icon className="h-3.5 w-3.5" aria-hidden="true" /> : null}
        {label}
      </span>
      <div className="h-1.5 overflow-hidden rounded-full bg-white/[0.08]">
        <motion.div
          className={`h-full rounded-full ${color}`}
          initial={false}
          animate={{ width: `${safeValue}%` }}
          transition={{ type: 'spring', stiffness: 120, damping: 22 }}
        />
      </div>
      <span className="text-right font-mono text-[10px] tabular-nums text-white/60">{Math.round(safeValue)}</span>
    </div>
  );
}

function GarageEmpty({ onReset }) {
  return (
    <div className="col-span-full flex min-h-56 flex-col items-center justify-center rounded-3xl border border-dashed border-white/10 bg-white/[0.02] px-5 text-center">
      <Search className="h-8 w-8 text-white/25" aria-hidden="true" />
      <h3 className="mt-3 text-sm font-bold text-white/80">No cars match those filters</h3>
      <p className="mt-1 max-w-xs text-xs leading-5 text-white/40">Try another model name, choose a different class, or reset the filters.</p>
      <button onClick={onReset} className="mt-4 inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-xs font-semibold text-white/70 transition hover:bg-white/10 hover:text-white">
        <RotateCcw className="h-3.5 w-3.5" /> Reset garage filters
      </button>
    </div>
  );
}

function ModeCard({ icon: Icon, title, eyebrow, description, accent, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      className="group relative overflow-hidden rounded-2xl border border-white/10 bg-white/[0.035] p-5 text-left transition duration-200 hover:-translate-y-0.5 hover:border-orange-400/40 hover:bg-orange-400/[0.04] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-400"
    >
      <div className={`absolute -right-5 -top-5 h-28 w-28 rounded-full blur-3xl transition group-hover:opacity-80 ${accent}`} />
      <div className="relative">
        <div className="mb-7 flex items-start justify-between">
          <span className="flex h-12 w-12 items-center justify-center rounded-2xl border border-white/10 bg-black/20">
            <Icon className="h-6 w-6 text-orange-200" />
          </span>
          <span className="rounded-full border border-white/10 px-2.5 py-1 text-[9px] font-black uppercase tracking-[0.18em] text-white/45">{eyebrow}</span>
        </div>
        <h3 className="text-xl font-black tracking-tight text-white">{title}</h3>
        <p className="mt-2 max-w-sm text-xs leading-5 text-white/50">{description}</p>
        <div className="mt-5 flex items-center gap-2 text-xs font-bold text-orange-300">
          Enter event <ArrowRight className="h-3.5 w-3.5 transition group-hover:translate-x-1" />
        </div>
      </div>
    </button>
  );
}

export default function Game() {
  const reduceMotion = useReducedMotion();
  const firstCarId = ALL_CARS?.[0]?.id ?? null;
  const [filter, setFilter] = useState('All');
  const [search, setSearch] = useState('');
  const [sortBy, setSortBy] = useState('featured');
  const [favoritesOnly, setFavoritesOnly] = useState(false);
  const [selectedId, setSelectedId] = useState(firstCarId);
  const [screen, setScreen] = useState('garage'); // 'garage' | 'mode' | 'drive'
  const [mode, setMode] = useState('open');
  const [tuneOpen, setTuneOpen] = useState(false);
  const [tunes, setTunes] = useState(() => normalizeTunes(readStorage(TUNES_KEY, {})));
  const [favorites, setFavorites] = useState(() => {
    const stored = readStorage(FAVORITES_KEY, []);
    return Array.isArray(stored) ? stored.filter((id) => typeof id === 'string' || typeof id === 'number') : [];
  });
  const [modeDialogOpen, setModeDialogOpen] = useState(false);

  const selected = useMemo(
    () => ALL_CARS.find((car) => car.id === selectedId) || ALL_CARS[0] || null,
    [selectedId],
  );

  // Persist separately from state updates: React updater functions remain pure.
  useEffect(() => {
    try { window.localStorage.setItem(TUNES_KEY, JSON.stringify(tunes)); } catch { /* storage can be blocked or full */ }
  }, [tunes]);

  useEffect(() => {
    try { window.localStorage.setItem(FAVORITES_KEY, JSON.stringify(favorites)); } catch { /* storage is optional */ }
  }, [favorites]);

  // The base car data remains unchanged; tuning is an overlay for the driving component.
  const tuned = useMemo(() => {
    if (!selected) return null;
    const tune = tunes[selected.id] || {};
    const speedDelta = Number.isFinite(Number(tune.engine)) ? Number(tune.engine) : 0;
    const accelDelta = Number.isFinite(Number(tune.turbo)) ? Number(tune.turbo) : 0;
    const gripDelta = Number.isFinite(Number(tune.tires)) ? Number(tune.tires) : 0;
    const nosValue = Number(tune.nos);
    return {
      ...selected,
      topSpeed: clamp(Number(selected.topSpeed) + speedDelta, 30, 100),
      accel: clamp(Number(selected.accel) + accelDelta, 30, 100),
      grip: clamp(Number(selected.grip) + gripDelta, 30, 100),
      nitroMax: Number.isFinite(nosValue) ? clamp(nosValue, 0, 200) : 100,
    };
  }, [selected, tunes]);

  const list = useMemo(() => {
    const normalizedSearch = search.trim().toLocaleLowerCase();
    const filtered = ALL_CARS.filter((car) => {
      const classMatches = filter === 'All' || car.class === filter;
      const favoriteMatches = !favoritesOnly || favorites.includes(car.id);
      const searchMatches = !normalizedSearch || [car.name, car.brand, car.class, car.id]
        .some((value) => String(value ?? '').toLocaleLowerCase().includes(normalizedSearch));
      return classMatches && favoriteMatches && searchMatches;
    });

    if (sortBy === 'speed') return [...filtered].sort((a, b) => (Number(b.topSpeed) || 0) - (Number(a.topSpeed) || 0));
    if (sortBy === 'accel') return [...filtered].sort((a, b) => (Number(b.accel) || 0) - (Number(a.accel) || 0));
    if (sortBy === 'name') return [...filtered].sort((a, b) => String(a.name).localeCompare(String(b.name)));
    if (sortBy === 'brand') return [...filtered].sort((a, b) => String(a.brand).localeCompare(String(b.brand)) || String(a.name).localeCompare(String(b.name)));
    return filtered;
  }, [filter, search, sortBy, favorites, favoritesOnly]);

  const setTune = useCallback((id, nextTune) => {
    if (id == null || !nextTune || typeof nextTune !== 'object') return;
    setTunes((previous) => ({ ...previous, [id]: { ...(previous[id] || {}), ...nextTune } }));
  }, []);

  const resetFilters = useCallback(() => {
    setFilter('All');
    setSearch('');
    setSortBy('featured');
    setFavoritesOnly(false);
  }, []);

  const toggleFavorite = useCallback((id) => {
    setFavorites((previous) => previous.includes(id) ? previous.filter((item) => item !== id) : [...previous, id]);
  }, []);

  const chooseCar = useCallback((id) => {
    setSelectedId(id);
    setTuneOpen(false);
  }, []);

  const closeModeDialog = useCallback(() => {
    setModeDialogOpen(false);
    setScreen('garage');
  }, []);

  const enterMode = useCallback((nextMode) => {
    setMode(nextMode);
    setModeDialogOpen(false);
    setTuneOpen(false);
    setScreen('drive');
  }, []);

  if (!selected || !tuned) {
    return (
      <div className="flex min-h-screen items-center justify-center bg-[#070910] px-6 text-center text-white">
        <div className="max-w-md rounded-3xl border border-white/10 bg-white/[0.03] p-8">
          <CarFront className="mx-auto h-9 w-9 text-orange-300" />
          <h1 className="mt-4 text-xl font-black">Garage unavailable</h1>
          <p className="mt-2 text-sm leading-6 text-white/50">No vehicle data was found in <code>ALL_CARS</code>. Add at least one car to <code>@/data/cars</code> and reload the garage.</p>
        </div>
      </div>
    );
  }

  return (
    <AnimatePresence mode="wait" initial={false}>
      {screen === 'drive' ? (
        <motion.div key="drive" {...screenMotion} transition={reduceMotion ? { duration: 0 } : screenMotion.transition} className="fixed inset-0 z-50 bg-[#05070c]">
          <Suspense fallback={<DriveLoading />}>
            <DrivingGame car={tuned} mode={mode} onExit={() => setScreen('garage')} />
          </Suspense>
        </motion.div>
      ) : (
        <motion.div key="garage" {...screenMotion} transition={reduceMotion ? { duration: 0 } : screenMotion.transition} className="min-h-screen overflow-hidden bg-[#070910] text-white selection:bg-orange-400/30">
          <div className="pointer-events-none fixed inset-0 opacity-40" aria-hidden="true" style={{ background: 'radial-gradient(ellipse at 12% -5%, rgba(249,115,22,.15), transparent 32%), radial-gradient(ellipse at 90% 35%, rgba(14,165,233,.08), transparent 36%)' }} />
          <header className="sticky top-0 z-30 border-b border-white/[0.07] bg-[#070910]/85 backdrop-blur-2xl">
            <div className="mx-auto flex max-w-[1500px] items-center justify-between gap-4 px-4 py-3.5 sm:px-6 lg:px-8">
              <Link to="/game" className="group flex min-w-0 items-center gap-3" aria-label="Velocity Drift home">
                <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-orange-400/25 bg-orange-400/10 text-orange-300 shadow-lg shadow-orange-950/20">
                  <Gauge className="h-5 w-5" />
                </span>
                <span className="min-w-0">
                  <span className="block truncate text-lg font-black tracking-tight sm:text-xl">VELOCITY<span className="text-orange-400">DRIFT</span></span>
                  <span className="block truncate text-[9px] font-bold uppercase tracking-[0.22em] text-white/35">Street racing · tuned by you</span>
                </span>
              </Link>
              <div className="hidden items-center gap-5 md:flex">
                <div className="text-right">
                  <p className="text-[10px] font-bold uppercase tracking-[0.19em] text-white/35">Garage status</p>
                  <p className="mt-0.5 text-xs font-semibold text-white/75">{ALL_CARS.length} machines · {favorites.length} saved</p>
                </div>
                <div className="h-8 w-px bg-white/10" />
              </div>
              <Link to="/settings" aria-label="Settings" title="Settings" className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-white/10 bg-white/[0.04] text-white/55 transition hover:border-white/20 hover:bg-white/[0.08] hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-400">
                <SettingsIcon className="h-4 w-4" />
              </Link>
            </div>
          </header>

          <main className="relative mx-auto max-w-[1500px] px-4 py-6 sm:px-6 sm:py-8 lg:px-8">
            <div className="mb-6 flex flex-wrap items-end justify-between gap-3">
              <div>
                <p className="mb-2 flex items-center gap-2 text-[10px] font-black uppercase tracking-[0.25em] text-orange-300"><span className="h-px w-6 bg-orange-400" /> Driver profile / 001</p>
                <h1 className="text-3xl font-black tracking-[-0.045em] sm:text-4xl">Your next <span className="text-white/40">machine.</span></h1>
                <p className="mt-2 max-w-xl text-xs leading-5 text-white/40 sm:text-sm">Inspect your build, fine-tune its setup, and choose how you want to drive.</p>
              </div>
              <div className="flex items-center gap-2 rounded-xl border border-white/[0.08] bg-white/[0.03] px-3 py-2.5">
                <span className="relative flex h-2 w-2"><span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400/60" /><span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-400" /></span>
                <span className="text-[10px] font-bold uppercase tracking-[0.15em] text-white/55">Systems ready</span>
              </div>
            </div>

            <section className="mb-9 grid gap-4 xl:grid-cols-[minmax(0,1.45fr)_minmax(330px,.75fr)]">
              <div className="group relative isolate min-h-[330px] overflow-hidden rounded-[28px] border border-white/10 bg-[#0d111a] p-5 sm:min-h-[390px] sm:p-8">
                <div className="absolute inset-0 -z-20 bg-gradient-to-br from-[#141b27] via-[#0c111a] to-[#080b11]" />
                <div className="absolute -right-24 -top-28 -z-10 h-80 w-80 rounded-full blur-3xl transition duration-700 group-hover:scale-110" style={{ background: `radial-gradient(circle, ${selected.color || '#f97316'}3b 0%, transparent 69%)` }} />
                <div className="absolute inset-x-0 bottom-0 -z-10 h-32 bg-gradient-to-t from-black/55 to-transparent" />
                <div className="absolute bottom-12 left-0 right-0 -z-10 h-px bg-gradient-to-r from-transparent via-white/15 to-transparent" />
                <div className="relative flex h-full min-h-[280px] flex-col">
                  <div className="flex flex-wrap items-center gap-2">
                    <span className="rounded-md border border-orange-300/25 bg-orange-300/10 px-2 py-1 text-[9px] font-black uppercase tracking-[0.18em] text-orange-200">{selected.class}</span>
                    <span className="text-[11px] font-semibold text-white/40">{selected.brand}</span>
                    <button onClick={() => toggleFavorite(selected.id)} className={`ml-auto inline-flex items-center gap-1.5 rounded-lg border px-2.5 py-1.5 text-[10px] font-bold transition ${favorites.includes(selected.id) ? 'border-rose-400/30 bg-rose-400/10 text-rose-200' : 'border-white/10 bg-black/10 text-white/45 hover:text-white'}`} aria-pressed={favorites.includes(selected.id)}>
                      <Heart className={`h-3.5 w-3.5 ${favorites.includes(selected.id) ? 'fill-current' : ''}`} />
                      {favorites.includes(selected.id) ? 'Saved' : 'Save car'}
                    </button>
                  </div>
                  <div className="mt-4">
                    <h2 className="max-w-3xl text-3xl font-black tracking-[-0.045em] sm:text-5xl">{selected.name}</h2>
                    <p className="mt-2 text-xs text-white/40 sm:text-sm">Selected vehicle <span className="mx-1.5 text-white/20">/</span> {String(selected.id)}</p>
                  </div>
                  <div className="relative mt-auto flex min-h-[150px] flex-1 items-center justify-center pt-5 sm:min-h-[190px]">
                    <div className="absolute bottom-3 h-10 w-[78%] rounded-[50%] bg-black/60 blur-2xl" />
                    <div className="absolute bottom-6 h-px w-[86%] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
                    <CarSilhouette car={selected} className="relative z-10 h-40 w-full max-w-[610px] drop-shadow-[0_25px_25px_rgba(0,0,0,0.65)] sm:h-52" />
                  </div>
                  <div className="mt-2 flex flex-wrap items-center justify-between gap-3 border-t border-white/[0.08] pt-4">
                    <div className="flex items-center gap-2 text-[10px] font-bold uppercase tracking-[0.13em] text-white/40"><CircleDot className="h-3.5 w-3.5 text-orange-300" /> Build preview</div>
                    <div className="text-right text-[10px] text-white/30">Paint <span className="ml-1 inline-block h-2.5 w-2.5 rounded-full border border-white/30 align-middle" style={{ background: selected.color || '#888' }} /></div>
                  </div>
                </div>
              </div>

              <div className="flex flex-col rounded-[28px] border border-white/10 bg-[#0c1018] p-5 sm:p-7">
                <div className="flex items-start justify-between gap-3">
                  <div><p className="text-[9px] font-black uppercase tracking-[0.24em] text-orange-300">Vehicle telemetry</p><h3 className="mt-1 text-xl font-black tracking-tight">Performance profile</h3></div>
                  <span className="flex h-10 w-10 items-center justify-center rounded-xl border border-white/10 bg-white/[0.035] text-orange-200"><Gauge className="h-5 w-5" /></span>
                </div>
                <div className="mb-5 mt-7 space-y-4">
                  <StatBar label="Speed" value={tuned.topSpeed} color="bg-gradient-to-r from-orange-500 to-orange-300" icon={Gauge} />
                  <StatBar label="Accel" value={tuned.accel} color="bg-gradient-to-r from-amber-500 to-yellow-300" icon={Zap} />
                  <StatBar label="Grip" value={tuned.grip} color="bg-gradient-to-r from-cyan-500 to-sky-300" icon={CircleDot} />
                </div>
                <div className="grid grid-cols-3 gap-2">
                  {[{ label: 'Top speed', value: tuned.topSpeed, unit: '/100' }, { label: 'Launch', value: tuned.accel, unit: '/100' }, { label: 'Cornering', value: tuned.grip, unit: '/100' }].map((stat) => (
                    <div key={stat.label} className="rounded-2xl border border-white/[0.07] bg-white/[0.025] p-3">
                      <div className="font-mono text-xl font-black tabular-nums sm:text-2xl">{stat.value}<span className="ml-0.5 text-[9px] font-semibold text-white/25">{stat.unit}</span></div>
                      <div className="mt-1 text-[9px] font-bold uppercase tracking-[0.11em] text-white/35">{stat.label}</div>
                    </div>
                  ))}
                </div>
                <div className="mt-auto space-y-2.5 pt-7">
                  <button onClick={() => { setModeDialogOpen(true); setScreen('mode'); }} className="group flex w-full items-center justify-between rounded-2xl bg-gradient-to-r from-orange-500 to-red-600 px-5 py-4 text-left font-black shadow-lg shadow-orange-950/30 transition hover:brightness-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-300">
                    <span><span className="block text-[9px] font-black uppercase tracking-[0.2em] text-white/70">Ready when you are</span><span className="mt-0.5 block text-sm">Start engine</span></span>
                    <span className="flex h-9 w-9 items-center justify-center rounded-xl bg-black/15 transition group-hover:translate-x-0.5"><ArrowRight className="h-4 w-4" /></span>
                  </button>
                  <button onClick={() => setTuneOpen(true)} className="flex w-full items-center justify-center gap-2 rounded-2xl border border-white/10 bg-white/[0.035] py-3 text-xs font-bold text-white/70 transition hover:border-white/20 hover:bg-white/[0.06] hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-300">
                    <SlidersHorizontal className="h-4 w-4" /> Open tuning shop
                  </button>
                </div>
              </div>
            </section>

            <section aria-labelledby="garage-heading">
              <div className="mb-4 flex flex-wrap items-end justify-between gap-3">
                <div><p className="text-[9px] font-black uppercase tracking-[0.23em] text-orange-300">Vehicle collection</p><h2 id="garage-heading" className="mt-1 text-2xl font-black tracking-tight sm:text-3xl">Choose your ride<span className="text-white/25">.</span></h2><p className="mt-1.5 text-xs text-white/40">{list.length} of {ALL_CARS.length} vehicles shown</p></div>
                <button onClick={() => setFavoritesOnly((value) => !value)} aria-pressed={favoritesOnly} className={`inline-flex items-center gap-2 rounded-xl border px-3 py-2.5 text-xs font-bold transition ${favoritesOnly ? 'border-rose-300/30 bg-rose-300/10 text-rose-200' : 'border-white/10 bg-white/[0.03] text-white/55 hover:text-white'}`}><Star className={`h-3.5 w-3.5 ${favoritesOnly ? 'fill-current' : ''}`} /> Favorites <span className="font-mono">{favorites.length}</span></button>
              </div>
              <div className="mb-4 grid gap-2 sm:grid-cols-[minmax(0,1fr)_170px]">
                <label className="relative block">
                  <Search className="pointer-events-none absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-white/30" />
                  <input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="Search make, model or class…" aria-label="Search cars" className="h-11 w-full rounded-xl border border-white/[0.09] bg-white/[0.025] pl-10 pr-4 text-xs text-white outline-none transition placeholder:text-white/25 focus:border-orange-400/50 focus:bg-white/[0.04] focus:ring-2 focus:ring-orange-400/10" />
                </label>
                <label className="relative flex items-center">
                  <span className="sr-only">Sort vehicles</span>
                  <select value={sortBy} onChange={(event) => setSortBy(event.target.value)} className="h-11 w-full appearance-none rounded-xl border border-white/[0.09] bg-[#0c1018] px-3.5 pr-9 text-xs text-white/70 outline-none focus:border-orange-400/50">
                    <option value="featured">Featured order</option><option value="speed">Highest speed</option><option value="accel">Best acceleration</option><option value="name">Name A–Z</option><option value="brand">Make A–Z</option>
                  </select><ChevronDown className="pointer-events-none absolute right-3 h-3.5 w-3.5 text-white/35" />
                </label>
              </div>
              <div className="mb-5 flex flex-wrap gap-2">
                {CLASS_FILTERS.map((className) => (
                  <button key={className} onClick={() => setFilter(className)} aria-pressed={filter === className} className={`rounded-full border px-3.5 py-2 text-[10px] font-bold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-300 ${filter === className ? 'border-orange-400/40 bg-orange-400 text-[#180e08] shadow-md shadow-orange-950/20' : 'border-white/[0.07] bg-white/[0.025] text-white/50 hover:border-white/15 hover:text-white/80'}`}>
                    {className}
                  </button>
                ))}
                {(search || filter !== 'All' || favoritesOnly || sortBy !== 'featured') && <button onClick={resetFilters} className="inline-flex items-center gap-1.5 px-2 text-[10px] font-bold text-orange-200/70 transition hover:text-orange-100"><X className="h-3 w-3" /> Reset</button>}
              </div>

              <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6">
                {list.length === 0 ? <GarageEmpty onReset={resetFilters} /> : list.map((car, index) => {
                  const active = selectedId === car.id;
                  const favorite = favorites.includes(car.id);
                  const carTune = tunes[car.id] || {};
                  const displayedSpeed = clamp(Number(car.topSpeed) + (Number(carTune.engine) || 0), 30, 100);
                  return (
                    <motion.div
                      layout={!reduceMotion}
                      key={car.id}
                      className={`group relative overflow-hidden rounded-2xl border p-3 transition duration-200 ${active ? 'border-orange-400/55 bg-orange-400/[0.055] shadow-lg shadow-orange-950/10' : 'border-white/[0.07] bg-[#0c1018] hover:-translate-y-0.5 hover:border-white/20 hover:bg-[#101520]'}`}
                    >
                      <button type="button" onClick={() => chooseCar(car.id)} aria-pressed={active} aria-label={`Select ${car.brand} ${car.name}`} className="block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-orange-400">
                        <div className="relative mb-3 flex h-[94px] items-center justify-center overflow-hidden rounded-xl bg-gradient-to-b from-white/[0.045] to-black/20 sm:h-[105px]">
                          <div className="absolute inset-x-3 bottom-4 h-4 rounded-[50%] bg-black/45 blur-xl" />
                          <div className="absolute inset-x-4 bottom-3 h-px bg-gradient-to-r from-transparent via-white/15 to-transparent" />
                          <CarSilhouette car={car} className="relative h-[70px] w-full max-w-[230px] transition duration-300 group-hover:scale-[1.045] sm:h-[80px]" />
                        </div>
                        <div className="flex items-center gap-1.5 text-[9px] font-bold uppercase tracking-[0.14em] text-white/35"><span className="h-2 w-2 rounded-full border border-white/20" style={{ background: car.color || '#888' }} />{car.brand}<span className="ml-auto truncate text-white/25">{car.class}</span></div>
                        <div className="mt-1.5 truncate pr-1 text-sm font-bold tracking-tight text-white/90">{car.name}</div>
                        <div className="mt-3 flex items-center justify-between border-t border-white/[0.07] pt-2.5">
                          <span className="flex items-center gap-1 text-[9px] font-bold uppercase tracking-[0.12em] text-white/35"><Gauge className="h-3 w-3" /> Speed</span>
                          <span className="font-mono text-[11px] font-bold tabular-nums text-white/75">{displayedSpeed}<span className="ml-0.5 text-[9px] text-white/30">/100</span></span>
                        </div>
                        <div className={`mt-2 h-0.5 overflow-hidden rounded-full bg-white/[0.07] ${active ? 'opacity-100' : 'opacity-0 group-hover:opacity-70'}`}><div className="h-full rounded-full bg-gradient-to-r from-orange-500 to-amber-300" style={{ width: `${displayedSpeed}%` }} /></div>
                        {active && <span className="absolute bottom-3 right-3 rounded-md bg-orange-400 px-1.5 py-1 text-[8px] font-black uppercase tracking-wider text-[#170b05]">Selected</span>}
                      </button>
                      <button type="button" onClick={() => toggleFavorite(car.id)} aria-label={favorite ? `Remove ${car.name} from favorites` : `Add ${car.name} to favorites`} aria-pressed={favorite} className={`absolute right-2 top-2 z-10 flex h-7 w-7 items-center justify-center rounded-lg border backdrop-blur-md transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-400 ${favorite ? 'border-rose-300/25 bg-rose-400/15 text-rose-200' : 'border-white/[0.07] bg-black/25 text-white/35 opacity-75 hover:text-white group-hover:opacity-100'}`}>
                        <Heart className={`h-3.5 w-3.5 ${favorite ? 'fill-current' : ''}`} />
                      </button>
                    </motion.div>
                  );
                })}
              </div>
            </section>
          </main>

          <footer className="relative mt-8 border-t border-white/[0.07] bg-black/15 px-4 py-5 text-center sm:px-6">
            <p className="text-[9px] font-bold uppercase tracking-[0.22em] text-white/25">VelocityDrift · Built for the late-night run</p>
          </footer>

          <AnimatePresence>
            {tuneOpen && (
              <motion.div key="tune-modal" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="relative z-40">
                <TuneModal car={tuned} tune={tunes[selectedId]} onChange={(nextTune) => setTune(selectedId, nextTune)} onClose={() => setTuneOpen(false)} />
              </motion.div>
            )}
          </AnimatePresence>

          <AnimatePresence>
            {screen === 'mode' && modeDialogOpen && (
              <motion.div key="mode-dialog" role="presentation" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="fixed inset-0 z-40 flex items-center justify-center bg-black/75 p-4 backdrop-blur-md" onMouseDown={(event) => { if (event.target === event.currentTarget) closeModeDialog(); }}>
                <motion.div role="dialog" aria-modal="true" aria-labelledby="mode-title" initial={{ opacity: 0, y: 12, scale: 0.98 }} animate={{ opacity: 1, y: 0, scale: 1 }} exit={{ opacity: 0, y: 8 }} className="w-full max-w-2xl rounded-[28px] border border-white/10 bg-[#0b1018] p-5 shadow-2xl shadow-black/60 sm:p-8">
                  <div className="flex items-start justify-between gap-4">
                    <div><p className="text-[9px] font-black uppercase tracking-[0.24em] text-orange-300">Event selection</p><h2 id="mode-title" className="mt-1 text-2xl font-black tracking-tight sm:text-3xl">Pick your race.</h2><p className="mt-2 text-xs text-white/40">Ready to drive: <span className="font-semibold text-white/75">{selected.brand} {selected.name}</span></p></div>
                    <button onClick={closeModeDialog} aria-label="Close event selection" className="flex h-9 w-9 items-center justify-center rounded-xl border border-white/10 bg-white/[0.03] text-white/50 transition hover:text-white"><X className="h-4 w-4" /></button>
                  </div>
                  <div className="mt-6 grid gap-3 sm:grid-cols-2">
                    <ModeCard icon={CarFront} title="Open World" eyebrow="Free roam" accent="bg-cyan-500/15" description="Cruise a neon-lit city, weave through traffic, explore at your own pace, and test your tuned build." onClick={() => enterMode('open')} />
                    <ModeCard icon={Trophy} title="Drag Race" eyebrow="402 metres" accent="bg-orange-500/15" description="Launch hard over a true quarter-mile, work through your gears, and use nitro to chase a better time." onClick={() => enterMode('drag')} />
                  </div>
                  <button onClick={closeModeDialog} className="mt-4 w-full rounded-xl py-2.5 text-xs font-semibold text-white/40 transition hover:bg-white/[0.04] hover:text-white/70">Back to garage</button>
                </motion.div>
              </motion.div>
            )}
          </AnimatePresence>
        </motion.div>
      )}
    </AnimatePresence>
  );
}
Editor is loading...
Leave a Comment