diff --git a/frontend/src/App.js b/frontend/src/App.js
index 0b2067a..79aadf2 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
+import LandingView from './components/LandingView';
import UploadView from './components/UploadView';
import QueryView from './components/QueryView';
import './App.css';
@@ -11,7 +12,7 @@ const API_BASE_URL =
: 'https://documindrex.onrender.com');
export default function App() {
- const [view, setView] = useState('upload');
+ const [view, setView] = useState('landing');
const [transitionClass, setTransitionClass] = useState('visible');
const [documentId, setDocumentId] = useState(null);
const [documentName, setDocumentName] = useState('');
@@ -101,6 +102,14 @@ export default function App() {
}, 300);
};
+ if (view === 'landing') {
+ return (
+
diff --git a/frontend/src/components/LandingView.css b/frontend/src/components/LandingView.css
new file mode 100644
index 0000000..bd0df44
--- /dev/null
+++ b/frontend/src/components/LandingView.css
@@ -0,0 +1,436 @@
+@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&display=swap');
+
+/* ─── Shell ──────────────────────────────────────────────── */
+
+.landing {
+ position: relative;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: #060606;
+ color: #ffffff;
+ font-family: 'DM Sans', -apple-system, sans-serif;
+ overflow: hidden;
+}
+
+/* Grain overlay */
+.landing__noise {
+ position: absolute;
+ inset: 0;
+ z-index: 0;
+ pointer-events: none;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23g)'/%3E%3C/svg%3E");
+ background-repeat: repeat;
+ opacity: 0.028;
+}
+
+/* Sage-green ambient glow — top right */
+.landing__glow {
+ position: absolute;
+ top: -160px;
+ right: -120px;
+ width: 780px;
+ height: 780px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(100, 148, 100, 0.20) 0%, transparent 62%);
+ pointer-events: none;
+ z-index: 0;
+}
+
+/* ─── Nav ────────────────────────────────────────────────── */
+
+.landing__nav {
+ position: relative;
+ z-index: 10;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1.2rem 2.5rem;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+.landing__logo {
+ display: flex;
+ align-items: center;
+ gap: 0.55rem;
+ font-family: 'Syne', sans-serif;
+ font-weight: 700;
+ font-size: 0.95rem;
+ letter-spacing: 0.01em;
+ color: inherit;
+}
+
+.landing__logo-mark {
+ font-size: 1.15rem;
+ color: rgba(110, 168, 110, 0.95);
+ line-height: 1;
+}
+
+.landing__nav-links {
+ display: flex;
+ align-items: center;
+ gap: 1.75rem;
+ font-size: 0.84rem;
+ color: rgba(255, 255, 255, 0.5);
+}
+
+.landing__nav-links a {
+ color: inherit;
+ text-decoration: none;
+ transition: color 180ms ease;
+}
+.landing__nav-links a:hover { color: rgba(255, 255, 255, 0.88); }
+
+.landing__nav-cta {
+ font-size: 0.83rem;
+ font-family: 'DM Sans', sans-serif;
+ padding: 0.45rem 1.15rem;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ background: rgba(255, 255, 255, 0.04);
+ color: rgba(255, 255, 255, 0.78);
+ cursor: pointer;
+ transition: border-color 180ms, background 180ms, color 180ms;
+}
+.landing__nav-cta:hover {
+ border-color: rgba(255, 255, 255, 0.32);
+ background: rgba(255, 255, 255, 0.08);
+ color: #fff;
+}
+
+/* ─── Hero ───────────────────────────────────────────────── */
+
+.landing__hero {
+ position: relative;
+ z-index: 1;
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 580px;
+}
+
+/* ─── Rail SVG ───────────────────────────────────────────── */
+
+.landing__rails-svg {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 2;
+}
+
+/* ─── Station nodes ──────────────────────────────────────── */
+/* Each station: circle bead ON the line + label beside it */
+
+.landing__station {
+ position: absolute;
+ z-index: 3;
+ display: flex;
+ align-items: center;
+ gap: 0.55rem;
+}
+
+/* Left-top: Parser — at the right end of left-top rail */
+.landing__station--lt {
+ top: 33%;
+ left: 13%;
+ transform: translateY(-50%);
+}
+
+/* Left-bottom: Embeddings — at the right end of left-bottom rail */
+.landing__station--lb {
+ top: 67%;
+ left: 8%;
+ transform: translateY(-50%);
+}
+
+/* Right-top: Retrieval — at the left end of right-top rail */
+.landing__station--rt {
+ top: 28%;
+ right: 13%;
+ transform: translateY(-50%);
+}
+
+/* Right-bottom: Citations — at the left end of right-bottom rail */
+.landing__station--rb {
+ top: 67%;
+ right: 11%;
+ transform: translateY(-50%);
+}
+
+/* Circle bead — dark fill so the line "passes through" it */
+.landing__station-circle {
+ flex-shrink: 0;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ border: 1px solid rgba(255, 255, 255, 0.10);
+ background: #090909;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.7rem;
+ color: rgba(255, 255, 255, 0.48);
+}
+
+.landing__station-text {
+ display: flex;
+ flex-direction: column;
+ gap: 0.14rem;
+}
+
+.landing__station-text--right {
+ text-align: right;
+}
+
+.landing__station-name {
+ font-size: 0.8rem;
+ color: rgba(255, 255, 255, 0.7);
+ font-family: 'DM Sans', sans-serif;
+ font-weight: 400;
+ white-space: nowrap;
+}
+
+.landing__station-sub {
+ font-size: 0.69rem;
+ color: rgba(255, 255, 255, 0.28);
+ font-family: 'DM Sans', sans-serif;
+ white-space: nowrap;
+}
+
+/* ─── Center content ─────────────────────────────────────── */
+
+.landing__center {
+ position: relative;
+ z-index: 4;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ gap: 1.2rem;
+ max-width: 620px;
+ padding: 0 2rem;
+}
+
+.landing__play {
+ width: 38px;
+ height: 38px;
+ border-radius: 50%;
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.62rem;
+ color: rgba(255, 255, 255, 0.42);
+ margin-bottom: 0.2rem;
+}
+
+.landing__badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.32rem 1rem 0.32rem 0.72rem;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.09);
+ background: rgba(255, 255, 255, 0.03);
+ font-size: 0.78rem;
+ color: rgba(255, 255, 255, 0.5);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+}
+
+.landing__badge-dot {
+ font-size: 0.68rem;
+ color: rgba(110, 168, 110, 0.9);
+ line-height: 1;
+}
+
+.landing__heading {
+ font-family: 'Syne', sans-serif;
+ font-size: clamp(2.8rem, 7vw, 5.8rem);
+ font-weight: 800;
+ letter-spacing: -0.04em;
+ line-height: 1.0;
+ margin: 0;
+ color: #ffffff;
+}
+
+.landing__slogan {
+ font-size: 0.95rem;
+ font-family: 'DM Sans', sans-serif;
+ font-weight: 400;
+ color: rgba(255, 255, 255, 0.38);
+ letter-spacing: 0.01em;
+ margin: -0.4rem 0 0;
+}
+
+.landing__sub {
+ font-size: 0.88rem;
+ color: rgba(255, 255, 255, 0.38);
+ line-height: 1.75;
+ font-weight: 300;
+ margin: 0;
+}
+
+.landing__ctas {
+ display: flex;
+ align-items: center;
+ gap: 0.7rem;
+ margin-top: 0.5rem;
+}
+
+.landing__cta-dark {
+ padding: 0.62rem 1.55rem;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ background: rgba(22, 22, 22, 0.92);
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 0.86rem;
+ font-family: 'DM Sans', sans-serif;
+ font-weight: 500;
+ cursor: pointer;
+ transition: background 180ms, border-color 180ms;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+}
+.landing__cta-dark:hover {
+ background: rgba(40, 40, 40, 0.95);
+ border-color: rgba(255, 255, 255, 0.28);
+}
+
+.landing__cta-light {
+ padding: 0.62rem 1.55rem;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ background: rgba(255, 255, 255, 0.93);
+ color: #0a0a0a;
+ font-size: 0.86rem;
+ font-family: 'DM Sans', sans-serif;
+ font-weight: 500;
+ cursor: pointer;
+ transition: background 180ms;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+}
+.landing__cta-light:hover { background: rgba(245, 245, 245, 0.95); }
+
+/* ─── Bar visualizer ─────────────────────────────────────── */
+
+.landing__bars {
+ position: absolute;
+ bottom: 68px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ align-items: flex-end;
+ gap: 5px;
+ height: 88px;
+ z-index: 2;
+}
+
+.landing__bar {
+ width: 3px;
+ height: var(--h, 50%);
+ background: rgba(255, 255, 255, 0.09);
+ border-radius: 2px 2px 0 0;
+ animation: bar-breathe 3.5s ease-in-out infinite;
+ animation-delay: var(--d, 0s);
+ transform-origin: bottom;
+}
+
+@keyframes bar-breathe {
+ 0%, 100% { opacity: 0.3; transform: scaleY(0.6); }
+ 50% { opacity: 0.8; transform: scaleY(1); }
+}
+
+/* ─── Bottom indicators ──────────────────────────────────── */
+
+.landing__scroll {
+ position: absolute;
+ bottom: 1.75rem;
+ left: 2.5rem;
+ display: flex;
+ align-items: center;
+ gap: 0.7rem;
+ z-index: 5;
+}
+
+.landing__scroll-icon {
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.68rem;
+ color: rgba(255, 255, 255, 0.55);
+}
+
+.landing__scroll-text {
+ font-size: 0.75rem;
+ color: rgba(255, 255, 255, 0.32);
+ font-family: 'DM Sans', sans-serif;
+}
+
+.landing__section-label {
+ position: absolute;
+ bottom: 1.75rem;
+ right: 2.5rem;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 0.4rem;
+ font-size: 0.76rem;
+ color: rgba(255, 255, 255, 0.32);
+ font-family: 'DM Sans', sans-serif;
+ z-index: 5;
+}
+
+.landing__section-line {
+ width: 26px;
+ height: 1px;
+ background: rgba(255, 255, 255, 0.2);
+}
+
+/* ─── Tech strip ─────────────────────────────────────────── */
+
+.landing__strip {
+ position: relative;
+ z-index: 5;
+ display: flex;
+ align-items: center;
+ gap: 2.5rem;
+ padding: 1.15rem 2.5rem;
+ border-top: 1px solid rgba(255, 255, 255, 0.055);
+ background: rgba(0, 0, 0, 0.25);
+}
+
+.landing__strip-label {
+ font-size: 0.72rem;
+ color: rgba(255, 255, 255, 0.2);
+ font-family: 'DM Sans', sans-serif;
+ white-space: nowrap;
+}
+
+.landing__strip-logos {
+ display: flex;
+ align-items: center;
+ gap: 2.25rem;
+ flex-wrap: wrap;
+}
+
+.landing__strip-logo {
+ font-size: 0.8rem;
+ font-family: 'Syne', sans-serif;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ color: rgba(255, 255, 255, 0.2);
+ transition: color 180ms ease;
+ cursor: default;
+}
+.landing__strip-logo:hover { color: rgba(255, 255, 255, 0.45); }
diff --git a/frontend/src/components/LandingView.jsx b/frontend/src/components/LandingView.jsx
new file mode 100644
index 0000000..f062d86
--- /dev/null
+++ b/frontend/src/components/LandingView.jsx
@@ -0,0 +1,158 @@
+import React from 'react';
+import './LandingView.css';
+
+export default function LandingView({ onOpenApp }) {
+ return (
+
+
+
+
+ {/* ── Nav ───────────────────────────────────────────── */}
+
+
+ {/* ── Hero ──────────────────────────────────────────── */}
+
+
+ {/* Horizontal rail lines (SVG) */}
+
+
+ {/* Left-top station: Parser */}
+
+
▲
+
+ • Parser
+ PDF · DOCX · TXT
+
+
+
+ {/* Left-bottom station: Embeddings */}
+
+
⬡
+
+ • Embeddings
+ 1536-d vectors
+
+
+
+ {/* Right-top station: Retrieval */}
+
+
+ • Retrieval
+ Semantic search
+
+
✳
+
+
+ {/* Right-bottom station: Citations */}
+
+
+ • Citations
+ Source-linked
+
+
◈
+
+
+ {/* ── Center content ─────────────────────────────── */}
+
+
▶
+
+
+ ◉
+ ask questions, get cited answers →
+
+
+
DocuMind
+
+
Upload once. Ask anything.
+
+
+ Upload a PDF or paste text. Ask anything.
+ You get the answer and exactly where it came from.
+
+
+
+
+
+ {/* Bar visualizer */}
+
+ {[
+ { h: '55%', d: '0s' },
+ { h: '90%', d: '0.3s' },
+ { h: '100%',d: '0.15s' },
+ { h: '70%', d: '0.45s' },
+ { h: '40%', d: '0.1s' },
+ ].map((b, i) => (
+
+ ))}
+
+
+ {/* Bottom indicators */}
+
+ ↓
+ 01/02 · Scroll down
+
+
+
+
+
+ {/* ── Tech strip ────────────────────────────────────── */}
+
+
Powered by
+
+ {['OpenAI', 'Cohere', 'Pinecone', 'FastAPI', 'React', 'Render'].map((name) => (
+ {name}
+ ))}
+
+
+
+ );
+}