# Project export: Plot

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: TreeHacks 2025
- Tagline: Plot delivers comprehensive insights on any location. Whether you're scouting investments or shaping skylines, Plot helps you shape your plot’s plot—making smarter decisions before you break ground.
- Devpost: https://devpost.com/software/plot-3pi8c4
- GitHub: https://github.com/toni-akintola/jats
- Video: https://www.youtube.com/embed/jkV3BTOF3GQ?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (LangChain: Best Use of LangChain (LangChain Swag Box, $250 LangSmith Credits, and access to LangGraph Cloud per team member))
- Team: 4 GitHub contributor(s) — toni-akintola (62 commits), Jennifer (36 commits), Shahan Neda (18 commits), Angela Zhang (11 commits)

## Devpost submission (written by the team)

### Inspiration

This project was born out of our own personal pain points as students. Like many others, we’ve faced the challenges of searching for housing at school, for summer internships, full-time roles, and traveling. When planning my trip to Rome, I had no idea which area was safe to stay in for an Airbnb. I ended up spending hours on Reddit looking for reviews and suggestions, which felt inefficient and time-consuming. This made us realize that finding the right places to stay could be far more seamless with the right insights from the right sources. We saw a gap in the market for a platform that could quickly and accurately provide sentiment data on locations, helping people make informed decisions about housing, whether for short-term stays or long-term investments. What if we could make this process faster and more efficient? Building the Project Our first step was building a sentiment analysis engine, since we knew there was an abundance of social media data available to us. We could easily aggregate what people were saying about different places—whether it’s about the safety of neighborhoods, or the overall vibe of a city. Using AI agents, we orchestrated a workflow to perform searches and analyze sentiment across multiple data sources. Our initial goal was to build a simple map for sentiment analysis, but as we refined our approach, we realized that there’s a much broader context to consider when evaluating a location. Beyond social media data, factors like economic trends, natural disasters, and local events all impact people's perceptions of a place. This insight led us to expand our project to build a comprehensive property intelligence platform. We also worked closely with mentors and property developers who helped us understand the nuances of the industry. It became clear that our platform could be extremely valuable to property developers, who need to analyze many of the same factors as renters, but with a much longer-term view. This shift in perspective led us to add features specifically catered to property developers, such as real-time property data streams and a user profile page to inform the agentic search. Core Technology The core of our project lies in a swarm of AI agents that execute parallel tasks to gather, analyze, and update data in real time. The following are some notable components of this project. Core Architecture: The project is built as a Next.js application with TypeScript, focusing on real estate market analysis using sentiment analysis. The main components are organized in a modular structure with clear separation of concerns between UI, services, and data processing. Core Architecture: The project is built as a Next.js application with TypeScript, focusing on real estate market analysis using sentiment analysis. The main components are organized in a modular structure with clear separation of concerns between UI, services, and data processing. Data Collection: The agentic workflow kicks off by scouring various data sources, including social media, news outlets, economic reports, and environmental data. The agents target specific factors that influence a location's desirability, such as crime rates, job market trends, housing prices, and local events. Data Collection: The agentic workflow kicks off by scouring various data sources, including social media, news outlets, economic reports, and environmental data. The agents target specific factors that influence a location's desirability, such as crime rates, job market trends, housing prices, and local events. Sentiment Analysis: The SentimentAnalyzer class serves as the core engine for processing sentiment data. It evaluates the tone and context of online discussions—whether people are generally positive or negative about a particular area. Multiple data sources are supported through a pluggable architecture, and the analyzer processes text data in parallel. Results include sentiment scores, keyword extraction, and temporal analysis. Sentiment Analysis: The SentimentAnalyzer class serves as the core engine for processing sentiment data. It evaluates the tone and context of online discussions—whether people are generally positive or negative about a particular area. Multiple data sources are supported through a pluggable architecture, and the analyzer processes text data in parallel. Results include sentiment scores, keyword extraction, and temporal analysis. Sentiment Dashboard Interface and Real-Time Updates: The SentimentDashboard acts as the main visualization interface. Its main features include multi-location analysis support, real-time sentiment scoring, interactive charts showing sentiment trends, keyword highlighting, and mention tracking. Sentiment Dashboard Interface and Real-Time Updates: The SentimentDashboard acts as the main visualization interface. Its main features include multi-location analysis support, real-time sentiment scoring, interactive charts showing sentiment trends, keyword highlighting, and mention tracking. Risk Assessment: Parallel to sentiment analysis, other agents use the Federal Emergency Management Agency API to assess the risk factors of a location, such as history of natural disasters (e.g., floods, earthquakes), economic volatility, or crime rates. These agents pull data from global news, scientific studies, and financial reports to generate a comprehensive risk profile. Risk Assessment: Parallel to sentiment analysis, other agents use the Federal Emergency Management Agency API to assess the risk factors of a location, such as history of natural disasters (e.g., floods, earthquakes), economic volatility, or crime rates. These agents pull data from global news, scientific studies, and financial reports to generate a comprehensive risk profile. Data Synthesis and Updates: As new information comes in, agents continuously update the platform (map, search results) in real time. If a major news event occurs or if sentiment shifts dramatically, the agents immediately re-analyze the data and adjust the results. This enables our users to have access to the most up-to-date information, helping them make decisions on the fly. Data Synthesis and Updates: As new information comes in, agents continuously update the platform (map, search results) in real time. If a major news event occurs or if sentiment shifts dramatically, the agents immediately re-analyze the data and adjust the results. This enables our users to have access to the most up-to-date information, helping them make decisions on the fly. The orchestration of these technologies allows us to gather and process a wide variety of data points quickly and efficiently, ensuring that the platform is always fresh and relevant. Challenges Faced One of the major challenges we faced was aligning the project’s goals with our different interests and backgrounds. We were all beginners at some aspects of the technologies we wanted to use, so balancing the desire to learn new things with the need to create something useful was tricky. However, the sentiment analysis aspect of the project—along with the real-world applications for both travelers and property developers—kept us focused and motivated. Another challenge was figuring out how to make the platform both effective and scalable. We needed to ensure the sentiment analysis could be done in real-time and that it could incorporate data from diverse sources. This is where our sponsors played a huge role in helping us streamline the process. Thanks to Langchain, Mistral AI, and Perplexity, we were able to perform high-efficiency searches and provide insights quickly. Development Tools & Technologies Throughout this journey, we leaned heavily on tools from our sponsors to improve efficiency and enhance our workflow: Perplexity was instrumental in answering queries and performing real-time searches, which helped us gather valuable insights quickly. The search integration within Perplexity Sonar made it ideal for our needs, and we frequently queried it during the project. Perplexity was instrumental in answering queries and performing real-time searches, which helped us gather valuable insights quickly. The search integration within Perplexity Sonar made it ideal for our needs, and we frequently queried it during the project. Windsurf by Codeium became our go-to tool for boosting productivity. It helped us 10x our efficiency, thanks to its memory and model context protocol features, which were vital for informing Cascade to make useful code edits and suggestions. Windsurf by Codeium became our go-to tool for boosting productivity. It helped us 10x our efficiency, thanks to its memory and model context protocol features, which were vital for informing Cascade to make useful code edits and suggestions. Langchain served as our foundation for building complex AI workflows. Its composable chains and agent frameworks helped us orchestrate our swarm of AI agents effectively, enabling seamless integration of different data sources and analysis tools into our pipeline. Langchain served as our foundation for building complex AI workflows. Its composable chains and agent frameworks helped us orchestrate our swarm of AI agents effectively, enabling seamless integration of different data sources and analysis tools into our pipeline. Mistral AI powered our core sentiment analysis engine with its robust language understanding capabilities. We leveraged its models for processing and analyzing text data from various sources, providing accurate sentiment scoring and context-aware analysis that formed the backbone of our real-time insights. Mistral AI powered our core sentiment analysis engine with its robust language understanding capabilities. We leveraged its models for processing and analyzing text data from various sources, providing accurate sentiment scoring and context-aware analysis that formed the backbone of our real-time insights. What We Learned This project taught us a lot about the importance of balancing innovation with utility. While we were initially excited about the "cool" factor of sentiment analysis, it was only by catering to the needs of property developers that we were able to make it truly useful. Additionally, we learned how to work effectively as a team despite coming from different schools and backgrounds. We also gained a deeper understanding of how AI can be applied to solve real-world problems at scale—particularly in fields like property development, where data-driven decisions can make or break a project. Conclusion We’re incredibly proud of what we’ve built. We’ve created something unique that taps into the power of real-time, sentiment-driven property intelligence. By incorporating community sentiment, economic indicators, and real-time updates, our platform offers a truly comprehensive view of any location. There’s no other product on the market quite like ours, and we’re excited to see where it goes from here. We hope you enjoy exploring our project as much as we enjoyed building it!

## README (from the GitHub repository)

This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.


## Detected evidence (automated analysis)

Indexed codebase: 89 recognized source files, 282 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- LangChain (technology) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Vercel AI SDK (technology) — detected in the code
- Mistral AI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (96 of 96)

```
.gitignore
components.json
eslint.config.mjs
next.config.js
next.config.ts
package.json
postcss.config.mjs
README.md
src/app/(default)/layout.tsx
src/app/(default)/page.tsx
src/app/api/hackernews-sentiment/route.ts
src/app/api/listing-research/route.ts
src/app/api/property-opportunities/route.ts
src/app/api/reddit-sentiment/route.ts
src/app/api/risk-assessment/route.ts
src/app/api/sentiment-analysis/route.ts
src/app/api/sentiment/route.ts
src/app/api/set-name/route.ts
src/app/api/twitter-sentiment/route.ts
src/app/globals.css
src/app/hello/page.tsx
src/app/layout.tsx
src/app/listing/[location]/page.tsx
src/app/loading/loading-animation.json
src/app/loading/loading-animation.tsx
src/app/loading/page.tsx
src/app/map/page.tsx
src/app/page.tsx
src/app/portfolio/page.tsx
src/app/profile/page.tsx
src/app/property/[id]/page.tsx
src/app/risk/page.tsx
src/app/search/page.tsx
src/app/spreadsheet/page.tsx
src/components/agent-loading.tsx
src/components/header.tsx
src/components/listing-card.tsx
src/components/listing-research.tsx
src/components/listings-controls.tsx
src/components/listings-grid.tsx
src/components/listings.tsx
src/components/nav-bar.tsx
src/components/portfolio-button.tsx
src/components/profile/profile-card.tsx
src/components/profile/profile-form.tsx
src/components/property-search.tsx
src/components/research-view.tsx
src/components/sentiment-control.tsx
src/components/sentiment-dashboard.tsx
src/components/tabbed-dashboard.tsx
src/components/ui/alert.tsx
src/components/ui/area-chart.tsx
src/components/ui/avatar.tsx
src/components/ui/badge.tsx
src/components/ui/button.tsx
src/components/ui/card.tsx
src/components/ui/chart.tsx
src/components/ui/checkbox.tsx
src/components/ui/dropdown.tsx
src/components/ui/form.tsx
src/components/ui/input.tsx
src/components/ui/label.tsx
src/components/ui/loading-spinner.tsx
src/components/ui/progress.tsx
src/components/ui/select.tsx
src/components/ui/skeleton.tsx
src/components/ui/spreadsheet-dashboard.tsx
src/components/ui/tabs.tsx
src/components/ui/textarea.tsx
src/components/ui/toast.tsx
src/components/ui/toaster.tsx
src/components/ui/typewriter-text.tsx
src/components/user-profile.tsx
src/contexts/header-context.tsx
src/hooks/use-property-search.ts
src/hooks/use-toast.ts
src/lib/listings.ts
src/lib/utils.ts
src/services/agent-types.ts
src/services/risk-service.ts
src/services/sentiment-analyzer.ts
src/services/sentiment-service.ts
src/services/sources/google-places.ts
src/services/sources/hackernews.ts
src/services/sources/reddit.ts
src/services/sources/twitter.ts
src/services/types.ts
src/services/types/hackernews.ts
src/store/listings-store.ts
src/store/profile-store.ts
src/types/listing.ts
src/types/profile.ts
src/types/research.ts
tailwind.config.js
tailwind.config.ts
tsconfig.json
```

### Dependencies

- package.json: @ai-sdk/openai@^1.1.11, @ai-sdk/perplexity@^1.0.0, @eslint/eslintrc@^3, @hookform/resolvers@^4.1.0, @langchain/community@^0.3.30, @langchain/core@^0.3.40, @langchain/langgraph@^0.2.46, @langchain/mistralai@^0.2.0, @langchain/openai@^0.4.4, @mapbox/mapbox-gl-geocoder@^5.0.3, @radix-ui/react-avatar@^1.1.3, @radix-ui/react-checkbox@^1.1.4, @radix-ui/react-label@^2.1.2, @radix-ui/react-progress@^1.1.2, @radix-ui/react-select@^2.1.6, @radix-ui/react-slot@^1.1.2, @radix-ui/react-tabs@^1.1.3, @radix-ui/react-toast@^1.2.6, @types/jest@^29.5.14, @types/mapbox-gl@^3.4.1, @types/node@^20, @types/react@^19, @types/react-dom@^19, @types/sentiment@^5.0.4, ai@^4.1.41, class-variance-authority@^0.7.1, clsx@^2.1.1, eslint@^9, eslint-config-next@15.1.7, framer-motion@^12.4.3, jest@^29.7.0, jest-environment-jsdom@^29.7.0, lottie-react@^2.4.1, lucide-react@^0.475.0, mapbox-gl@^3.10.0, next@15.1.7, openai@^4.85.1, postcss@^8, react@^19.0.0, react-dom@^19.0.0, react-hook-form@^7.54.2, react-icons@^5.4.0, react-intersection-observer@^9.15.1, react-map-gl@^8.0.1, recharts@^2.15.1, sentiment@^5.0.2, tailwind-merge@^3.0.1, tailwindcss@^3.4.1, tailwindcss-animate@^1.0.7, typescript@^5, zod@^3.24.2, zustand@^5.0.3

### Recent commits (newest first)

- Merge branch 'demo'
- merge
- Merge pull request #11 from toni-akintola/fix-search-bar
- fix portfolio
- Merge pull request #10 from toni-akintola/fix-search-bar
- Update page.tsx
- update
- map demo
- format
- spacing
- finished
- fix loading page
- fix more
- fix header
- Merge branch 'main' of github.com:toni-akintola/jats
- added aparts photos
- Merge branch 'tone-in-feels'
- that's all folks.
- header issue
- need to figure out a way to do images

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

### package.json

```
{
  "name": "jats",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@ai-sdk/openai": "^1.1.11",
    "@ai-sdk/perplexity": "^1.0.0",
    "@hookform/resolvers": "^4.1.0",
    "@langchain/community": "^0.3.30",
    "@langchain/core": "^0.3.40",
    "@langchain/langgraph": "^0.2.46",
    "@langchain/mistralai": "^0.2.0",
    "@langchain/openai": "^0.4.4",
    "@mapbox/mapbox-gl-geocoder": "^5.0.3",
    "@radix-ui/react-avatar": "^1.1.3",
    "@radix-ui/react-checkbox": "^1.1.4",
    "@radix-ui/react-label": "^2.1.2",
    "@radix-ui/react-progress": "^1.1.2",
    "@radix-ui/react-select": "^2.1.6",
    "@radix-ui/react-slot": "^1.1.2",
    "@radix-ui/react-tabs": "^1.1.3",
    "@radix-ui/react-toast": "^1.2.6",
    "@types/mapbox-gl": "^3.4.1",
    "ai": "^4.1.41",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "framer-motion": "^12.4.3",
    "lottie-react": "^2.4.1",
    "lucide-react": "^0.475.0",
    "mapbox-gl": "^3.10.0",
    "next": "15.1.7",
    "openai": "^4.85.1",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-hook-form": "^7.54.2",
    "react-icons": "^5.4.0",
    "react-intersection-observer": "^9.15.1",
    "react-map-gl": "^8.0.1",
    "recharts": "^2.15.1",
    "sentiment": "^5.0.2",
    "tailwind-merge": "^3.0.1",
    "tailwindcss-animate": "^1.0.7",
    "zod": "^3.24.2",
    "zustand": "^5.0.3"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@types/jest": "^29.5.14",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "@types/sentiment": "^5.0.4",
    "eslint": "^9",
    "eslint-config-next": "15.1.7",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Fredoka } from "next/font/google";
import "./globals.css";
import { HeaderProvider } from "@/contexts/header-context";
import { Header } from "@/components/header";

const fredoka = Fredoka({
  subsets: ["latin"],
  variable: "--font-fredoka",
  weight: ["300", "400"],
});

export const metadata: Metadata = {
  title: "Plot - Property Analysis Intelligence",
  description: "AI-powered property analysis and development opportunities",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const isMapPage =
    typeof window !== "undefined" && window.location.pathname.includes("/map");

  return (
    <html lang="en">
      <body
        className={`${fredoka.variable} font-fredoka antialiased min-h-screen`}
        style={{
          background: `linear-gradient(135deg, 
            #0e3b5c 0%,
            #5e4f6d 25%,
            #9f6671 50%,
            #d8897b 75%,
            #f4ac7b 100%
          ) fixed`,
        }}
      >
        {isMapPage ? (
          children
        ) : (
          <div className="relative pt-16">
            {/* <Header /> */}
            {children}
          </div>
        )}
      </body>
    </html>
  );
}

```

### src/app/page.tsx

```typescript
"use client";

import { NavBar } from "@/components/nav-bar";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useEffect } from "react";
import { useInView } from "react-intersection-observer";
import Image from "next/image";
import Link from "next/link";
const companies = [
  { name: "Urban Development Partners", logo: "/logos/udp.svg" },
  { name: "Blackstone Real Estate", logo: "/logos/blackstone.svg" },
  { name: "CBRE Group", logo: "/logos/cbre.svg" },
  { name: "JLL", logo: "/logos/jll.svg" },
  { name: "Cushman & Wakefield", logo: "/logos/cw.svg" },
];

const features = [
  {
    title: "Market Intelligence",
    description:
      "Analyze property values, trends, and growth potential across markets using advanced AI algorithms",
    icon: "📊",
  },
  {
    title: "Opportunity Detection",
    description:
      "Automatically identify undervalued properties and emerging neighborhood trends",
    icon: "🎯",
  },
  {
    title: "Risk Assessment",
    description:
      "Evaluate investment risks using predictive modeling and historical data analysis",
    icon: "🛡️",
  },
];

const benefits = [
  "Reduce research time by 75%",
  "Identify opportunities before they hit the market",
  "Make data-driven investment decisions",
  "Automate property analysis workflows",
];

export default function Home() {
  const [headerRef, headerInView] = useInView();

  useEffect(() => {
    document.documentElement.style.scrollBehavior = "smooth";
  }, []);

  return (
    <main className="min-h-screen text-white">
      <NavBar />
      {/* Hero Section */}
      <section className="pt-32 pb-20 px-4 relative" ref={headerRef}>
        <div className="max-w-7xl mx-auto text-center">
          <h2 className="text-2xl text-white/80 mb-8 max-w-4xl mx-auto">
            Great developments start with the right insights
          </h2>
          <h1 className="text-5xl md:text-6xl font-bold text-white mb-6">
            Plot delivers them instantly
          </h1>
          <p className="text-xl text-white/80 mb-8 max-w-3xl mx-auto">
            Turn market data into actionable insights with our intelligent
            property analysis platform.
          </p>
          <div className="flex gap-4 justify-center">
            <Link href="/map">
              <Button
                size="lg"
                variant="outline"
                className="bg-[#f4ac7b] hover:bg-[#d8897b] text-[#0e3b5c]"
              >
                Start Free Trial
              </Button>
            </Link>
            <Button
              size="lg"
              variant="outline"
              className="bg-[#f4ac7b] hover:bg-[#d8897b] text-[#0e3b5c]"
            >
              Watch Demo
            </Button>
          </div>
        </div>
      </section>

      {/* Features Section */}
      <section id="features" className="py-20">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="grid md:grid-cols-3 gap-8">
            {features.map((feature) => (
              <div
                key={feature.title}
                className="p-6 bg-[#0e3b5c]/60 backdrop-blur-sm rounded-lg shadow-lg hover:shadow-xl transition-all border border-white/10"
              >
                <div className="text-4xl mb-4">{feature.icon}</div>
                <h3 className="text-xl font-semibold text-[#f4ac7b] mb-2">
                  {feature.title}
                </h3>
                <p className="text-white/80">{feature.description}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Social Proof Section */}
      <section className="py-20">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="grid grid-cols-5 gap-8 items-center mb-16">
            {companies.map((company) => (
              <div
                key={company.name}
                className="opacity-70 hover:opacity-100 transition-all"
              >
                {/* <Image
                  src={company.logo}
                  alt={company.name}
                  className="h-8 w-auto brightness-0 invert"
                /> */}
              </div>
            ))}
          </div>
          <blockquote className="text-center max-w-3xl mx-auto">
            <p className="text-xl text-white/90 mb-4">
              &ldquo;Plot has transformed how we identify investment
              opportunities. We&apos;ve increased our portfolio value by 32% in
              just six months.&rdquo;
            </p>
            <footer className="text-white/70">
              Sarah Chen, Director of Acquisitions at Urban Development Partners
            </footer>
          </blockquote>
        </div>
      </section>

      {/* Benefits Section */}
      <section className="py-20">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="grid md:grid-cols-2 gap-12 items-center">
            <div>
              <h2 className="text-3xl font-bold text-[#f4ac7b] mb-6">
                Why Choose Plot?
              </h2>
              <ul className="space-y-4">
                {benefits.map((benefit) => (
                  <li key={benefit} className="flex items-center">
                    <span className="text-[#f4ac7b] mr-2">✓</span>
                    <span className="text-white/80">{benefit}</span>
                  </li>
                ))}
              </ul>
            </div>
            <div className="bg-[#0e3b5c]/60 p-6 rounded-lg shadow-lg border border-white/10">
              <Image
                src="/aparts/21.jpg"
                alt="Modern property visualization"
                width={1920}
                height={1080}
                className="aspect-video object-cover rounded-md"
                priority
              />
            </div>
          </div>
        </div>
      </section>

      {/* CTA Section */}
      <section className
[truncated — 2500 more characters]
```

### src/app/portfolio/page.tsx

```typescript
import Listings from "@/components/listings";
import { getListings } from "@/lib/listings";

export default async function PortfolioPage() {
  const listings = await getListings();

  return (
    <div className="pt-24">
      <Listings initialListings={listings} />
    </div>
  );
}

```

### src/app/(default)/layout.tsx

```typescript
import { HeaderProvider } from "@/contexts/header-context";
import { Header } from "@/components/header";

export default function DefaultLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="relative pt-16">
      <HeaderProvider>
        <Header />
        {children}
      </HeaderProvider>
    </div>
  );
}

```

### src/app/spreadsheet/page.tsx

```typescript
import { SpreadsheetDashboard } from "@/components/ui/spreadsheet-dashboard";

export default function SpreadsheetPage() {
  return (
    <main className="min-h-screen py-8">
      <div className="container">
        <h1 className="text-3xl font-bold mb-8 text-center">
          Interactive Spreadsheet
        </h1>
        <SpreadsheetDashboard />
      </div>
    </main>
  );
}

```

### src/app/profile/page.tsx

```typescript
import { ProfileForm } from "@/components/profile/profile-form";
import { ProfileCard } from "@/components/profile/profile-card";

export default function ProfilePage() {
  return (
    <div className="py-16 max-h-full h-full min-h-screen relative z-50">
      <div className="max-w-5xl mx-auto p-4 sm:p-6 space-y-8">
        <h1 className="text-3xl font-bold text-white mb-8">
          Developer Profile
        </h1>
        <div className="grid md:grid-cols-3 gap-8">
          <div className="md:col-span-1">
            <ProfileCard />
          </div>
          <div className="md:col-span-2">
            <ProfileForm />
          </div>
        </div>
      </div>
    </div>
  );
}

```

### src/app/loading/page.tsx

```typescript
"use client";

import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useSearchParams } from "next/navigation";

const RunningFigure = () => {
  return (
    <div className="animate-bounce flex space-x-12">
      {[1, 2, 3].map((i) => (
        <div
          key={i}
          className="flex flex-col items-center justify-center text-white text-4xl animate-pulse"
          style={{ animationDelay: `${i * 200}ms` }}
        >
          🏃
        </div>
      ))}
    </div>
  );
};

export default function LoadingPage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const name = searchParams.get("name");
  const agentString = name ? name + "\'s" : "a";

  useEffect(() => {
    const timer = setTimeout(() => {
      router.push("/map");
    }, 3000);

    return () => clearTimeout(timer);
  }, [router]);

  return (
    <main
      className="min-h-screen flex flex-col items-center justify-center relative -mt-16"
      style={{
        background: `linear-gradient(135deg, 
          #0e3b5c 0%,
          #5e4f6d 25%,
          #9f6671 50%,
          #d8897b 75%,
          #f4ac7b 100%
        )`,
      }}
    >
      <div className="relative z-10 w-full max-w-xl text-center">
        <div className="w-96 h-32 mx-auto flex items-center justify-center">
          <RunningFigure />
        </div>
        {/* <div className="w-96 h-96 mx-auto">
          <Lottie 
            animationData={loadingAnimation} 
            loop={true}
          />
        </div> */}
        <h2 className="text-2xl font-medium text-white mt-8">
          {agentString} swarm of agents have been deployed...
        </h2>
        <p className="text-white/80 mt-4">
          Analyzing sentiment data from multiple sources
        </p>
      </div>
    </main>
  );
}

```

### src/app/hello/page.tsx

```typescript
"use client";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useRouter } from "next/navigation";

export default function HelloPage() {
  const router = useRouter();

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);

    const response = await fetch("/api/set-name", {
      method: "POST",
      body: formData,
    });

    if (response.ok) {
      const { result } = await response.json();
      router.push(`/loading?name=${encodeURIComponent(result)}`);
    }
  };

  return (
    <main className="flex items-center justify-center h-screen -mt-16">
      <div className="absolute inset-0 bg-black/5" />
      <div className="w-full max-w-md p-8 bg-white/10 backdrop-blur-md rounded-lg shadow-lg border border-white/10 relative z-10">
        <h1 className="text-4xl font-bold mb-8 text-white text-center">
          Welcome to Plot
        </h1>
        <form onSubmit={handleSubmit} className="space-y-6">
          <div>
            <label
              htmlFor="name"
              className="block text-lg font-medium text-white/90 mb-3"
            >
              What&apos;s your name?
            </label>
            <Input
              type="text"
              id="name"
              name="name"
              required
              className="w-full bg-white/5 border-white/20 text-white text-lg placeholder:text-white/40 h-12"
              placeholder="Enter your name"
            />
          </div>
          <div>
            <label
              htmlFor="location"
              className="block text-lg font-medium text-white/90 mb-3"
            >
              Where are you located?
            </label>
            <Input
              type="text"
              name="location"
              id="location"
              required
              className="w-full bg-white/5 border-white/20 text-white text-lg placeholder:text-white/40 h-12"
              placeholder="Enter your location"
            />
          </div>
          <Button
            type="submit"
            className="w-full h-12 text-lg font-medium bg-white/20 hover:bg-white/30 text-white border border-white/20"
          >
            Continue →
          </Button>
        </form>
      </div>
    </main>
  );
}

```

### src/app/search/page.tsx

```typescript
"use client";
import { useState } from "react";
import { PropertySearch } from "@/components/property-search";
import Listings from "@/components/listings";
import { Listing } from "@/types/listing";
import { NavBar } from "@/components/nav-bar";

// Move the skeleton component here since it's specific to this page
function ListingSkeleton() {
  return (
    <div className="rounded-xl overflow-hidden border border-white/10 bg-white/5 animate-pulse">
      <div className="aspect-video bg-white/10" />
      <div className="p-6 space-y-4">
        <div className="h-6 bg-white/10 rounded w-3/4" />
        <div className="h-4 bg-white/10 rounded w-1/2" />
        <div className="space-y-2">
          <div className="h-4 bg-white/10 rounded w-full" />
          <div className="h-4 bg-white/10 rounded w-5/6" />
        </div>
      </div>
    </div>
  );
}

export default function SearchPage() {
  const [listings, setListings] = useState<Listing[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSearch = async (searchParams: {
    location: string;
    propertyType?: string;
    priceRange?: string;
  }) => {
    setIsLoading(true);
    setError(null);

    try {
      const response = await fetch("/api/property-opportunities", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(searchParams),
      });

      const data = await response.json();
      if (!response.ok) throw new Error(data.error);
      setListings(data.opportunities);
    } catch (e) {
      setError(e instanceof Error ? e.message : "Failed to find opportunities");
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <main className="py-8 min-h-screen">
      <NavBar />
      <div className="container space-y-8 min-h-screen">
        <div className="max-w-4xl mx-auto">
          <h1 className="text-3xl font-bold text-white mb-2">
            Property Search
          </h1>
          <p className="text-white/60 mb-8">
            Find development opportunities in your target market
          </p>

          <PropertySearch
            onSearch={handleSearch}
            isLoading={isLoading}
            error={error}
          />
        </div>

        {/* Listings Section */}
        <div className="max-w-4xl mx-auto">
          <h2 className="text-2xl font-bold text-white mb-6">
            {listings.length > 0 ? "Potential Opportunities" : "Your Listings"}
          </h2>

          {isLoading ? (
            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
              {[...Array(4)].map((_, i) => (
                <ListingSkeleton key={i} />
              ))}
            </div>
          ) : (
            listings.length > 0 && <Listings initialListings={listings} />
          )}
        </div>
      </div>
    </main>
  );
}

```

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