# Project export: VroomMates

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Have lots of Mates you and your friends want to pick up? Let VroomMates help you plan out your carpool!
- Devpost: https://devpost.com/software/vroommates
- GitHub: https://github.com/jonnypan2325/VroomMates
- Demo: http://vroommates.co/
- Team: 3 GitHub contributor(s) — eriyoungg (9 commits), Jonathan Pan (6 commits), vyomshah05 (4 commits)

## Devpost submission (written by the team)

### Inspiration

We noticed that whenever there were off-campus club activities, there was always a large number of people in need of rides to get to the venue. Event organizers would do their best to assign drivers for each rider through messy group chats, but the process was often manual, time-consuming, and inefficient. Many times, drivers had to take longer detours to pick up riders who other nearby drivers could have picked up. This led to unnecessary delays and confusion, which often resulted in frustration for both drivers and passengers. With VroomMates, we wanted to centralize and automate the planning of carpools by creating a solution that optimizes rider-driver assignments. The goal was to make the process of organizing rides easier and more efficient for both event organizers and participants. The idea of using technology to solve this common issue inspired us to create a tool that not only streamlines the ride-matching process but also minimizes detours and travel time, making it a win-win for everyone involved.

### What it does

VroomMates is a carpool management system that centralizes the process of organizing carpools for events. It allows users to register as drivers or riders, input their locations and destinations, and automatically match riders with drivers based on optimal routes. VroomMates uses A* for pathfinding and linear distance using the Haversine Formula to cluster the drivers. This reduces unnecessary detours and streamlines transportation logistics.

### How we built it

VroomMates was built using a full-stack approach. The front end was developed with React, leveraging the Google Maps API for location input, tracking, and map displays. The back end was powered by Flask, where Python handled the clustering algorithms to generate optimized driver routes. These routes were stored in Google Datastore, allowing users to save and resume their sessions across devices. We implemented continuous deployment with GitHub Actions and hosted the app on Vercel to streamline development and updates.

### Challenges we ran into

One of the biggest challenges we encountered was creating the Post and Get functions for Flask. Since we modularized the entire project and everybody worked on different parts simultaneously, we saved the Flask implementation for the very last. Even though we were sure that all the parts worked independently, connecting the backend operations to display on the front end proved to be messier than we anticipated.

### Accomplishments we're proud of

We are proud that our program works.

### What we learned

The hackathon prize is the friends we made along the way.

### What's next

Add functionality for live contribution between drivers and riders for the same map. Support the ability to add a desired arrival time and VroomMates will give routes that takes current traffic conditions into consideration. Oh, and IPO as a trillion-dollar company.

## README (from the GitHub repository)

# VroomMates

Carpool webapp — a React + Flask application that groups passengers with drivers
heading to a shared destination and suggests an optimized route for each driver.

The repo contains both the frontend (React, in `src/` and `public/`) and the
backend (Flask, in `app.py` and `backend/`) in a single project.

## Prerequisites

You will need the following installed locally:

- **Node.js** 18 or newer — https://nodejs.org/
- **npm** (ships with Node.js) — verify with `npm --version`
- **Python** 3.10 or newer — https://www.python.org/downloads/
- **pip** (ships with Python) — verify with `pip --version`

> The repo's existing `requirements.txt` was generated against Python 3.12, so
> 3.10+ is recommended. On macOS and most Linux distros, `python` and `pip`
> may be called `python3` and `pip3` — substitute as needed.

## 1. Clone and enter the repo

```bash
git clone https://github.com/jonnypan2325/VroomMates.git
cd VroomMates
```

## 2. Create your `.env` file

Copy the template and fill in your own keys:

```bash
cp .env.example .env
```

Then open `.env` and replace the placeholder values. See
[Getting the Google credentials](#getting-the-google-credentials) below.

## 3. Install Python dependencies

It is strongly recommended to use a virtual environment so the backend's
packages don't pollute your system Python:

```bash
python -m venv .venv
# macOS / Linux:
source .venv/bin/activate
# Windows (PowerShell):
.venv\Scripts\Activate.ps1

pip install -r requirements.txt
```

The `.venv/` directory is already listed in `.gitignore`.

## 4. Install Node dependencies

```bash
npm install
```

This installs both the React app and the dev tooling (including
[`concurrently`](https://www.npmjs.com/package/concurrently), which the `dev`
script below uses to run the frontend and backend together).

## 5. Run the app

You have three options.

### Option A — run both servers together (recommended)

```bash
npm run dev
```

This uses `concurrently` to start the Flask backend (`python app.py`) and the
React dev server (`react-scripts start`) in a single terminal. Output from each
process is prefixed with `backend` or `frontend`.

### Option B — run each server in its own terminal

In one terminal, start the backend:

```bash
python app.py
```

In a second terminal, start the frontend:

```bash
npm start
```

### Default ports

| Service  | URL                          |
| -------- | ---------------------------- |
| Frontend | http://localhost:3000        |
| Backend  | http://localhost:5000        |

The frontend talks to the backend over HTTP, so **both servers must be running
at the same time** for the app to work end-to-end. If you only start one, the
UI will load but route optimization requests will fail.

## Getting the Google credentials

### Google OAuth Client ID (`REACT_APP_GOOGLE_CLIENT_ID`)

1. Go to the [Google Cloud Console — Credentials page](https://console.cloud.google.com/apis/credentials).
2. Create (or select) a project.
3. Click **Create Credentials → OAuth client ID**.
4. If prompted, configure the OAuth consent screen first (External, just fill in the required fields).
5. Choose **Web application** as the application type.
6. Under **Authorized JavaScript origins**, add `http://localhost:3000`.
7. Under **Authorized redirect URIs**, also add `http://localhost:3000`.
8. Copy the generated **Client ID** and paste it into `.env` as
   `REACT_APP_GOOGLE_CLIENT_ID`.

### Google Maps API key (`REACT_APP_GOOGLE_MAPS_API_KEY`)

1. In the same [Credentials page](https://console.cloud.google.com/apis/credentials),
   click **Create Credentials → API key**.
2. From the [API Library](https://console.cloud.google.com/apis/library), enable
   these APIs for your project:
   - **Maps JavaScript API**
   - **Places API**
3. Copy the API key and paste it into `.env` as `REACT_APP_GOOGLE_MAPS_API_KEY`.
4. The frontend's Maps script tag in `public/index.html` reads the key via
   Create React App's `%REACT_APP_GOOGLE_MAPS_API_KEY%` HTML substitution,
   which is resolved at build time — you don't need to edit `index.html`
   yourself. (If you change `.env`, restart `npm start` for the new value to
   be picked up.)
5. It is highly recommended to add HTTP referrer restrictions to the key in
   the Google Cloud Console so it can only be used from your domains.

### Flask backend URL (`REACT_APP_FLASK_API_URL`)

The React frontend reads `REACT_APP_FLASK_API_URL` to know where the Flask
backend is running. For local development, leave the value in `.env.example`
(`http://127.0.0.1:5000`) as-is.

> **Security note:** anything prefixed with `REACT_APP_` is embedded into the
> built JavaScript bundle and is therefore visible to anyone who loads the
> site. Treat these as public keys and lock them down with origin / referrer
> restrictions in the Google Cloud Console.

## Available npm scripts

| Script           | What it does                                              |
| ---------------- | --------------------------------------------------------- |
| `npm start`      | Start the React dev server on port 3000.                  |
| `npm run backend`| Start the Flask backend (`python app.py`) on port 5000.   |
| `npm run dev`    | Start the backend and frontend together via `concurrently`.|
| `npm run build`  | Produce a production build of the frontend in `build/`.   |
| `npm test`       | Run the React test suite.                                 |

## Project layout

```
.
├── app.py                # Flask backend entrypoint
├── backend/              # Additional backend modules
├── public/               # Static assets and HTML shell
├── src/                  # React frontend source
├── requirements.txt      # Python dependencies
├── package.json          # Node dependencies + scripts
├── .env.example          # Template for local environment variables
└── .gitignore
```


## Detected evidence (automated analysis)

Indexed codebase: 10 recognized source files, 38 KB.
- CSS (language) — detected in the code
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (17 of 17)

```
.env.example
.gitignore
.vercelignore
app.py
package.json
public/index.html
public/manifest.json
public/robots.txt
README.md
requirements.txt
src/App.css
src/App.js
src/index.css
src/index.js
src/LocationInput.js
src/reportWebVitals.js
src/setupTests.js
```

### Dependencies

- package.json: @react-oauth/google@^0.12.1, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, axios@^1.7.7, concurrently@^9.2.1, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, web-vitals@^2.1.4
- requirements.txt: Flask@==3.0.3, Flask-Cors@==4.0.1, python-dotenv@==1.0.1

### Recent commits (newest first)

- fix(frontend): surface backend 400/404 errors instead of masking them as 'service unreachable'
- feat: wire optimizer response into UI and surface API errors
- chore(deps): slim requirements.txt to actually-imported packages
- cleanup(index): drop dead initMap + use REACT_APP_GOOGLE_CLIENT_ID
- fix(.env.example): rename FLASK_API_URL to REACT_APP_FLASK_API_URL
- ci(vercel): add .vercelignore so Vercel only builds the React app
- fix(app): replace perpendicular-line metric with route-detour, harden validation
- fix(frontend): remove unused code and stabilize useEffect deps
- chore: ignore .venv/ and __pycache__/; untrack 889 stale artifacts
- feat: externalize secrets/config via env vars + .env.example
- chore: add .gitignore, setup README, dev script, and env-driven Maps key
- chore: clean up app.py and remove duplicate Path_find.py
- ready????
- flass???k
- Working on flask?
- css changes
- implement the UI with flask
- Added dependencies to package.json
- Added login/loggoff functionality and updated gitignore
- Merge branch 'main' of https://github.com/jonnypan2325/VroomMates

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
Flask==3.0.3
Flask-Cors==4.0.1
python-dotenv==1.0.1

```

### package.json

```
{
  "name": "vroommates",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@react-oauth/google": "^0.12.1",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.7.7",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "backend": "python app.py",
    "dev": "concurrently -n backend,frontend -c blue,green \"npm run backend\" \"npm run start\""
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "concurrently": "^9.2.1"
  }
}

```

### app.py

```python
from flask import Flask, request, jsonify
from dotenv import load_dotenv
from flask_cors import CORS
import math
import heapq
import json
import logging


def haversine_distance(coord1, coord2, R=3959):
    '''
    Great-circle distance in miles between two (lng, lat) coordinates.

    Note: this module stores all coordinates as (longitude, latitude)
    tuples (Driver/Passenger.get_coords() and the destination tuple).
    R defaults to the Earth radius in miles.
    '''
    lng1, lat1 = coord1
    lng2, lat2 = coord2
    lat1_r = math.radians(lat1)
    lat2_r = math.radians(lat2)
    dlat = lat2_r - lat1_r
    dlon = math.radians(lng2 - lng1)
    a = math.sin(dlat / 2) ** 2 + math.cos(lat1_r) * math.cos(lat2_r) * math.sin(dlon / 2) ** 2
    return 2 * R * math.asin(math.sqrt(a))


#The algorithm to get the most optimal paths
class Driver:
    def __init__(self,x,y,capacity, driver_num):
        self.x = x
        self.y = y
        self.capacity = capacity
        self.driver_num = driver_num
        self.passengers = []

    def get_coords(self):
        return (self.x,self.y)

    def get_capacity(self):
        return self.capacity

    def get_driver_num(self):
        return self.driver_num

    def add_passenger(self, passenger):
        self.passengers.append(passenger)
        self.capacity = self.capacity - 1

    def get_passengers(self):
        return self.passengers

    def get_path(self, destination):
        if not self.passengers:
            return [self.get_coords(), destination]
        open_list = [(0, (self.get_coords(), tuple(self.passengers), []))]

        visited = set()

        while(open_list):
            cost, (current_position, remaining_passengers, path_taken) = heapq.heappop(open_list)

            if (current_position, remaining_passengers) in visited:
                continue

            visited.add((current_position, remaining_passengers))

            if not remaining_passengers and current_position == destination:
                return [self.get_coords()] + path_taken

            for i, passenger in enumerate(remaining_passengers):
                new_cost = cost + haversine_distance(current_position, passenger.get_coords()) + haversine_distance(passenger.get_coords(), destination)
                new_remaining_passengers = remaining_passengers[:i] + remaining_passengers[i+1:]
                new_path = path_taken + [passenger.get_coords()]
                if (passenger.get_coords(), new_remaining_passengers) not in visited:
                    heapq.heappush(open_list, (new_cost,(passenger.get_coords(),new_remaining_passengers,new_path)))

            if not remaining_passengers:
                heapq.heappush(open_list, (cost+haversine_distance(current_position, destination), (destination, remaining_passengers, path_taken+[destination])))


class Passenger:
    def __init__(self,x,y, passenger_num):
        self.x = x
        self.y = y
        self.passenger_num = passenger_num

    def get_coords(self):
        return (self.x,self.y)

    def get_passenger_num(self):
        return self.passenger_num

def distance_from_line(passenger, driver, destination):
    '''
    Detour cost (in miles) for `driver` to pick up `passenger` and continue
    to `destination`, compared to driving straight to the destination:

        detour = d(driver -> passenger) + d(passenger -> destination)
                 - d(driver -> destination)

    By the triangle inequality this is always >= 0. Lower means the
    passenger is a better fit for this driver's route, so it's a useful
    pairwise score for assignment optimization.
    '''
    driver_to_passenger = haversine_distance(driver.get_coords(), passenger.get_coords())
    passenger_to_dest = haversine_distance(passenger.get_coords(), destination)
    driver_to_dest = haversine_distance(driver.get_coords(), destination)
    return (driver_to_passenger + passenger_to_dest) - driver_to_dest


def assign_drivers(drivers, passengers, destination):
    '''
    Assigns each passenger to a driver using a global-greedy bipartite
    assignment over pairwise detour cost (see `distance_from_line`).

    Compared to the previous per-passenger greedy, this lets a passenger
    with one outstanding cheap match "win" that driver even if some other
    passenger is processed first in iteration order. Capacity is enforced
    via `driver.get_capacity()` / `driver.add_passenger()`.
    '''
    if not drivers or not passengers:
        return drivers

    candidates = []
    for passenger in passengers:
        for driver in drivers:
            cost = distance_from_line(passenger, driver, destination)
            candidates.append((
                cost,
                passenger.get_passenger_num(),
                driver.get_driver_num(),
            ))
    # Sort by cost ascending; ties broken deterministically by ids.
    candidates.sort()

    driver_by_num = {d.get_driver_num(): d for d in drivers}
    passenger_by_num = {p.get_passenger_num(): p for p in passengers}
    assigned = set()

    for _cost, pnum, dnum in candidates:
        if pnum in assigned:
            continue
        driver = driver_by_num[dnum]
        if driver.get_capacity() > 0:
            driver.add_passenger(passenger_by_num[pnum])
            assigned.add(pnum)
            if len(assigned) == len(passengers):
                break
    return drivers


def give_paths(drivers, passengers, destination):
    '''
    Returns one path per driver (in input order). A path is a list of
    (lng, lat) tuples starting at the driver and ending at `destination`.
    Drivers with no assigned passengers get a direct two-point path.
    '''
    drivers = assign_drivers(drivers, passengers, destination)
    paths = []
    for d in drivers:
        if not d.get_passengers():
            paths.append([d.get_coords(), destination])
            continue
        path = d.get_path(destination)
        if not path:
            # Defensive fallback: A* search returne
[truncated — 4714 more characters]
```

### src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { GoogleOAuthProvider } from "@react-oauth/google"

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <GoogleOAuthProvider clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}>
    <React.StrictMode>
      <App />
    </React.StrictMode>,
  </GoogleOAuthProvider>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### src/App.js

```javascript
import './App.css';
import React, { useState, useEffect } from 'react';
import LocationInput from './LocationInput';
import { googleLogout, useGoogleLogin } from '@react-oauth/google';
import axios from 'axios';

function App() {
   const [map, setMap] = useState(null); // State for the Google Map instance
  const [directionsRenderer, setDirectionsRenderer] = useState(null); // State for DirectionsRenderer instance
  const [routeData, setRouteData] = useState(null); // State for route data

  // State for handling user and profile data
  const [user, setUser] = useState(null);
  const [profile, setProfile] = useState(null);

  // Google login functionality
  const login = useGoogleLogin({
    onSuccess: (codeResponse) => {
      setUser(codeResponse);
      console.log("User signed in");
    },
    onError: (error) => console.log('Login Failed:', error),
  });

  // Fetch user profile data after login
  useEffect(() => {
    if (user) {
      axios
        .get(`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${user.access_token}`, {
          headers: {
            Authorization: `Bearer ${user.access_token}`,
            Accept: 'application/json',
          },
        })
        .then((res) => setProfile(res.data))
        .catch((err) => console.log(err));
    }
  }, [user]);

  // Log out functionality
  const logOut = () => {
    googleLogout();
    setProfile(null);
    console.log("User signed out");
  };
  

  useEffect(() => {
    const initMap = () => {
      const mapInstance = new window.google.maps.Map(document.getElementById('map'), {
        center: { lat: 37.784, lng: -122.403 },
        zoom: 14,
      });

      const directionsRendererInstance = new window.google.maps.DirectionsRenderer();
      directionsRendererInstance.setMap(mapInstance); // Attach the directions renderer to the map

      // Store the map and directionsRenderer instances in state
      setMap(mapInstance);
      setDirectionsRenderer(directionsRendererInstance);

      const locationButton = document.createElement('button');
      locationButton.textContent = 'Pan to Current Location';
      locationButton.classList.add('custom-map-control-button');
      mapInstance.controls[window.google.maps.ControlPosition.TOP_CENTER].push(locationButton);

      locationButton.addEventListener('click', () => {
        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(
            (position) => {
              const pos = {
                lat: position.coords.latitude,
                lng: position.coords.longitude,
              };
              mapInstance.setCenter(pos);
            },
            () => {
              handleLocationError(true, mapInstance.getCenter(), mapInstance);
            }
          );
        } else {
          //handleLocationError(false, infoWindow, mapInstance.getCenter(), mapInstance);
        }
      });
    };

    const handleLocationError = (browserHasGeolocation, pos, mapInstance) => {
      const infoWindow = new window.google.maps.InfoWindow({
        position: pos,
      });
      infoWindow.setContent(
        browserHasGeolocation
          ? 'Error: The Geolocation service failed.'
          : "Error: Your browser doesn't support geolocation."
      );
      infoWindow.open(mapInstance);
    };

    // Initialize map when Google Maps is ready
    if (window.google) {
      initMap();
    } else {
      window.onload = initMap;
    }
  }, []); // Ensure this runs only once, when the component mounts
        
  return (
    <div style={{ display: 'flex' }}>
      <div style={{ width: '30%', padding: '20px', backgroundColor: '#fff5f5' }}>
        <h1>VroomMates</h1>
        <p>Enter locations for drivers, passengers, and destination:</p>
        {/* Google Login Button */}
        {profile ? (
          <div>
            {/* <img src={profile.picture} alt="user" /> */}
            {/* <h3>User Logged in</h3> */}
            {/* <p>Name: {profile.name}</p> */}
            {/* <p>Email Address: {profile.email}</p> */}
            <p>Hello, {profile.given_name}</p>
            <button className="google-btn google-logout-btn" onClick={logOut}>
              <span> Log out </span> 👋
            </button>
          </div>
        ) : (
          <button className="google-btn" onClick={() => login()}>Sign in with Google 🚀</button>
        )}
  
        {/* Location Input Component */}
        <LocationInput
          map={map}
          directionsRenderer={directionsRenderer}
          setRouteData={setRouteData}
        />
  
        {/* Display route data */}
        {routeData && (
          <div>
            <h3>Optimized Route Data</h3>
            <pre>{JSON.stringify(routeData, null, 2)}</pre>
          </div>
        )}
  
        
      </div>
  
      {/* Google Map */}
      <div id="map" style={{ height: '1000px', width: '70%' }}></div>
    </div>
  );
}

export default App;

```

### src/setupTests.js

```javascript
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

```

### src/reportWebVitals.js

```javascript
const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

```

### src/index.css

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

```

### public/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="description" content="Web site created using create-react-app" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>VroomMates</title>
  </head>
  <body>
    <div id="root"></div>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=%REACT_APP_GOOGLE_MAPS_API_KEY%&libraries=places"
      async
      defer
    ></script>
  </body>
</html>
```

### src/App.css

```css
.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

.custom-map-control-button {
  background-color: #fff;
  border: none;
  outline: none;
  width: 200px;
  height: 40px;
  margin-top: 10px;
  cursor: pointer;
  text-align: center;
  font-size: 14px;
  font-weight: bold;
  color: #333;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.driver-input-group,
.passenger-input-group {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 10px;
}

input,
select {
  border: 2px solid #d3d3d3;
  padding: 10px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin: 5px 0;
  font-family: Arial, sans-serif; /* Change to a cleaner font */
}

input[type="number"] {
  width: 50px; /* Narrower input for capacity */
}

.google-btn {
  background-color: #4285f4;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 40px;
  font-size: 14px;
  cursor: pointer;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.google-btn:hover {
  background-color: #357ae8;
  box-shadow: 0 5px 7px rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
}

.google-logout-btn {
  background-color: #db4437;
}

.google-logout-btn:hover {
  background-color: #c23321;
}

h1 {
  color: #2a6eb3;
  font-family: Arial, sans-serif;
}

p {
  color: #555555;
  font-style: italic;
}

h2 {
  color: #6a1b9a;
  font-family: Arial, sans-serif;
}

h3 {
  color: purple;
  font-family: Arial, sans-serif;
}

pre {
  color: black;
  font-family: Georgia, serif;
}

#map {
  border-left: 1px solid #d3d3d3;
}
.custom-map-control-button {
  display: block; /* Ensure button takes full width */
  margin: 10px auto; /* Center the button and give space above */
  background-color: #fff;
  border: none;
  outline: none;
  width: 200px;
  height: 40px;
  cursor: pointer;
  text-align: center;
  font-size: 14px;
  font-weight: bold;
  color: #333;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}

.passenger-input-group button {
  margin-top: 10px; /* Adds space above the button */
}

.driver-input-group button {
  margin-top: 10px; /* Adds space above the button */
}

```

[1 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]