Skip to content

Commit 5199aae

Browse files
Sbussisoclaude
andcommitted
feat(landing): privacy-first hero section with vs-competitors micro-table
The landing page was burying the privacy differentiator in a generic "Fully Encrypted" feature card. A visitor scanning the grid for 10 seconds couldn't tell us apart from any other cloud camera company. With /security and the full Ring/Nest/Wyze comparison now shipping, it makes sense to surface the pitch on the page that decides whether someone keeps reading. ### New section (#privacy) Inserted between the features grid and the architecture section. On purpose breaks the alt/non-alt background rhythm — dedicated gradient treatment so the visual hierarchy says "read this one". Two-column grid, stacks on mobile at 900px, collapses the comparison cards to a single column at 480px. **Left column** — the claim, in order of how someone scans: - Eyebrow: "Privacy by design" - Headline: "Your footage never leaves your network for AI." - One-paragraph lede contrasting consumer cameras that cloud-ML frames against our on-device FFmpeg + ~60s in-memory cache - Four checkmarked bullets: on-device motion, AES-256-GCM recordings, no analytics, no-video-to-hand-over LE posture - Two CTAs — primary to /security (gradient button matching existing .landing-btn-primary), secondary to /legal/privacy **Right column** — side-by-side "SourceBox Sentry" vs "Ring · Nest · Wyze" mini comparison cards. Us-card green-tinted, them-card red-tinted with ✓ / ✗ rows. Four rows each, matched by topic so the reader's eye naturally compares across. ### Tightened existing feature card "Fully Encrypted" → "Encrypted End to End to Disk" with concrete copy (HTTPS in transit, AES-256-GCM at rest, machine-id-derived key, stolen drive unreadable). The vague original predated the BLOB encryption commit — this catches the card up to what's actually shipping. ### Accessibility `aria-hidden` on the visual comparison block because the same information is already enumerated in the checkmarked bullets above. Screen readers get the bullets, not the decorative duplicate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 956c8e8 commit 5199aae

2 files changed

Lines changed: 266 additions & 3 deletions

File tree

frontend/src/pages/LandingPage.jsx

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,11 @@ function LandingPage() {
101101
</div>
102102
<div className="landing-feature-card">
103103
<div className="landing-feature-icon">🔒</div>
104-
<h3>Fully Encrypted</h3>
104+
<h3>Encrypted End to End to Disk</h3>
105105
<p>
106-
HTTPS web UI with Clerk multi-tenant authentication. HLS segments are
107-
served same-origin behind your JWT — no third-party storage in the live video path.
106+
HTTPS from camera to browser. Recordings on the CloudNode are sealed at
107+
rest with AES-256-GCM using a machine-id-derived key — a stolen drive
108+
is unreadable elsewhere.
108109
</p>
109110
</div>
110111
<div className="landing-feature-card">
@@ -152,6 +153,66 @@ function LandingPage() {
152153
</div>
153154
</section>
154155

156+
{/* Privacy-first — positioned after the features grid so a scanning
157+
visitor sees it right after "why us". Breaks the alt/non-alt rhythm
158+
on purpose; the colour treatment signals "read this one". */}
159+
<section id="privacy" className="landing-section-privacy">
160+
<div className="landing-container">
161+
<div className="landing-privacy-grid">
162+
<div className="landing-privacy-copy">
163+
<span className="landing-privacy-eyebrow">Privacy by design</span>
164+
<h2 className="landing-privacy-title">
165+
Your footage never leaves your network for AI.
166+
</h2>
167+
<p className="landing-privacy-lede">
168+
Consumer cameras ship frames to cloud services so they can run
169+
person, vehicle, and face detection. We don't — motion analysis
170+
runs on your CloudNode using FFmpeg, and the cloud only ever
171+
holds a rolling 60-second live buffer in memory. Your recordings
172+
stay on hardware you own, encrypted at rest.
173+
</p>
174+
<ul className="landing-privacy-points">
175+
<li><strong>Motion detection runs locally.</strong> No ML API calls, no frames uploaded, no cloud vision service.</li>
176+
<li><strong>Recordings are encrypted at rest.</strong> AES-256-GCM with a key derived from your device's OS machine ID.</li>
177+
<li><strong>No analytics, no ad networks, no data brokers.</strong> Verifiable in our source with a single grep.</li>
178+
<li><strong>We don't hold your video.</strong> If law enforcement asks for footage, they have to ask you — we don't have it to hand over.</li>
179+
</ul>
180+
<div className="landing-privacy-ctas">
181+
<Link to="/security" className="landing-privacy-cta primary">
182+
How we compare →
183+
</Link>
184+
<Link to="/legal/privacy" className="landing-privacy-cta secondary">
185+
Read the Privacy Policy
186+
</Link>
187+
</div>
188+
</div>
189+
190+
<div className="landing-privacy-visual" aria-hidden="true">
191+
<div className="landing-privacy-compare">
192+
<div className="landing-privacy-card us">
193+
<div className="landing-privacy-card-label">SourceBox Sentry</div>
194+
<ul>
195+
<li><span className="chk yes"></span> Motion runs on-device</li>
196+
<li><span className="chk yes"></span> Recordings encrypted at rest</li>
197+
<li><span className="chk yes"></span> No analytics or trackers</li>
198+
<li><span className="chk yes"></span> Open source (AGPL / GPL)</li>
199+
</ul>
200+
</div>
201+
<div className="landing-privacy-card them">
202+
<div className="landing-privacy-card-label">Ring · Nest · Wyze</div>
203+
<ul>
204+
<li><span className="chk no"></span> Cloud ML on your video</li>
205+
<li><span className="chk no"></span> Vendor holds the keys</li>
206+
<li><span className="chk no"></span> Ad-sharing disclosed (Wyze)</li>
207+
<li><span className="chk no"></span> Proprietary firmware</li>
208+
</ul>
209+
</div>
210+
</div>
211+
</div>
212+
</div>
213+
</div>
214+
</section>
215+
155216
{/* Architecture Section */}
156217
<section id="architecture" className="landing-section">
157218
<div className="landing-container">

frontend/src/styles/landing.css

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,4 +1968,206 @@
19681968
grid-template-columns: 1fr;
19691969
gap: 2rem;
19701970
}
1971+
}
1972+
1973+
/* ── Privacy section ──────────────────────────────────────────────
1974+
Placed between the features grid and the architecture section.
1975+
Distinct gradient so it visually breaks the alternating rhythm —
1976+
this is the "read this one" section. */
1977+
.landing-section-privacy {
1978+
padding: 6rem 0;
1979+
background:
1980+
radial-gradient(1200px 400px at 10% 10%, rgba(59, 130, 246, 0.10), transparent 60%),
1981+
radial-gradient(900px 400px at 90% 90%, rgba(34, 197, 94, 0.08), transparent 60%),
1982+
var(--bg-primary, #0b0c0f);
1983+
border-top: 1px solid rgba(255, 255, 255, 0.06);
1984+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
1985+
}
1986+
1987+
.landing-privacy-grid {
1988+
display: grid;
1989+
grid-template-columns: 1.35fr 1fr;
1990+
gap: 3.5rem;
1991+
align-items: center;
1992+
}
1993+
1994+
.landing-privacy-eyebrow {
1995+
display: inline-block;
1996+
font-size: 0.75rem;
1997+
letter-spacing: 0.12em;
1998+
text-transform: uppercase;
1999+
color: var(--accent-green, #22c55e);
2000+
font-weight: 600;
2001+
margin-bottom: 0.75rem;
2002+
}
2003+
2004+
.landing-privacy-title {
2005+
font-size: clamp(1.75rem, 3.5vw, 2.5rem);
2006+
line-height: 1.15;
2007+
letter-spacing: -0.02em;
2008+
margin: 0 0 1rem;
2009+
}
2010+
2011+
.landing-privacy-lede {
2012+
color: var(--text-secondary);
2013+
font-size: 1.05rem;
2014+
line-height: 1.6;
2015+
margin-bottom: 1.5rem;
2016+
}
2017+
2018+
.landing-privacy-points {
2019+
list-style: none;
2020+
padding: 0;
2021+
margin: 0 0 2rem;
2022+
}
2023+
2024+
.landing-privacy-points li {
2025+
position: relative;
2026+
padding-left: 1.5rem;
2027+
margin-bottom: 0.75rem;
2028+
color: var(--text-secondary);
2029+
line-height: 1.55;
2030+
}
2031+
2032+
.landing-privacy-points li::before {
2033+
content: "✓";
2034+
position: absolute;
2035+
left: 0;
2036+
top: 0;
2037+
color: var(--accent-green, #22c55e);
2038+
font-weight: 700;
2039+
}
2040+
2041+
.landing-privacy-points li strong {
2042+
color: var(--text-primary);
2043+
font-weight: 600;
2044+
}
2045+
2046+
.landing-privacy-ctas {
2047+
display: flex;
2048+
gap: 0.75rem;
2049+
flex-wrap: wrap;
2050+
}
2051+
2052+
.landing-privacy-cta {
2053+
display: inline-flex;
2054+
align-items: center;
2055+
gap: 0.4rem;
2056+
padding: 0.75rem 1.35rem;
2057+
border-radius: 8px;
2058+
font-size: 0.95rem;
2059+
font-weight: 500;
2060+
text-decoration: none;
2061+
transition: all 0.2s ease;
2062+
}
2063+
2064+
.landing-privacy-cta.primary {
2065+
background: linear-gradient(135deg, #22c55e, #16a34a);
2066+
color: #000;
2067+
}
2068+
2069+
.landing-privacy-cta.primary:hover {
2070+
transform: translateY(-2px);
2071+
box-shadow: 0 8px 25px rgba(34, 197, 94, 0.3);
2072+
}
2073+
2074+
.landing-privacy-cta.secondary {
2075+
background: transparent;
2076+
border: 1px solid var(--border-light, rgba(255, 255, 255, 0.15));
2077+
color: var(--text-primary);
2078+
}
2079+
2080+
.landing-privacy-cta.secondary:hover {
2081+
background: var(--bg-card, rgba(255, 255, 255, 0.04));
2082+
border-color: var(--accent-green, #22c55e);
2083+
}
2084+
2085+
/* Side-by-side comparison cards — us green-tinted, them muted red —
2086+
so the visual differentiator is obvious at a glance without any copy. */
2087+
.landing-privacy-visual {
2088+
display: flex;
2089+
justify-content: center;
2090+
}
2091+
2092+
.landing-privacy-compare {
2093+
display: grid;
2094+
grid-template-columns: 1fr 1fr;
2095+
gap: 0.75rem;
2096+
width: 100%;
2097+
max-width: 520px;
2098+
}
2099+
2100+
.landing-privacy-card {
2101+
background: var(--bg-card, rgba(255, 255, 255, 0.04));
2102+
border: 1px solid var(--border-color, rgba(255, 255, 255, 0.08));
2103+
border-radius: 12px;
2104+
padding: 1.25rem 1rem;
2105+
}
2106+
2107+
.landing-privacy-card.us {
2108+
border-color: rgba(34, 197, 94, 0.4);
2109+
background: linear-gradient(180deg, rgba(34, 197, 94, 0.08), rgba(34, 197, 94, 0.02));
2110+
}
2111+
2112+
.landing-privacy-card.them {
2113+
border-color: rgba(239, 68, 68, 0.3);
2114+
background: linear-gradient(180deg, rgba(239, 68, 68, 0.05), rgba(239, 68, 68, 0.01));
2115+
}
2116+
2117+
.landing-privacy-card-label {
2118+
font-size: 0.75rem;
2119+
letter-spacing: 0.08em;
2120+
text-transform: uppercase;
2121+
font-weight: 600;
2122+
color: var(--text-primary);
2123+
margin-bottom: 0.85rem;
2124+
padding-bottom: 0.5rem;
2125+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
2126+
}
2127+
2128+
.landing-privacy-card ul {
2129+
list-style: none;
2130+
padding: 0;
2131+
margin: 0;
2132+
font-size: 0.85rem;
2133+
color: var(--text-secondary);
2134+
}
2135+
2136+
.landing-privacy-card li {
2137+
padding: 0.4rem 0;
2138+
display: flex;
2139+
align-items: flex-start;
2140+
gap: 0.5rem;
2141+
line-height: 1.4;
2142+
}
2143+
2144+
.landing-privacy-card .chk {
2145+
flex-shrink: 0;
2146+
width: 1.1rem;
2147+
font-weight: 700;
2148+
}
2149+
2150+
.landing-privacy-card .chk.yes {
2151+
color: var(--accent-green, #22c55e);
2152+
}
2153+
2154+
.landing-privacy-card .chk.no {
2155+
color: #ef4444;
2156+
}
2157+
2158+
@media (max-width: 900px) {
2159+
.landing-privacy-grid {
2160+
grid-template-columns: 1fr;
2161+
gap: 2.5rem;
2162+
}
2163+
2164+
.landing-privacy-compare {
2165+
max-width: 100%;
2166+
}
2167+
}
2168+
2169+
@media (max-width: 480px) {
2170+
.landing-privacy-compare {
2171+
grid-template-columns: 1fr;
2172+
}
19712173
}

0 commit comments

Comments
 (0)