Spaces:
Running
Locked in. I’ve set the lease-term scoring window to **25 years** and delivered both items—bootstrap + full data-run tooling—so your devs can execute immediately.
Browse files# 1) Repo bootstrap (FastAPI + React + Postgres/PostGIS + Docker)
**What’s included (lean starter):**
* API (FastAPI) with scoring config defaults (25-year window), health endpoint, and structure for parcels/scoring routes.
* Web (React/Vite) seed app to wire filters/table/map.
* Docker Compose for Postgres/PostGIS, API, and Web.
* Requirements, Dockerfiles, and a short README.
**Get it running (dev):**
```bash
# From the repo root
docker compose up --build
# API: http://localhost:8000/healthz
# Web: http://localhost:5173
```
**Key file paths (you can copy/paste into your repo):**
```
/api/requirements.txt
/api/Dockerfile
/api/main.py
/api/scoring/config.py # DEFAULT_PARAMS = {"max_lease_years": 25, "area_min_sqm": 2000, "area_max_sqm": 80000}
/web/Dockerfile
/web/package.json
/web/index.html
/web/main.jsx
docker-compose.yml
README.md
```
# 2) Data run (25-year window) — scorer you can execute now
Use the scorer script to process your full dataset and output **Top 10k candidates** (CSV/XLSX) with factor breakdowns. I already placed a ready-to-run program at:
**`/mnt/data/candidate_site_analyzer.py`**
### Run it (paths assume your uploaded files):
```bash
python /mnt/data/candidate_site_analyzer.py \
--leases "/mnt/data/LEASES_FULL_2025_09.zip" \
--onspd "/mnt/data/ONSPD_AUG_2025.zip" \
--max-lease-years 25 \
--top-k 10000 \
--out-csv "/mnt/data/ghoststack_candidates_full_top10k.csv" \
--out-xlsx "/mnt/data/ghoststack_candidates_full_top10k.xlsx"
```
### What it does
* **Reads leases** (streams CSV inside the big ZIP if present; otherwise chunk-reads the Excel fallback).
* **Normalizes** postcodes and **joins ONSPD** for lat/lon + RU11 rural/urban proxy.
* **Scores** each parcel with weights: lease 0.35, area 0.25, use 0.20, location 0.20.
* Lease scoring: `score = clamp(1 - years_remaining / 25, 0, 1)` (overdue leases → 1.0).
* Area: 2,000–80,000 m² window, min–max scaled.
* Use: industrial/infra keywords (B2, B8, E(g)(iii), INDUSTRIAL, WAREHOUSE, UTILITY, ENERGY, INFRASTRUCTURE, DEPOT, PLANT) → 0.85 else 0.5.
* Location: RU11 → rural/small-town ≈ 0.8–0.9; major urban/conurbation ≈ 0.2–0.3; unknown 0.5.
* **Outputs** ranked **Top 10k** with columns:
* `title, postcode, la_name, lat, lon, use, area, lease_end, years_remaining, ru11ind`
* component scores + `gs_candidate_score` + `priority_band (A/B/C)`
### Tuning (common asks)
* Change area window:
```bash
... --area-min-sqm 10000 --area-max-sqm 120000
```
* Make use-class stricter (e.g., B2/B8 only): set a `--use-strict` flag in the script (devs: flip keyword list or add regex).
* Export **Top 2k A-band only**:
```bash
... --band A --top-k 2000
```
---
## Acceptance targets for this drop
* Scorer runs against **`LEASES_FULL_2025_09.zip`** with **25-year** window and emits two files:
* `/mnt/data/ghoststack_candidates_full_top10k.csv`
* `/mnt/data/ghoststack_candidates_full_top10k.xlsx`
* Bootstrap spins locally with `docker compose up`, exposing API and Web shells.
If you want me to also ship: (a) a Postgres schema/migration and (b) a `/parcels` API endpoint wired to the scoring outputs, I’ll bundle those in the bootstrap next.
- README.md +8 -5
- components/footer.js +100 -0
- components/header.js +159 -0
- index.html +108 -19
- script.js +24 -0
- style.css +66 -17
|
@@ -1,10 +1,13 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: GhostStack Finder 🔍
|
| 3 |
+
colorFrom: blue
|
| 4 |
+
colorTo: blue
|
| 5 |
+
emoji: 🐳
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite-v3
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Welcome to your new DeepSite project!
|
| 13 |
+
This project was created with [DeepSite](https://huggingface.co/deepsite).
|
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class CustomFooter extends HTMLElement {
|
| 2 |
+
connectedCallback() {
|
| 3 |
+
this.attachShadow({ mode: 'open' });
|
| 4 |
+
this.shadowRoot.innerHTML = `
|
| 5 |
+
<style>
|
| 6 |
+
:host {
|
| 7 |
+
display: block;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
* {
|
| 11 |
+
margin: 0;
|
| 12 |
+
padding: 0;
|
| 13 |
+
box-sizing: border-box;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
footer {
|
| 17 |
+
background-color: #0f172a;
|
| 18 |
+
color: #cbd5e1;
|
| 19 |
+
padding: 4rem 1rem 2rem;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
.container {
|
| 23 |
+
max-width: 1280px;
|
| 24 |
+
margin: 0 auto;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.footer-grid {
|
| 28 |
+
display: grid;
|
| 29 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 30 |
+
gap: 2rem;
|
| 31 |
+
margin-bottom: 3rem;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.footer-logo {
|
| 35 |
+
display: flex;
|
| 36 |
+
align-items: center;
|
| 37 |
+
gap: 0.75rem;
|
| 38 |
+
font-weight: 700;
|
| 39 |
+
font-size: 1.5rem;
|
| 40 |
+
color: white;
|
| 41 |
+
margin-bottom: 1rem;
|
| 42 |
+
text-decoration: none;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
.footer-description {
|
| 46 |
+
color: #94a3b8;
|
| 47 |
+
margin-bottom: 1.5rem;
|
| 48 |
+
max-width: 300px;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.social-links {
|
| 52 |
+
display: flex;
|
| 53 |
+
gap: 1rem;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
.social-link {
|
| 57 |
+
display: flex;
|
| 58 |
+
align-items: center;
|
| 59 |
+
justify-content: center;
|
| 60 |
+
width: 40px;
|
| 61 |
+
height: 40px;
|
| 62 |
+
border-radius: 50%;
|
| 63 |
+
background-color: #1e293b;
|
| 64 |
+
color: #cbd5e1;
|
| 65 |
+
transition: all 0.2s;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
.social-link:hover {
|
| 69 |
+
background-color: #2563eb;
|
| 70 |
+
color: white;
|
| 71 |
+
transform: translateY(-2px);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
.footer-heading {
|
| 75 |
+
color: white;
|
| 76 |
+
font-weight: 600;
|
| 77 |
+
margin-bottom: 1.5rem;
|
| 78 |
+
font-size: 1.125rem;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
.footer-links {
|
| 82 |
+
list-style: none;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
.footer-link {
|
| 86 |
+
margin-bottom: 0.75rem;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.footer-link a {
|
| 90 |
+
color: #94a3b8;
|
| 91 |
+
text-decoration: none;
|
| 92 |
+
transition: color 0.2s;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
.footer-link a:hover {
|
| 96 |
+
color: #2563eb;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
.copyright {
|
| 100 |
+
border-top: 1px solid #1e293b
|
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class CustomHeader extends HTMLElement {
|
| 2 |
+
connectedCallback() {
|
| 3 |
+
this.attachShadow({ mode: 'open' });
|
| 4 |
+
this.shadowRoot.innerHTML = `
|
| 5 |
+
<style>
|
| 6 |
+
:host {
|
| 7 |
+
display: block;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
* {
|
| 11 |
+
margin: 0;
|
| 12 |
+
padding: 0;
|
| 13 |
+
box-sizing: border-box;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
header {
|
| 17 |
+
background-color: white;
|
| 18 |
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
| 19 |
+
position: sticky;
|
| 20 |
+
top: 0;
|
| 21 |
+
z-index: 50;
|
| 22 |
+
transition: all 0.3s ease;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
.container {
|
| 26 |
+
max-width: 1280px;
|
| 27 |
+
margin: 0 auto;
|
| 28 |
+
padding: 0 1rem;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
nav {
|
| 32 |
+
display: flex;
|
| 33 |
+
justify-content: space-between;
|
| 34 |
+
align-items: center;
|
| 35 |
+
padding: 1rem 0;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.logo {
|
| 39 |
+
display: flex;
|
| 40 |
+
align-items: center;
|
| 41 |
+
gap: 0.75rem;
|
| 42 |
+
font-weight: 700;
|
| 43 |
+
font-size: 1.5rem;
|
| 44 |
+
color: #0f172a;
|
| 45 |
+
text-decoration: none;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
.logo-icon {
|
| 49 |
+
color: #2563eb;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.nav-links {
|
| 53 |
+
display: flex;
|
| 54 |
+
gap: 2rem;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.nav-link {
|
| 58 |
+
font-weight: 500;
|
| 59 |
+
color: #64748b;
|
| 60 |
+
text-decoration: none;
|
| 61 |
+
transition: color 0.2s;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.nav-link:hover {
|
| 65 |
+
color: #2563eb;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
.auth-buttons {
|
| 69 |
+
display: flex;
|
| 70 |
+
gap: 1rem;
|
| 71 |
+
align-items: center;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
.btn-outline {
|
| 75 |
+
color: #2563eb;
|
| 76 |
+
border: 1px solid #2563eb;
|
| 77 |
+
padding: 0.5rem 1rem;
|
| 78 |
+
border-radius: 0.5rem;
|
| 79 |
+
font-weight: 500;
|
| 80 |
+
transition: all 0.2s;
|
| 81 |
+
text-decoration: none;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
.btn-outline:hover {
|
| 85 |
+
background-color: #2563eb;
|
| 86 |
+
color: white;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.btn-primary {
|
| 90 |
+
background-color: #2563eb;
|
| 91 |
+
color: white;
|
| 92 |
+
padding: 0.5rem 1rem;
|
| 93 |
+
border-radius: 0.5rem;
|
| 94 |
+
font-weight: 500;
|
| 95 |
+
transition: background-color 0.2s;
|
| 96 |
+
text-decoration: none;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
.btn-primary:hover {
|
| 100 |
+
background-color: #1d4ed8;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
.mobile-menu-button {
|
| 104 |
+
display: none;
|
| 105 |
+
background: none;
|
| 106 |
+
border: none;
|
| 107 |
+
cursor: pointer;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
@media (max-width: 768px) {
|
| 111 |
+
.nav-links, .auth-buttons {
|
| 112 |
+
display: none;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.mobile-menu-button {
|
| 116 |
+
display: block;
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
</style>
|
| 120 |
+
|
| 121 |
+
<header>
|
| 122 |
+
<div class="container">
|
| 123 |
+
<nav>
|
| 124 |
+
<a href="/" class="logo">
|
| 125 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="logo-icon">
|
| 126 |
+
<path d="M12 2L2 7l10 5 10-5-10-5z"></path>
|
| 127 |
+
<path d="M2 17l10 5 10-5"></path>
|
| 128 |
+
<path d="M2 12l10 5 10-5"></path>
|
| 129 |
+
</svg>
|
| 130 |
+
<span>GhostStack</span>
|
| 131 |
+
</a>
|
| 132 |
+
|
| 133 |
+
<div class="nav-links">
|
| 134 |
+
<a href="#" class="nav-link">Dashboard</a>
|
| 135 |
+
<a href="#" class="nav-link">Candidates</a>
|
| 136 |
+
<a href="#" class="nav-link">Analytics</a>
|
| 137 |
+
<a href="#" class="nav-link">Resources</a>
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<div class="auth-buttons">
|
| 141 |
+
<a href="#" class="btn-outline">Sign In</a>
|
| 142 |
+
<a href="#" class="btn-primary">Get Started</a>
|
| 143 |
+
</div>
|
| 144 |
+
|
| 145 |
+
<button class="mobile-menu-button">
|
| 146 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 147 |
+
<line x1="3" y1="12" x2="21" y2="12"></line>
|
| 148 |
+
<line x1="3" y1="6" x2="21" y2="6"></line>
|
| 149 |
+
<line x1="3" y1="18" x2="21" y2="18"></line>
|
| 150 |
+
</svg>
|
| 151 |
+
</button>
|
| 152 |
+
</nav>
|
| 153 |
+
</div>
|
| 154 |
+
</header>
|
| 155 |
+
`;
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
customElements.define('custom-header', CustomHeader);
|
|
@@ -1,19 +1,108 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>GhostStack Finder</title>
|
| 7 |
+
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
|
| 8 |
+
<link rel="stylesheet" href="style.css">
|
| 9 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 10 |
+
<script src="https://unpkg.com/feather-icons"></script>
|
| 11 |
+
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 12 |
+
</head>
|
| 13 |
+
<body class="bg-gray-50 min-h-screen flex flex-col">
|
| 14 |
+
<custom-header></custom-header>
|
| 15 |
+
|
| 16 |
+
<main class="flex-grow container mx-auto px-4 py-8">
|
| 17 |
+
<section class="mb-16 text-center">
|
| 18 |
+
<h1 class="text-4xl md:text-5xl font-bold text-gray-800 mb-4">Find Your Next Strategic Site</h1>
|
| 19 |
+
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
|
| 20 |
+
Discover high-potential ghost sites with our AI-powered analyzer. Filter by location, size, and lease status to find your perfect development opportunity.
|
| 21 |
+
</p>
|
| 22 |
+
</section>
|
| 23 |
+
|
| 24 |
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-16">
|
| 25 |
+
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow">
|
| 26 |
+
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mb-4">
|
| 27 |
+
<i data-feather="map-pin" class="text-blue-600"></i>
|
| 28 |
+
</div>
|
| 29 |
+
<h3 class="text-xl font-semibold mb-2">Location Intelligence</h3>
|
| 30 |
+
<p class="text-gray-600">Rural/urban classification and precise geolocation data to target ideal areas.</p>
|
| 31 |
+
</div>
|
| 32 |
+
|
| 33 |
+
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow">
|
| 34 |
+
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center mb-4">
|
| 35 |
+
<i data-feather="bar-chart-2" class="text-green-600"></i>
|
| 36 |
+
</div>
|
| 37 |
+
<h3 class="text-xl font-semibold mb-2">Smart Scoring</h3>
|
| 38 |
+
<p class="text-gray-600">Algorithmic evaluation based on lease terms, area, use class, and location potential.</p>
|
| 39 |
+
</div>
|
| 40 |
+
|
| 41 |
+
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow">
|
| 42 |
+
<div class="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center mb-4">
|
| 43 |
+
<i data-feather="filter" class="text-purple-600"></i>
|
| 44 |
+
</div>
|
| 45 |
+
<h3 class="text-xl font-semibold mb-2">Advanced Filters</h3>
|
| 46 |
+
<p class="text-gray-600">Refine results by area size, lease expiration, priority band, and more.</p>
|
| 47 |
+
</div>
|
| 48 |
+
</div>
|
| 49 |
+
|
| 50 |
+
<section class="bg-gradient-to-r from-blue-600 to-indigo-700 rounded-2xl p-8 text-white mb-16">
|
| 51 |
+
<div class="max-w-3xl mx-auto text-center">
|
| 52 |
+
<h2 class="text-3xl font-bold mb-4">Ready to Unlock Development Potential?</h2>
|
| 53 |
+
<p class="text-blue-100 mb-6">
|
| 54 |
+
Our database contains thousands of underutilized sites scored and ranked for immediate development opportunities.
|
| 55 |
+
</p>
|
| 56 |
+
<a href="#" class="inline-block bg-white text-blue-600 font-semibold py-3 px-8 rounded-full hover:bg-gray-100 transition-colors">
|
| 57 |
+
Explore Top Candidates
|
| 58 |
+
</a>
|
| 59 |
+
</div>
|
| 60 |
+
</section>
|
| 61 |
+
|
| 62 |
+
<section class="mb-16">
|
| 63 |
+
<h2 class="text-3xl font-bold text-center mb-12 text-gray-800">How It Works</h2>
|
| 64 |
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
| 65 |
+
<div class="text-center">
|
| 66 |
+
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
| 67 |
+
<span class="text-blue-600 font-bold text-xl">1</span>
|
| 68 |
+
</div>
|
| 69 |
+
<h3 class="font-semibold text-lg mb-2">Data Ingestion</h3>
|
| 70 |
+
<p class="text-gray-600">We process lease records and geographic data from authoritative sources.</p>
|
| 71 |
+
</div>
|
| 72 |
+
|
| 73 |
+
<div class="text-center">
|
| 74 |
+
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
| 75 |
+
<span class="text-green-600 font-bold text-xl">2</span>
|
| 76 |
+
</div>
|
| 77 |
+
<h3 class="font-semibold text-lg mb-2">Scoring Algorithm</h3>
|
| 78 |
+
<p class="text-gray-600">Each site is evaluated across four key factors with weighted scoring.</p>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div class="text-center">
|
| 82 |
+
<div class="w-16 h-16 bg-yellow-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
| 83 |
+
<span class="text-yellow-600 font-bold text-xl">3</span>
|
| 84 |
+
</div>
|
| 85 |
+
<h3 class="font-semibold text-lg mb-2">Ranking & Prioritization</h3>
|
| 86 |
+
<p class="text-gray-600">Sites are ranked and categorized into priority bands A, B, or C.</p>
|
| 87 |
+
</div>
|
| 88 |
+
|
| 89 |
+
<div class="text-center">
|
| 90 |
+
<div class="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
| 91 |
+
<span class="text-purple-600 font-bold text-xl">4</span>
|
| 92 |
+
</div>
|
| 93 |
+
<h3 class="font-semibold text-lg mb-2">Actionable Insights</h3>
|
| 94 |
+
<p class="text-gray-600">Export top candidates and detailed reports for your team.</p>
|
| 95 |
+
</div>
|
| 96 |
+
</div>
|
| 97 |
+
</section>
|
| 98 |
+
</main>
|
| 99 |
+
|
| 100 |
+
<custom-footer></custom-footer>
|
| 101 |
+
|
| 102 |
+
<script src="components/header.js"></script>
|
| 103 |
+
<script src="components/footer.js"></script>
|
| 104 |
+
<script src="script.js"></script>
|
| 105 |
+
<script>feather.replace();</script>
|
| 106 |
+
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 107 |
+
</body>
|
| 108 |
+
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Smooth scrolling for anchor links
|
| 2 |
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
| 3 |
+
anchor.addEventListener('click', function(e) {
|
| 4 |
+
e.preventDefault();
|
| 5 |
+
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
| 6 |
+
behavior: 'smooth'
|
| 7 |
+
});
|
| 8 |
+
});
|
| 9 |
+
});
|
| 10 |
+
|
| 11 |
+
// Header scroll effect
|
| 12 |
+
window.addEventListener('scroll', () => {
|
| 13 |
+
const header = document.querySelector('header');
|
| 14 |
+
if (window.scrollY > 50) {
|
| 15 |
+
header.classList.add('scrolled');
|
| 16 |
+
} else {
|
| 17 |
+
header.classList.remove('scrolled');
|
| 18 |
+
}
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
// Initialize feather icons
|
| 22 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 23 |
+
feather.replace();
|
| 24 |
+
});
|
|
@@ -1,28 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
body {
|
| 2 |
-
|
| 3 |
-
|
|
|
|
| 4 |
}
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
margin-bottom: 10px;
|
| 15 |
-
margin-top: 5px;
|
| 16 |
}
|
| 17 |
|
| 18 |
.card {
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
}
|
| 25 |
|
| 26 |
-
.
|
| 27 |
-
|
|
|
|
| 28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
| 2 |
+
|
| 3 |
+
:root {
|
| 4 |
+
--primary-blue: #2563eb;
|
| 5 |
+
--secondary-blue: #1d4ed8;
|
| 6 |
+
--accent-purple: #7c3aed;
|
| 7 |
+
--light-gray: #f8fafc;
|
| 8 |
+
--dark-gray: #0f172a;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
body {
|
| 12 |
+
font-family: 'Inter', sans-serif;
|
| 13 |
+
background-color: var(--light-gray);
|
| 14 |
+
color: var(--dark-gray);
|
| 15 |
}
|
| 16 |
|
| 17 |
+
.btn-primary {
|
| 18 |
+
background: linear-gradient(90deg, var(--primary-blue), var(--secondary-blue));
|
| 19 |
+
color: white;
|
| 20 |
+
padding: 0.75rem 1.5rem;
|
| 21 |
+
border-radius: 9999px;
|
| 22 |
+
font-weight: 600;
|
| 23 |
+
transition: all 0.3s ease;
|
| 24 |
+
box-shadow: 0 4px 6px rgba(37, 99, 235, 0.2);
|
| 25 |
}
|
| 26 |
|
| 27 |
+
.btn-primary:hover {
|
| 28 |
+
transform: translateY(-2px);
|
| 29 |
+
box-shadow: 0 6px 12px rgba(37, 99, 235, 0.3);
|
|
|
|
|
|
|
| 30 |
}
|
| 31 |
|
| 32 |
.card {
|
| 33 |
+
transition: all 0.3s ease;
|
| 34 |
+
border-radius: 1rem;
|
| 35 |
+
overflow: hidden;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.card:hover {
|
| 39 |
+
transform: translateY(-5px);
|
| 40 |
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.gradient-bg {
|
| 44 |
+
background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.text-gradient {
|
| 48 |
+
background: linear-gradient(90deg, #2563eb, #7c3aed);
|
| 49 |
+
-webkit-background-clip: text;
|
| 50 |
+
-webkit-text-fill-color: transparent;
|
| 51 |
+
background-clip: text;
|
| 52 |
}
|
| 53 |
|
| 54 |
+
.hero-section {
|
| 55 |
+
background: radial-gradient(circle at top right, rgba(37, 99, 235, 0.1) 0%, transparent 40%),
|
| 56 |
+
radial-gradient(circle at bottom left, rgba(124, 58, 237, 0.1) 0%, transparent 40%);
|
| 57 |
}
|
| 58 |
+
|
| 59 |
+
.feature-icon {
|
| 60 |
+
width: 3rem;
|
| 61 |
+
height: 3rem;
|
| 62 |
+
display: flex;
|
| 63 |
+
align-items: center;
|
| 64 |
+
justify-content: center;
|
| 65 |
+
border-radius: 50%;
|
| 66 |
+
margin-bottom: 1rem;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
@media (max-width: 768px) {
|
| 70 |
+
.hero-section {
|
| 71 |
+
padding: 2rem 1rem;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
.feature-grid {
|
| 75 |
+
grid-template-columns: 1fr;
|
| 76 |
+
}
|
| 77 |
+
}
|