# Project export: WasteFellow

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: CruzHacks 2026
- Tagline: Less Waste. Smarter Dining.
- Devpost: https://devpost.com/software/wastefellow-x50dhp
- GitHub: https://github.com/jjain12/WasteFellow
- Video: https://www.youtube.com/embed/Jz9LbdplnYk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — gpt-engineer-app[bot] (6 commits)

## Devpost submission (written by the team)

### Inspiration

Walking through UCSC dining halls, we noticed mountains of uneaten food being thrown away daily. Students take more than they can eat, dining staff over-prepare popular items, and there's no data to guide better decisions. We realized that what gets measured gets managed – so we set out to build an AI-powered system that turns food waste from an invisible problem into actionable insights.

### What it does

WasteFellow is an AI-powered food waste monitoring system for UCSC dining halls. Cameras on conveyor belts automatically scan returned plates, using computer vision to identify and measure leftover food in real-time. The dashboard displays live metrics across all five dining halls—total waste, cost impact, plates scanned, and waste per student—while breaking down data by meal time and food category. The system's AI engine analyzes patterns and generates specific recommendations for dining staff, such as "Reduce Rice & Grains by 35% at lunch" or "Increase Fruits by 10% at dinner." By turning every plate into actionable data, WasteFellow helps dining services optimize portions, cut costs, and eliminate food waste.

### How we built it

We built it using a streamlined tech stack optimized for real-time food waste detection and analysis. The frontend runs on Streamlit with Python, providing an intuitive dashboard that updates instantly as new data flows in. We trained a custom object detection model using Roboflow, feeding it hundreds of images of plates with various food items to teach it to recognize and classify leftovers like rice, vegetables, proteins, and fruits. The model connects via Roboflow's API, processing uploaded plate images and returning detected food items with confidence scores. We store all detection data, meal statistics, and dining hall metrics, structuring tables for daily stats, meal-specific waste, dining hall breakdowns, and individual detections. The recommendation engine uses a custom algorithm that calculates waste percentages by meal and food type, then applies smart thresholds—flagging items over 25% waste for reduction and items under 8% waste for potential increase. The system automatically categorizes detected food items, estimates weight based on portion sizes (approximately 0.15 lbs per detected item), updates all relevant database tables, and triggers dashboard refreshes to display real-time insights. Everything is containerized in a single application that can be deployed on any server with camera access, making it ready for immediate testing in actual dining halls.

### Challenges we ran into

Our biggest challenge was integrating Roboflow's detection API with Streamlit, syncing database updates across multiple tables, and ensuring instant frontend refreshes required extensive debugging. Every plate scan had to simultaneously update daily stats, meal-specific waste, dining hall data, and food categories without creating bottlenecks. We also struggled with training the AI to distinguish similar foods and estimating weight accurately. While we built a working proof-of-concept, perfecting this data pipeline is essential because we plan to launch WasteFellow as a real project at UCSC dining halls and expand to other college campuses. This hackathon proved it works—now we're focused on making it production-ready to actually tackle food waste at scale.

### Accomplishments we're proud of

We’re proud of leading an initial idea into a functional product with a clear sustainability mission. Through creating numerous iterations of our project, we validated a real waste-reduction problem and built a solution designed around user needs.

### What we learned

We learned that simple, easy-to-use tools are essential for encouraging sustainable behavior. Getting feedback early from mentors and communicating clearly as a team helped us build a better and more effective project.

### What's next

We plan to implement WasteFellow in UCSC dining halls by installing cameras on return lines and working with dining staff to test the system in real conditions. Using feedback from this rollout, we’ll improve accuracy, usability, and recommendations, with the long-term goal of expanding WasteFellow to other college campuses that want an easy way to track and reduce food waste.

## README (from the GitHub repository)

# Welcome to your Lovable project

## Project info

**URL**: https://lovable.dev/projects/REPLACE_WITH_PROJECT_ID

## How can I edit this code?

There are several ways of editing your application.

**Use Lovable**

Simply visit the [Lovable Project](https://lovable.dev/projects/REPLACE_WITH_PROJECT_ID) and start prompting.

Changes made via Lovable will be committed automatically to this repo.

**Use your preferred IDE**

If you want to work locally using your own IDE, you can clone this repo and push changes. Pushed changes will also be reflected in Lovable.

The only requirement is having Node.js & npm installed - [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating)

Follow these steps:

```sh
# Step 1: Clone the repository using the project's Git URL.
git clone <YOUR_GIT_URL>

# Step 2: Navigate to the project directory.
cd <YOUR_PROJECT_NAME>

# Step 3: Install the necessary dependencies.
npm i

# Step 4: Start the development server with auto-reloading and an instant preview.
npm run dev
```

**Edit a file directly in GitHub**

- Navigate to the desired file(s).
- Click the "Edit" button (pencil icon) at the top right of the file view.
- Make your changes and commit the changes.

**Use GitHub Codespaces**

- Navigate to the main page of your repository.
- Click on the "Code" button (green button) near the top right.
- Select the "Codespaces" tab.
- Click on "New codespace" to launch a new Codespace environment.
- Edit files directly within the Codespace and commit and push your changes once you're done.

## What technologies are used for this project?

This project is built with:

- Vite
- TypeScript
- React
- shadcn-ui
- Tailwind CSS

## How can I deploy this project?

Simply open [Lovable](https://lovable.dev/projects/REPLACE_WITH_PROJECT_ID) and click on Share -> Publish.

## Can I connect a custom domain to my Lovable project?

Yes, you can!

To connect a domain, navigate to Project > Settings > Domains and click Connect Domain.

Read more here: [Setting up a custom domain](https://docs.lovable.dev/features/custom-domain#custom-domain)


## Detected evidence (automated analysis)

Indexed codebase: 80 recognized source files, 207 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Python (language) — claimed on Devpost, not found in the code
- Streamlit (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (88 of 88)

```
.gitignore
bun.lockb
components.json
eslint.config.js
index.html
package.json
postcss.config.js
public/robots.txt
README.md
src/App.css
src/App.tsx
src/components/Header.tsx
src/components/ImageUploadSection.tsx
src/components/MonthlyTrendsCard.tsx
src/components/NavLink.tsx
src/components/RecommendationsCard.tsx
src/components/StatisticsCard.tsx
src/components/ui/accordion.tsx
src/components/ui/alert-dialog.tsx
src/components/ui/alert.tsx
src/components/ui/aspect-ratio.tsx
src/components/ui/avatar.tsx
src/components/ui/badge.tsx
src/components/ui/breadcrumb.tsx
src/components/ui/button.tsx
src/components/ui/calendar.tsx
src/components/ui/card.tsx
src/components/ui/carousel.tsx
src/components/ui/chart.tsx
src/components/ui/checkbox.tsx
src/components/ui/collapsible.tsx
src/components/ui/command.tsx
src/components/ui/context-menu.tsx
src/components/ui/dialog.tsx
src/components/ui/drawer.tsx
src/components/ui/dropdown-menu.tsx
src/components/ui/form.tsx
src/components/ui/hover-card.tsx
src/components/ui/input-otp.tsx
src/components/ui/input.tsx
src/components/ui/label.tsx
src/components/ui/menubar.tsx
src/components/ui/navigation-menu.tsx
src/components/ui/pagination.tsx
src/components/ui/popover.tsx
src/components/ui/progress.tsx
src/components/ui/radio-group.tsx
src/components/ui/resizable.tsx
src/components/ui/scroll-area.tsx
src/components/ui/select.tsx
src/components/ui/separator.tsx
src/components/ui/sheet.tsx
src/components/ui/sidebar.tsx
src/components/ui/skeleton.tsx
src/components/ui/slider.tsx
src/components/ui/sonner.tsx
src/components/ui/switch.tsx
src/components/ui/table.tsx
src/components/ui/tabs.tsx
src/components/ui/textarea.tsx
src/components/ui/toast.tsx
src/components/ui/toaster.tsx
src/components/ui/toggle-group.tsx
src/components/ui/toggle.tsx
src/components/ui/tooltip.tsx
src/components/ui/use-toast.ts
src/components/VisualRepresentationCard.tsx
src/hooks/use-mobile.tsx
src/hooks/use-toast.ts
src/index.css
src/lib/utils.ts
src/lib/wasteData.ts
src/main.tsx
src/pages/Index.tsx
src/pages/MonthlyTrendsPage.tsx
src/pages/NotFound.tsx
src/pages/RecommendationsPage.tsx
src/pages/StatisticsPage.tsx
src/pages/VisualRepresentationPage.tsx
src/test/example.test.ts
src/test/setup.ts
src/vite-env.d.ts
tailwind.config.ts
tsconfig.app.json
tsconfig.json
tsconfig.node.json
vite.config.ts
vitest.config.ts
```

### Dependencies

- package.json: @eslint/js@^9.32.0, @hookform/resolvers@^3.10.0, @radix-ui/react-accordion@^1.2.11, @radix-ui/react-alert-dialog@^1.1.14, @radix-ui/react-aspect-ratio@^1.1.7, @radix-ui/react-avatar@^1.1.10, @radix-ui/react-checkbox@^1.3.2, @radix-ui/react-collapsible@^1.1.11, @radix-ui/react-context-menu@^2.2.15, @radix-ui/react-dialog@^1.1.14, @radix-ui/react-dropdown-menu@^2.1.15, @radix-ui/react-hover-card@^1.1.14, @radix-ui/react-label@^2.1.7, @radix-ui/react-menubar@^1.1.15, @radix-ui/react-navigation-menu@^1.2.13, @radix-ui/react-popover@^1.1.14, @radix-ui/react-progress@^1.1.7, @radix-ui/react-radio-group@^1.3.7, @radix-ui/react-scroll-area@^1.2.9, @radix-ui/react-select@^2.2.5, @radix-ui/react-separator@^1.1.7, @radix-ui/react-slider@^1.3.5, @radix-ui/react-slot@^1.2.3, @radix-ui/react-switch@^1.2.5, @radix-ui/react-tabs@^1.1.12, @radix-ui/react-toast@^1.2.14, @radix-ui/react-toggle@^1.1.9, @radix-ui/react-toggle-group@^1.1.10, @radix-ui/react-tooltip@^1.2.7, @tailwindcss/typography@^0.5.16, @tanstack/react-query@^5.83.0, @testing-library/jest-dom@^6.6.0, @testing-library/react@^16.0.0, @types/node@^22.16.5, @types/react@^18.3.23, @types/react-dom@^18.3.7, @vitejs/plugin-react-swc@^3.11.0, autoprefixer@^10.4.21, class-variance-authority@^0.7.1, clsx@^2.1.1, cmdk@^1.1.1, date-fns@^3.6.0, embla-carousel-react@^8.6.0, eslint@^9.32.0, eslint-plugin-react-hooks@^5.2.0, eslint-plugin-react-refresh@^0.4.20, globals@^15.15.0, input-otp@^1.4.2, jsdom@^20.0.3, lovable-tagger@^1.1.13, lucide-react@^0.462.0, next-themes@^0.3.0, postcss@^8.5.6, react@^18.3.1, react-day-picker@^8.10.1, react-dom@^18.3.1, react-hook-form@^7.61.1, react-resizable-panels@^2.1.9, react-router-dom@^6.30.1, recharts@^2.15.4, sonner@^1.7.4, tailwind-merge@^2.6.0, tailwindcss@^3.4.17, tailwindcss-animate@^1.0.7, typescript@^5.8.3, typescript-eslint@^8.38.0, vaul@^0.9.9, vite@^5.4.19, vitest@^3.2.4, zod@^3.25.76

### Recent commits (newest first)

- Update site info for publish
- Make header subtitle
- Changes
- Make cards navigable to pages
- Changes
- Revamp dashboard UI
- Changes
- template: new_style_vite_react_shadcn_ts_testing_2026-01-08

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

### package.json

```
{
  "name": "vite_react_shadcn_ts",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "build:dev": "vite build --mode development",
    "lint": "eslint .",
    "preview": "vite preview",
    "test": "vitest run",
    "test:watch": "vitest"
  },
  "dependencies": {
    "@hookform/resolvers": "^3.10.0",
    "@radix-ui/react-accordion": "^1.2.11",
    "@radix-ui/react-alert-dialog": "^1.1.14",
    "@radix-ui/react-aspect-ratio": "^1.1.7",
    "@radix-ui/react-avatar": "^1.1.10",
    "@radix-ui/react-checkbox": "^1.3.2",
    "@radix-ui/react-collapsible": "^1.1.11",
    "@radix-ui/react-context-menu": "^2.2.15",
    "@radix-ui/react-dialog": "^1.1.14",
    "@radix-ui/react-dropdown-menu": "^2.1.15",
    "@radix-ui/react-hover-card": "^1.1.14",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-menubar": "^1.1.15",
    "@radix-ui/react-navigation-menu": "^1.2.13",
    "@radix-ui/react-popover": "^1.1.14",
    "@radix-ui/react-progress": "^1.1.7",
    "@radix-ui/react-radio-group": "^1.3.7",
    "@radix-ui/react-scroll-area": "^1.2.9",
    "@radix-ui/react-select": "^2.2.5",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slider": "^1.3.5",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-switch": "^1.2.5",
    "@radix-ui/react-tabs": "^1.1.12",
    "@radix-ui/react-toast": "^1.2.14",
    "@radix-ui/react-toggle": "^1.1.9",
    "@radix-ui/react-toggle-group": "^1.1.10",
    "@radix-ui/react-tooltip": "^1.2.7",
    "@tanstack/react-query": "^5.83.0",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.1.1",
    "date-fns": "^3.6.0",
    "embla-carousel-react": "^8.6.0",
    "input-otp": "^1.4.2",
    "lucide-react": "^0.462.0",
    "next-themes": "^0.3.0",
    "react": "^18.3.1",
    "react-day-picker": "^8.10.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.61.1",
    "react-resizable-panels": "^2.1.9",
    "react-router-dom": "^6.30.1",
    "recharts": "^2.15.4",
    "sonner": "^1.7.4",
    "tailwind-merge": "^2.6.0",
    "tailwindcss-animate": "^1.0.7",
    "vaul": "^0.9.9",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@eslint/js": "^9.32.0",
    "@testing-library/jest-dom": "^6.6.0",
    "@testing-library/react": "^16.0.0",
    "@tailwindcss/typography": "^0.5.16",
    "@types/node": "^22.16.5",
    "@types/react": "^18.3.23",
    "@types/react-dom": "^18.3.7",
    "@vitejs/plugin-react-swc": "^3.11.0",
    "autoprefixer": "^10.4.21",
    "eslint": "^9.32.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.20",
    "globals": "^15.15.0",
    "jsdom": "^20.0.3",
    "lovable-tagger": "^1.1.13",
    "postcss": "^8.5.6",
    "tailwindcss": "^3.4.17",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.38.0",
    "vite": "^5.4.19",
    "vitest": "^3.2.4"
  }
}

```

### src/main.tsx

```typescript
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

createRoot(document.getElementById("root")!).render(<App />);

```

### src/App.tsx

```typescript
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
import StatisticsPage from "./pages/StatisticsPage";
import MonthlyTrendsPage from "./pages/MonthlyTrendsPage";
import RecommendationsPage from "./pages/RecommendationsPage";
import VisualRepresentationPage from "./pages/VisualRepresentationPage";

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <TooltipProvider>
      <Toaster />
      <Sonner />
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Index />} />
          <Route path="/statistics" element={<StatisticsPage />} />
          <Route path="/monthly-trends" element={<MonthlyTrendsPage />} />
          <Route path="/recommendations" element={<RecommendationsPage />} />
          <Route path="/visual" element={<VisualRepresentationPage />} />
          {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
          <Route path="*" element={<NotFound />} />
        </Routes>
      </BrowserRouter>
    </TooltipProvider>
  </QueryClientProvider>
);

export default App;

```

### src/pages/Index.tsx

```typescript
import { useState, useCallback } from "react";
import { Link } from "react-router-dom";
import { Header } from "@/components/Header";
import { StatisticsCard } from "@/components/StatisticsCard";
import { MonthlyTrendsCard } from "@/components/MonthlyTrendsCard";
import { RecommendationsCard } from "@/components/RecommendationsCard";
import { VisualRepresentationCard } from "@/components/VisualRepresentationCard";
import { ImageUploadSection } from "@/components/ImageUploadSection";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { ChevronDown, Video } from "lucide-react";

const Index = () => {
  const [refreshKey, setRefreshKey] = useState(0);
  const [uploadOpen, setUploadOpen] = useState(true);

  const handleDetectionComplete = useCallback(() => {
    setRefreshKey(prev => prev + 1);
  }, []);

  return (
    <div className="min-h-screen bg-background">
      <Header />
      
      <main className="container mx-auto px-4 pb-8">
        {/* Description */}
        <div className="mb-6 p-4 bg-muted rounded-sm">
          <p className="text-foreground/80 text-sm leading-relaxed">
            <strong className="text-foreground">📹 How It Works:</strong> WasteFellow uses AI-powered cameras 
            installed on conveyor belts at each UCSC dining hall to automatically detect and measure food waste 
            in real-time. As students return their plates, our system identifies what types of food are being 
            discarded, calculates the weight, and tracks patterns across campus. The dashboard resets daily 
            at midnight, with an average baseline of <strong>1,000 lbs</strong> of food waste per day across all dining halls.
          </p>
        </div>

        {/* Upload Section - Collapsible */}
        <Collapsible open={uploadOpen} onOpenChange={setUploadOpen} className="mb-6">
          <CollapsibleTrigger className="flex items-center justify-between w-full p-4 bg-card rounded-sm text-card-foreground hover:bg-card/90 transition-colors">
            <span className="font-display text-primary">🧪 Upload Plate Image for Detection</span>
            <ChevronDown className={`w-5 h-5 text-primary transition-transform ${uploadOpen ? 'rotate-180' : ''}`} />
          </CollapsibleTrigger>
          <CollapsibleContent className="mt-2">
            <ImageUploadSection onDetectionComplete={handleDetectionComplete} />
          </CollapsibleContent>
        </Collapsible>

        {/* Dashboard Grid - 2x2 Layout */}
        <div key={refreshKey} className="grid grid-cols-1 lg:grid-cols-2 gap-6">
          <Link to="/statistics" className="animate-fade-in block hover:scale-[1.02] transition-transform" style={{ animationDelay: '0ms' }}>
            <div className="bg-card rounded-sm p-8 h-40 flex items-center justify-center border-l-4 border-primary">
              <h3 className="text-2xl font-display text-primary">📊 Today's Statistics</h3>
            </div>
          </Link>
          <Link to="/monthly-trends" className="animate-fade-in block hover:scale-[1.02] transition-transform" style={{ animationDelay: '100ms' }}>
            <div className="bg-card rounded-sm p-8 h-40 flex items-center justify-center border-l-4 border-primary">
              <h3 className="text-2xl font-display text-primary">📈 Monthly Trends</h3>
            </div>
          </Link>
          <Link to="/recommendations" className="animate-fade-in block hover:scale-[1.02] transition-transform" style={{ animationDelay: '200ms' }}>
            <div className="bg-card rounded-sm p-8 h-40 flex items-center justify-center border-l-4 border-primary">
              <h3 className="text-2xl font-display text-primary">🤖 AI Recommendations</h3>
            </div>
          </Link>
          <Link to="/visual" className="animate-fade-in block hover:scale-[1.02] transition-transform" style={{ animationDelay: '300ms' }}>
            <div className="bg-card rounded-sm p-8 h-40 flex items-center justify-center border-l-4 border-primary">
              <h3 className="text-2xl font-display text-primary">🍽️ Visual Representation</h3>
            </div>
          </Link>
        </div>

        {/* Live Camera Status */}
        <div className="mt-6 p-4 bg-success/10 rounded-sm flex items-center justify-center gap-3">
          <Video className="w-5 h-5 text-success" />
          <span className="text-foreground">
            <strong>🎥 Live Camera Feed Active</strong> — 5 cameras monitoring conveyor belts across campus
          </span>
          <span className="inline-flex items-center gap-1.5 text-success text-sm">
            <span className="w-2 h-2 bg-success rounded-full animate-pulse"></span>
            Recording
          </span>
        </div>
      </main>
    </div>
  );
};

export default Index;

```

### postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

```

### vitest.config.ts

```typescript
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react-swc";
import path from "path";

export default defineConfig({
  plugins: [react()],
  test: {
    environment: "jsdom",
    globals: true,
    setupFiles: ["./src/test/setup.ts"],
    include: ["src/**/*.{test,spec}.{ts,tsx}"],
  },
  resolve: {
    alias: { "@": path.resolve(__dirname, "./src") },
  },
});

```

### vite.config.ts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { componentTagger } from "lovable-tagger";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  server: {
    host: "::",
    port: 8080,
    hmr: {
      overlay: false,
    },
  },
  plugins: [react(), mode === "development" && componentTagger()].filter(Boolean),
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
}));

```

### eslint.config.js

```javascript
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
      "@typescript-eslint/no-unused-vars": "off",
    },
  },
);

```

### index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- TODO: Set the document title to the name of your application -->
    <title>Lovable App</title>
    <meta name="description" content="Tracks and analyzes food waste in dining halls using AI image detection.">
    <meta name="author" content="Lovable" />

    <!-- TODO: Update og:title to match your application name -->
    
    
    <meta property="og:type" content="website" />
    <meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/27df2965-6e8d-4f6b-8e7a-e7755571412a/id-preview-61228090--8a7fa041-0ce0-40ea-b914-06ea3545fa9d.lovable.app-1768722302616.png">

    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content="@Lovable" />
    <meta name="twitter:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/27df2965-6e8d-4f6b-8e7a-e7755571412a/id-preview-61228090--8a7fa041-0ce0-40ea-b914-06ea3545fa9d.lovable.app-1768722302616.png">
    <meta property="og:title" content="Lovable App">
  <meta name="twitter:title" content="Lovable App">
  <meta property="og:description" content="Tracks and analyzes food waste in dining halls using AI image detection.">
  <meta name="twitter:description" content="Tracks and analyzes food waste in dining halls using AI image detection.">
  <link rel="icon" type="image/x-icon" href="/favicon.ico">
</head>

  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

### tailwind.config.ts

```typescript
import type { Config } from "tailwindcss";

export default {
  darkMode: ["class"],
  content: ["./pages/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],
  prefix: "",
  theme: {
    container: {
      center: true,
      padding: "2rem",
      screens: {
        "2xl": "1400px",
      },
    },
    extend: {
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        display: ['Playfair Display', 'Georgia', 'serif'],
      },
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        success: {
          DEFAULT: "hsl(var(--success))",
          foreground: "hsl(var(--success-foreground))",
        },
        warning: {
          DEFAULT: "hsl(var(--warning))",
          foreground: "hsl(var(--warning-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
        sidebar: {
          DEFAULT: "hsl(var(--sidebar-background))",
          foreground: "hsl(var(--sidebar-foreground))",
          primary: "hsl(var(--sidebar-primary))",
          "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
          accent: "hsl(var(--sidebar-accent))",
          "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
          border: "hsl(var(--sidebar-border))",
          ring: "hsl(var(--sidebar-ring))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
      keyframes: {
        "accordion-down": {
          from: { height: "0" },
          to: { height: "var(--radix-accordion-content-height)" },
        },
        "accordion-up": {
          from: { height: "var(--radix-accordion-content-height)" },
          to: { height: "0" },
        },
        "fade-in": {
          from: { opacity: "0", transform: "translateY(10px)" },
          to: { opacity: "1", transform: "translateY(0)" },
        },
        "pulse-glow": {
          "0%, 100%": { boxShadow: "0 0 0 0 hsl(var(--success) / 0.4)" },
          "50%": { boxShadow: "0 0 0 8px hsl(var(--success) / 0)" },
        },
      },
      animation: {
        "accordion-down": "accordion-down 0.2s ease-out",
        "accordion-up": "accordion-up 0.2s ease-out",
        "fade-in": "fade-in 0.4s ease-out",
        "pulse-glow": "pulse-glow 2s ease-in-out infinite",
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
} satisfies Config;

```

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