diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/app.js b/docs/app.js new file mode 100644 index 0000000..3d2461c --- /dev/null +++ b/docs/app.js @@ -0,0 +1,46 @@ +/* OVERWATCH landing — count-up stats + scroll reveal. No network, no deps. */ +(function () { + 'use strict'; + const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + + /* count-up numbers when the stats row scrolls into view */ + function countUp(el) { + const target = parseInt(el.dataset.target, 10); + if (isNaN(target)) return; + if (!target || reduceMotion) { el.textContent = String(target); return; } + const dur = 1100, start = performance.now(); + (function tick(now) { + const p = Math.min(1, (now - start) / dur); + el.textContent = String(Math.round(target * (1 - Math.pow(1 - p, 3)))); + if (p < 1) requestAnimationFrame(tick); + })(performance.now()); + } + + const statsRow = document.getElementById('stats-row'); + if (statsRow) { + const nums = statsRow.querySelectorAll('.num[data-target]'); + if ('IntersectionObserver' in window && !reduceMotion) { + const io = new IntersectionObserver((entries, obs) => { + entries.forEach((e) => { + if (e.isIntersecting) { nums.forEach(countUp); obs.disconnect(); } + }); + }, { threshold: 0.4 }); + io.observe(statsRow); + } else { + nums.forEach((el) => { el.textContent = el.dataset.target; }); + } + } + + /* scroll-triggered reveal */ + const reveals = document.querySelectorAll('.reveal'); + if (!('IntersectionObserver' in window) || reduceMotion) { + reveals.forEach((el) => el.classList.add('in')); + } else { + const ro = new IntersectionObserver((entries, obs) => { + entries.forEach((e) => { + if (e.isIntersecting) { e.target.classList.add('in'); obs.unobserve(e.target); } + }); + }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }); + reveals.forEach((el) => ro.observe(el)); + } +})(); diff --git a/docs/img/overwatch-main.png b/docs/img/overwatch-main.png new file mode 100644 index 0000000..e61bc81 Binary files /dev/null and b/docs/img/overwatch-main.png differ diff --git a/docs/img/overwatch-settings.png b/docs/img/overwatch-settings.png new file mode 100644 index 0000000..86a1fa7 Binary files /dev/null and b/docs/img/overwatch-settings.png differ diff --git a/docs/img/overwatch-sources.png b/docs/img/overwatch-sources.png new file mode 100644 index 0000000..f6d70fa Binary files /dev/null and b/docs/img/overwatch-sources.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..8b9e1cb --- /dev/null +++ b/docs/index.html @@ -0,0 +1,473 @@ + + + + + +OVERWATCH — passive surveillance detection for Android + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + v0.5.2 · Android · passive +
+

+ OVERWATCH +

+

+ A native Android app that passively detects surveillance around you. + Open it, hit START, and a ring turns green → yellow → + orange → red as the engine gets more sure there's a Flock Safety ALPR, + an Axon body camera, or active police nearby. + It only listens. It never transmits, probes, or jams. +

+ +
+ OVERWATCH main screen: a live map inside a green "all clear" threat ring, centered on the user with a crosshair, and a STOP button. +
+ +
+
0fused sources
+
0threat tiers
+
0packets sent
+
0releases
+
+ + + +

Passive defense only. Debug-signed APK — sideload; no Play Store. Read the README.

+
+
+ + +
+
+
+ Fuses signal from +
    +
  • Bluetooth-LE + WiFi radio
  • +
  • DeFlock ALPR map
  • +
  • Citizen incidents
  • +
  • Waze police alerts
  • +
  • OpenStreetMap · Overpass
  • +
+
+
+
+ + +
+
+
+ +

One tap. A live threat map.

+

+ While scanning, the circle becomes an OpenStreetMap centered on + you, wrapped in a threat-color ring for the current tier and + marked with a ⌖ crosshair. Every detection is a dot, color-coded by + source — so each mark is self-explanatory. Lock the screen and the + foreground notification keeps the tier live; the phone vibrates only + when the threat escalates. +

+
+ +
+
+ Detection-sources drill-down: BLE, WiFi, DeFlock, Citizen, Waze and Commercial rows, each with a color tier dot and the observations that fired it. +
+
+
+ 1 +
+ Threat-color ring +

The map is wrapped in the current tier's color — green, yellow, + orange, or red — so you read your situation at a glance without + opening anything.

+
+
+
+ 2 +
+ Source-color dots +

Flock / DeFlock cameras red · + Waze police blue · + Citizen incidents purple. + Tap any row for coordinates + a Maps deep-link.

+
+
+
+ 3 +
+ Foreground notification +

Rebuilt on every tier change — OVERWATCH • RED with + the top detection's score. Priority bumps to HIGH on RED so the + system surfaces it as a heads-up, screen locked or not.

+
+
+
+ 4 +
+ Escalation-only haptics +

A short pulse for YELLOW, double for ORANGE, escalating triple + for RED — but only on upward transitions, so it never + nags you while a threat lingers.

+
+
+
+
+
+
+ + +
+
+
+ +

Six sensors, one score.

+

Every observation is scored 0–100 by the confidence + engine; the on-screen tier is the max live score across all + sources. Cross-source corroboration — a BLE hit and a + DeFlock map match in the same spot — naturally pushes the tier higher + than either alone.

+
+ +
+
+
📶
+

BLE — Bluetooth-LE

+

+ Vendor MAC OUIs (Axon, Flock Penguin / Raven, XUNTONG mfg id + 0x09C8, "TN" serial pattern), Raven service UUIDs, and + device-name patterns. Iterates every manufacturer-data entry + per advert — not just the first — so it doesn't miss a buried match. +

+
+ +
+
📡
+

WiFi

+

+ BSSID OUI prefixes for Flock infrastructure (31-prefix superset) and + Flock-XXXX SSID patterns, polled every 35 s — just under + the Android 11+ scan throttle. +

+
+ +
+
🎥
+

DeFlock — ALPR map

+

+ Crowdsourced ALPR camera locations within range (200 m default) via + the Overpass API (overpass.deflock.org → fallback + overpass-api.de), with a 24 h on-disk cache and failure + backoff. Refetches when you move > 1.5 km. +

+
+ +
+
🚨
+

Citizen

+

+ Real-time public-safety incidents — police-relevant only, + fire/medical filtered out — within range and under 30 min old, + polled every 60 s from the Citizen trending feed. +

+
+ +
+
🚓
+

Waze — police alerts

+

+ Live user-reported POLICE alerts (default 500 m, + ~45 min freshness). Waze reCAPTCHA-gated its map endpoint, so + OVERWATCH reads a key-protected feed through a Caddy proxy at + api.blackflagintel.com that injects the key + server-side — the paid key never ships in the APK. + The app authenticates with a scoped, revocable X-App-Token + stored encrypted in the Android Keystore. +

+
+ +
+
🏠
+

Commercial

+

+ Nearby consumer smart-home gear (Nest, Ring, Echo, hidden cams) as a + secondary situational signal, riding the BLE + WiFi scans. + Score-capped at ORANGE so a cluster of doorbells never reads as + ALPR-grade certainty. +

+
+
+
+
+ + +
+
+
+ +

Four tiers. Highest live score wins.

+
+ +
+
+
< 40
+
GREEN
+

Nothing credible. Idle shows a muted gray ring so "all clear" reads differently from "not scanning."

+
+
+
40 – 69
+
YELLOW
+

A single weak indicator. Short vibration pulse on the way up.

+
+
+
70 – 84
+
ORANGE
+

High confidence — usually a hard radio hit or a close map match. Double pulse.

+
+
+
85 +
+
RED
+

Certain. Notification jumps to HIGH priority; escalating triple pulse.

+
+
+
+
+ + +
+
+
+ +

Runs in your pocket, not the cloud.

+
+ +
+
+
🔇
+

Passive by design

+

+ OVERWATCH only listens — it never transmits, probes, jams, or + interferes with any device or network. The Axon advertise/fuzz code + from one of the reference projects is intentionally + excluded. It reads the airwaves and public feeds; that's it. +

+
+ +
+
🫧
+

Floating overlay

+

+ The same threat-ring map renders in a small draggable bubble over + other apps (Settings → Display over other apps), so it stays with + you while you use your phone. +

+
+ +
+
🔐
+

Keys stay off-device

+

+ The paid Waze feed key lives server-side behind the proxy; the app + holds only a scoped, revocable token, encrypted via the Android + Keystore. No secrets in the APK. +

+
+ +
+
🩺
+

Honest per-source health

+

+ The drill-down marks a source Source unreachable when + its scanner couldn't reach its feed — a silent empty result and a + real failure look different. +

+
+ +
+
🗺
+

Your position, not your data

+

+ Location drives the proximity checks and the map on-device. No + account, no telemetry, no analytics — the scans and feeds run and + the results stay on your phone. +

+
+
+
+
+ + +
+
+
+
🛡
+
+

Situational awareness, not interference

+

+ OVERWATCH is a defensive, receive-only tool for knowing what's + watching you — Flock ALPRs, Axon body cameras, and police + presence — in the space you're already in. It does not touch, spoof, + or disrupt anything. Know your local laws; use it responsibly. +

+
+
+
+
+ + +
+
+
+ +

Sideload in three steps.

+
+ +
+
+ Settings screen: per-source toggles (BLE, WiFi, DeFlock, Citizen, Waze, Commercial), proximity distance sliders, and the encrypted Waze proxy token field. +
+
+
+
1 · download
+
    +
  • Grab the latest debug-signed APK from + Releases + (currently v0.5.2).
  • +
+
+
+
2 · install
+
    +
  • Sideload it — allow "install unknown apps" for your browser or files app, then open the APK.
  • +
+
+
+
3 · grant + start
+
    +
  • Grant location + nearby-devices + notifications, toggle the sources you want, hit START.
  • +
  • Optional: paste a Waze proxy token in Settings for police-report coverage.
  • +
+
+
+
+ +

+ Build from source, file issues, or read the internals: + github.com/KaraZajac/OVERWATCH +

+
+
+ + + + + + + + diff --git a/docs/og-card.html b/docs/og-card.html new file mode 100644 index 0000000..34b987c --- /dev/null +++ b/docs/og-card.html @@ -0,0 +1,35 @@ + + + +
+
OVERWATCH
+
Passive surveillance detection for Android. Flag nearby Flock ALPRs, Axon body cams & policeit only listens.
+
+ GREEN + YELLOW + ORANGE + RED +
+
BLE · WiFi · DeFlock · Citizen · Waze  —  six sensors, fused
+
+
overwatch.netslum.io
+ diff --git a/docs/og.png b/docs/og.png new file mode 100644 index 0000000..a4a1dcb Binary files /dev/null and b/docs/og.png differ diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 0000000..54fa27d --- /dev/null +++ b/docs/style.css @@ -0,0 +1,1087 @@ +/* ============================================================ + SKELETONKEY — landing page · marketing-grade redesign · v0.6.0 + palette: deep purple-tinted dark + emerald + KEV-red accents + fonts: Inter · JetBrains Mono · Space Grotesk display + ============================================================ */ + +* { box-sizing: border-box; } + +:root { + /* surfaces */ + --bg: #07070d; + --bg-2: #0c0c16; + --bg-3: #12121f; + --surface: #161628; + --surface-2: #1a1a30; + --border: #25253c; + --border-soft: #1c1c2d; + + /* text */ + --text: #ecedf7; + --text-soft: #c5c5d3; + --text-muted: #8a8a9d; + --text-dim: #5b5b75; + + /* accents */ + --accent: #10b981; /* emerald — primary, "ok/safe" */ + --accent-2: #06b6d4; /* cyan — primary gradient pair */ + --accent-hot: #34d399; /* lighter emerald, hover/glow */ + --warning: #f59e0b; /* amber — yellow modules */ + --danger: #ef4444; /* red — KEV/active exploit */ + --violet: #a855f7; /* violet — threat-intel accent */ + --blue: #60a5fa; /* blue — links */ + + /* gradients */ + --grad-brand: linear-gradient(135deg, #10b981 0%, #06b6d4 100%); + --grad-kev: linear-gradient(135deg, #ef4444 0%, #f59e0b 100%); + --grad-bg: radial-gradient(ellipse at top, rgba(16, 185, 129, 0.06) 0%, transparent 50%), + radial-gradient(ellipse at bottom right, rgba(168, 85, 247, 0.05) 0%, transparent 50%); + + /* type */ + --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif; + --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; + --display: "Space Grotesk", "Inter", -apple-system, sans-serif; + + /* layout */ + --maxw: 1180px; + --radius: 12px; + --radius-sm: 8px; + --radius-lg: 18px; + --shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.6); + --shadow-hi: 0 20px 60px -10px rgba(16, 185, 129, 0.15), 0 10px 30px -10px rgba(0, 0, 0, 0.6); +} + +html, body { + margin: 0; padding: 0; + background: var(--bg); + color: var(--text-soft); + font-family: var(--sans); + font-size: 16px; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; +} + +a { color: var(--accent-hot); text-decoration: none; transition: color .15s ease; } +a:hover { color: #fff; } + +code, pre { font-family: var(--mono); font-size: 0.93em; } +:not(pre) > code { + background: var(--surface); + border: 1px solid var(--border-soft); + border-radius: 4px; + padding: 0.08em 0.42em; + color: var(--accent-hot); + font-size: 0.86em; +} + +.container { + max-width: var(--maxw); + margin: 0 auto; + padding: 0 1.5rem; +} + +/* ============================================================ + ANIMATED GRADIENT MESH BACKGROUND (fixed, behind content) + ============================================================ */ +.bg-mesh { + position: fixed; + inset: 0; + z-index: -1; + overflow: hidden; + background: + var(--grad-bg), + var(--bg); +} +.mesh-blob { + position: absolute; + border-radius: 50%; + filter: blur(80px); + opacity: 0.4; + animation: drift 30s ease-in-out infinite alternate; +} +.mesh-blob-1 { + width: 580px; height: 580px; + background: radial-gradient(circle, rgba(16, 185, 129, 0.5), transparent 70%); + top: -150px; left: -150px; + animation-duration: 28s; +} +.mesh-blob-2 { + width: 480px; height: 480px; + background: radial-gradient(circle, rgba(6, 182, 212, 0.4), transparent 70%); + top: 200px; right: -120px; + animation-duration: 34s; animation-delay: -10s; +} +.mesh-blob-3 { + width: 420px; height: 420px; + background: radial-gradient(circle, rgba(168, 85, 247, 0.3), transparent 70%); + top: 700px; left: 40%; + animation-duration: 40s; animation-delay: -18s; +} +@keyframes drift { + 0% { transform: translate3d(0, 0, 0) rotate(0deg); } + 50% { transform: translate3d(80px, -40px, 0) rotate(120deg); } + 100% { transform: translate3d(-60px, 80px, 0) rotate(240deg); } +} +@media (prefers-reduced-motion: reduce) { + .mesh-blob { animation: none; } +} + +/* ============================================================ + TOP NAV + ============================================================ */ +.nav { + position: sticky; top: 0; z-index: 50; + padding: 0.85rem 0; + background: rgba(7, 7, 13, 0.72); + backdrop-filter: blur(14px) saturate(180%); + -webkit-backdrop-filter: blur(14px) saturate(180%); + border-bottom: 1px solid var(--border-soft); +} +.nav-inner { + display: flex; + align-items: center; + justify-content: space-between; +} +.nav-brand { + font-family: var(--mono); + font-weight: 700; + font-size: 0.95rem; + letter-spacing: 0.06em; + color: var(--text); + display: inline-flex; + align-items: center; + gap: 0.5rem; +} +.nav-brand:hover { color: #fff; } +.nav-mark { + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; height: 20px; + font-size: 1rem; + background: var(--grad-brand); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} +.nav-links { + display: flex; + align-items: center; + gap: 1.5rem; +} +.nav-links a { + font-size: 0.93rem; + color: var(--text-muted); + transition: color .15s ease; +} +.nav-links a:hover { color: var(--text); } +.nav-github { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; height: 36px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + color: var(--text-muted); +} +.nav-github:hover { + color: var(--text); + border-color: var(--accent); +} + +@media (max-width: 720px) { + .nav-links a:not(.nav-github) { display: none; } +} + +/* ============================================================ + HERO + ============================================================ */ +.hero { + padding: 5.5rem 0 5rem; + text-align: center; + position: relative; +} +.hero-inner { max-width: 880px; margin: 0 auto; } + +.hero-eyebrow { + display: inline-flex; + align-items: center; + gap: 0.5rem; + background: rgba(16, 185, 129, 0.08); + border: 1px solid rgba(16, 185, 129, 0.3); + color: var(--accent-hot); + font-family: var(--mono); + font-size: 0.8rem; + padding: 0.35rem 0.9rem; + border-radius: 999px; + margin-bottom: 1.5rem; +} +.dot { + display: inline-block; + width: 6px; height: 6px; + border-radius: 50%; + background: var(--accent-hot); +} +.dot-pulse { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); animation: pulse 2s infinite; } +@keyframes pulse { + 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.6); } + 70% { box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); } + 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } +} + +.hero-title { + margin: 0 0 1.25rem; + font-weight: 800; + letter-spacing: -0.04em; + line-height: 1; +} +.display-wordmark { + font-family: var(--display); + font-size: clamp(3rem, 11vw, 6.5rem); + background: linear-gradient(180deg, #fff 0%, #c5c5d3 80%, #8a8a9d 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + display: inline-block; +} + +.hero-tag { + font-size: clamp(1.05rem, 1.6vw, 1.25rem); + color: var(--text-soft); + margin: 0 auto 2.25rem; + max-width: 720px; +} +.hero-tag strong { color: #fff; } +.hero-tag-pop { + display: inline-block; + margin-top: 0.5rem; + padding: 0.2rem 0.6rem; + background: rgba(168, 85, 247, 0.1); + border-left: 2px solid var(--violet); + color: #d8b4fe; + font-family: var(--mono); + font-size: 0.85em; +} + +.install-block { + background: linear-gradient(180deg, rgba(22, 22, 40, 0.95) 0%, rgba(18, 18, 31, 0.95) 100%); + border: 1px solid var(--border); + border-radius: var(--radius); + margin: 0 auto 1.75rem; + max-width: 760px; + text-align: left; + position: relative; + box-shadow: var(--shadow); + overflow: hidden; +} +.install-bar { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.55rem 0.9rem; + background: rgba(0, 0, 0, 0.3); + border-bottom: 1px solid var(--border); +} +.install-dots { display: inline-flex; gap: 0.4rem; } +.install-dots i { + width: 11px; height: 11px; + border-radius: 50%; + background: var(--surface-2); + display: block; +} +.install-dots i:nth-child(1) { background: #ff5f57; } +.install-dots i:nth-child(2) { background: #febc2e; } +.install-dots i:nth-child(3) { background: #28c840; } +.install-title { + flex: 1; text-align: center; + font-family: var(--mono); font-size: 0.78rem; + color: var(--text-dim); letter-spacing: 0.04em; +} +.install-block pre { + margin: 0; + padding: 1rem 1.2rem; + color: var(--text); + white-space: pre-wrap; + word-break: break-all; + font-size: 0.92rem; + min-height: 2.5rem; +} +.install-block .prompt { color: var(--accent-hot); user-select: none; } +.cursor { color: var(--accent-hot); animation: blink 1s steps(2) infinite; } +@keyframes blink { 50% { opacity: 0; } } +.install-block .copy { + position: absolute; top: 0.5rem; right: 0.6rem; + background: rgba(0, 0, 0, 0.4); + border: 1px solid var(--border); + color: var(--text-muted); + font-family: var(--mono); + font-size: 0.72rem; padding: 0.25rem 0.55rem; + border-radius: 4px; + cursor: pointer; + transition: all .15s ease; +} +.install-block .copy:hover { color: var(--accent-hot); border-color: var(--accent); } +.install-block .copy.copied { color: var(--accent-hot); border-color: var(--accent); } + +.stats-row { + display: flex; flex-wrap: wrap; + gap: 0.6rem; justify-content: center; + margin: 0 0 2rem; +} +.stat-chip { + display: inline-flex; + align-items: baseline; + gap: 0.5rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 999px; + padding: 0.5rem 1.1rem; + font-size: 0.88rem; + color: var(--text-muted); +} +.stat-chip .num { + font-family: var(--mono); + font-weight: 700; + color: var(--text); + font-size: 1.05rem; + font-variant-numeric: tabular-nums; +} +.stat-chip.stat-kev { border-color: rgba(239, 68, 68, 0.3); } +.stat-chip.stat-kev .num { color: var(--danger); } +.stat-chip.stat-vfy { border-color: rgba(16, 185, 129, 0.4); } +.stat-chip.stat-vfy .num { color: var(--accent-hot); } + +.cta-row { + display: flex; gap: 0.75rem; + justify-content: center; + flex-wrap: wrap; +} +.btn { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.7rem 1.3rem; + border-radius: var(--radius-sm); + font-family: var(--sans); + font-size: 0.95rem; + font-weight: 500; + border: 1px solid var(--border); + color: var(--text); + background: var(--surface); + cursor: pointer; + transition: all .2s ease; +} +.btn:hover { + background: var(--surface-2); + border-color: var(--text-muted); + color: #fff; + text-decoration: none; + transform: translateY(-1px); +} +.btn-primary { + background: var(--grad-brand); + border-color: transparent; + color: #04201a; + font-weight: 600; + box-shadow: 0 6px 20px -6px rgba(16, 185, 129, 0.5); +} +.btn-primary:hover { + filter: brightness(1.1); + color: #04201a; + transform: translateY(-1px); + box-shadow: 0 10px 30px -6px rgba(16, 185, 129, 0.6); +} +.btn-ghost { background: transparent; } +.btn code { background: transparent; border: none; color: inherit; padding: 0; } + +.hero-warn { + margin-top: 1.75rem; + font-size: 0.83rem; + color: var(--text-dim); +} +.hero-warn a { color: var(--text-muted); border-bottom: 1px dotted var(--text-dim); } + +/* ============================================================ + TRUST STRIP + ============================================================ */ +.trust-strip { + padding: 2rem 0; + background: rgba(0, 0, 0, 0.3); + border-top: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); +} +.trust-row { + display: flex; align-items: center; + gap: 1.5rem; flex-wrap: wrap; + justify-content: center; +} +.trust-label { + font-size: 0.78rem; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 0.12em; + font-weight: 500; +} +.trust-items { + list-style: none; margin: 0; padding: 0; + display: flex; flex-wrap: wrap; + gap: 0.5rem 1.5rem; +} +.trust-items li { + font-family: var(--mono); + font-size: 0.83rem; + color: var(--text-soft); + letter-spacing: 0.02em; +} + +/* ============================================================ + SECTIONS (common) + ============================================================ */ +.section { padding: 6rem 0; position: relative; } +.section-head { margin-bottom: 3rem; max-width: 760px; } +.section-head h2 { + font-family: var(--display); + font-size: clamp(1.9rem, 4vw, 2.6rem); + letter-spacing: -0.02em; + line-height: 1.1; + margin: 0.5rem 0 1rem; + color: var(--text); + font-weight: 700; +} +.section-head .lead { + color: var(--text-soft); + font-size: 1.05rem; + margin: 0; + max-width: 680px; +} +.section-tag { + display: inline-block; + font-family: var(--mono); + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.18em; + color: var(--accent-hot); + padding: 0.3rem 0.7rem; + border: 1px solid rgba(16, 185, 129, 0.3); + border-radius: 999px; + margin-bottom: 0.75rem; +} + +/* scroll reveal */ +.reveal { + opacity: 0; + transform: translateY(24px); + transition: opacity .8s ease, transform .8s ease; +} +.reveal.in { + opacity: 1; + transform: translateY(0); +} +@media (prefers-reduced-motion: reduce) { + .reveal { opacity: 1; transform: none; transition: none; } +} + +/* ============================================================ + --EXPLAIN SHOWCASE + ============================================================ */ +.section-feature { + background: + radial-gradient(ellipse at top left, rgba(16, 185, 129, 0.06), transparent 50%), + var(--bg-2); + border-top: 1px solid var(--border-soft); +} +.terminal-shell { + background: #0a0a14; + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; + box-shadow: var(--shadow-hi); + margin: 0 auto 2.5rem; + max-width: 920px; +} +.terminal-bar { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.55rem 0.9rem; + background: rgba(0, 0, 0, 0.5); + border-bottom: 1px solid var(--border); +} +.terminal-body { + margin: 0; + padding: 1.5rem 1.75rem; + color: var(--text); + font-family: var(--mono); + font-size: 0.85rem; + line-height: 1.55; + white-space: pre-wrap; + min-height: 550px; +} +/* color classes that terminal output uses */ +.t-header { color: var(--accent-hot); } +.t-rule { color: var(--border); } +.t-mod { color: #fff; font-weight: 700; } +.t-cve { color: var(--violet); } +.t-summary { color: var(--text-soft); } +.t-label { color: var(--text-dim); } +.t-cwe { color: var(--accent); } +.t-tech { color: var(--accent-2); } +.t-kev-yes { color: var(--danger); font-weight: 700; } +.t-vuln { color: var(--warning); font-weight: 700; } +.t-ok { color: var(--accent); font-weight: 700; } +.t-i { color: var(--text-muted); } +.t-plus { color: var(--accent-hot); } +.t-check { color: var(--accent); } +.t-dot { color: var(--text-dim); } + +.explain-annotations { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.25rem; + max-width: 920px; + margin: 0 auto; +} +.annotation { + display: flex; + gap: 0.85rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.1rem 1.2rem; + transition: border-color .2s ease, transform .2s ease; +} +.annotation:hover { + border-color: var(--accent); + transform: translateY(-2px); +} +.anno-num { + flex-shrink: 0; + width: 28px; height: 28px; + border-radius: 50%; + background: var(--grad-brand); + color: #04201a; + font-weight: 700; + font-family: var(--mono); + display: flex; align-items: center; justify-content: center; + font-size: 0.85rem; +} +.annotation strong { color: var(--text); display: block; margin-bottom: 0.25rem; } +.annotation p { margin: 0; color: var(--text-muted); font-size: 0.9rem; } +@media (max-width: 700px) { + .explain-annotations { grid-template-columns: 1fr; } + .terminal-body { font-size: 0.78rem; padding: 1rem 1.1rem; } +} + +/* ============================================================ + BENTO GRID + ============================================================ */ +.section-bento { + background: + radial-gradient(ellipse at bottom right, rgba(168, 85, 247, 0.05), transparent 60%); +} +.bento { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-auto-rows: minmax(220px, auto); + gap: 1.25rem; +} +.bento-card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.5rem 1.6rem; + position: relative; + overflow: hidden; + transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease; +} +.bento-card::before { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(16, 185, 129, 0.05), transparent 50%); + opacity: 0; + transition: opacity .25s ease; + pointer-events: none; +} +.bento-card:hover { + border-color: var(--accent); + transform: translateY(-3px); + box-shadow: var(--shadow-hi); +} +.bento-card:hover::before { opacity: 1; } + +.bento-lg { grid-column: span 2; } +.bento-icon { + font-size: 1.5rem; + margin-bottom: 0.6rem; + display: inline-block; + width: 38px; height: 38px; + border-radius: var(--radius-sm); + background: var(--surface-2); + display: flex; align-items: center; justify-content: center; +} +.bento-card h3 { + font-family: var(--display); + font-size: 1.2rem; + margin: 0 0 0.5rem; + color: var(--text); + font-weight: 600; +} +.bento-card p { + color: var(--text-muted); + font-size: 0.93rem; + margin: 0 0 0.75rem; +} +.bento-card.bento-kev { border-color: rgba(239, 68, 68, 0.3); } +.bento-card.bento-kev .bento-icon { color: var(--danger); background: rgba(239, 68, 68, 0.1); } +.bento-card.bento-kev:hover { border-color: var(--danger); box-shadow: 0 20px 60px -10px rgba(239, 68, 68, 0.2); } +.bento-card.bento-vfy { border-color: rgba(16, 185, 129, 0.35); } +.bento-card.bento-vfy .bento-icon { color: var(--accent-hot); background: rgba(16, 185, 129, 0.1); font-weight: 800; } +.bento-card.bento-vfy:hover { border-color: var(--accent); box-shadow: 0 20px 60px -10px rgba(16, 185, 129, 0.25); } + +.bento-code { + background: var(--bg-2); + border: 1px solid var(--border-soft); + border-radius: var(--radius-sm); + padding: 0.75rem 0.9rem; + font-size: 0.78rem; + color: var(--text-soft); + margin: 0.75rem 0 0; + white-space: pre; + overflow-x: auto; +} + +.rule-cov { display: flex; flex-direction: column; gap: 0.5rem; } +.rule-row { + display: grid; + grid-template-columns: 60px 1fr 50px; + align-items: center; + gap: 0.6rem; + font-family: var(--mono); + font-size: 0.78rem; +} +.rule-row span:first-child { color: var(--text-muted); } +.rule-row span:last-child { color: var(--text); text-align: right; } +.rule-bar { + height: 6px; + background: var(--bg-2); + border-radius: 3px; + overflow: hidden; + display: block; +} +.rule-bar i { + display: block; + height: 100%; + background: var(--grad-brand); + border-radius: 3px; + transition: width 1.2s cubic-bezier(.4, 0, .2, 1); +} + +@media (max-width: 920px) { + .bento { grid-template-columns: repeat(2, 1fr); } + .bento-lg { grid-column: span 2; } +} +@media (max-width: 620px) { + .bento { grid-template-columns: 1fr; } + .bento-lg { grid-column: span 1; } +} + +/* ============================================================ + MODULE CORPUS PILLS + ============================================================ */ +.corpus-h { + font-family: var(--display); + font-size: 1.15rem; + margin: 2rem 0 0.5rem; + display: flex; + align-items: center; + gap: 0.6rem; + font-weight: 600; + flex-wrap: wrap; +} +.corpus-h-sub { + font-family: var(--sans); + font-weight: 400; + font-size: 0.85rem; + color: var(--text-muted); + margin-left: auto; +} +.corpus-dot { + width: 10px; height: 10px; + border-radius: 50%; + display: inline-block; +} +.corpus-dot.green { background: var(--accent); box-shadow: 0 0 12px var(--accent); } +.corpus-dot.yellow { background: var(--warning); box-shadow: 0 0 12px var(--warning); } + +.pills { + display: flex; flex-wrap: wrap; + gap: 0.45rem; + margin: 0.75rem 0 1.5rem; +} +.pill { + display: inline-flex; + align-items: center; + font-family: var(--mono); + font-size: 0.83rem; + padding: 0.3rem 0.7rem; + border-radius: 999px; + border: 1px solid var(--border); + background: var(--surface); + color: var(--text-soft); + transition: all .15s ease; +} +.pill:hover { + transform: translateY(-1px); + border-color: var(--text-muted); + color: #fff; +} +.pill.green { + border-color: rgba(16, 185, 129, 0.3); + color: var(--accent-hot); + background: rgba(16, 185, 129, 0.05); +} +.pill.green:hover { border-color: var(--accent); } +.pill.yellow { + border-color: rgba(245, 158, 11, 0.3); + color: var(--warning); + background: rgba(245, 158, 11, 0.05); +} +.pill.yellow:hover { border-color: var(--warning); } +.pill.kev { + background: rgba(239, 68, 68, 0.08); + border-color: rgba(239, 68, 68, 0.4); + font-weight: 600; +} +.pill.kev.green { color: var(--accent-hot); } +.pill.kev.yellow { color: var(--warning); } +.pill.kev:hover { border-color: var(--danger); } + +.corpus-foot { + margin-top: 1.5rem; + font-size: 0.88rem; + color: var(--text-muted); +} + +/* ============================================================ + AUDIENCE + ============================================================ */ +.section-audience { + background: + radial-gradient(ellipse at top right, rgba(96, 165, 250, 0.04), transparent 50%); + border-top: 1px solid var(--border-soft); +} +.audience-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.25rem; +} +.audience-card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.5rem 1.6rem; + display: flex; + flex-direction: column; + transition: all .25s ease; +} +.audience-card:hover { + transform: translateY(-3px); + border-color: currentColor; + box-shadow: var(--shadow); +} +.audience-icon { font-size: 1.5rem; margin-bottom: 0.5rem; } +.audience-card h3 { + font-family: var(--display); + font-size: 1.2rem; + margin: 0 0 0.5rem; + color: var(--text); + font-weight: 600; +} +.audience-card p { color: var(--text-muted); font-size: 0.93rem; margin: 0 0 1.25rem; } +.audience-link { + margin-top: auto; + align-self: flex-start; + font-family: var(--mono); + font-size: 0.83rem; + padding: 0.45rem 0.85rem; + border: 1px solid currentColor; + border-radius: var(--radius-sm); +} +.audience-red { color: #f87171; } +.audience-red .audience-link { color: #f87171; } +.audience-blue { color: #60a5fa; } +.audience-blue .audience-link { color: #60a5fa; } +.audience-gray { color: var(--text-muted); } +.audience-gray .audience-link { color: var(--text-muted); } +.audience-purple { color: var(--violet); } +.audience-purple .audience-link { color: var(--violet); } + +@media (max-width: 700px) { .audience-grid { grid-template-columns: 1fr; } } + +/* ============================================================ + HONESTY CALLOUT + ============================================================ */ +.section-callout { + padding: 4rem 0; +} +.callout { + background: + linear-gradient(135deg, rgba(16, 185, 129, 0.07), rgba(6, 182, 212, 0.04)), + var(--surface); + border: 1px solid rgba(16, 185, 129, 0.3); + border-radius: var(--radius-lg); + padding: 2rem 2.25rem; + display: flex; + gap: 1.5rem; + align-items: flex-start; + box-shadow: 0 20px 50px -20px rgba(16, 185, 129, 0.2); +} +.callout-mark { + width: 48px; height: 48px; + border-radius: 50%; + background: var(--grad-brand); + color: #04201a; + font-size: 1.3rem; + font-weight: 800; + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; +} +.callout h3 { + font-family: var(--display); + font-size: 1.3rem; + margin: 0 0 0.5rem; + color: var(--text); + font-weight: 700; +} +.callout p { + color: var(--text-soft); + margin: 0; + font-size: 0.96rem; +} +.callout strong { color: var(--accent-hot); } +@media (max-width: 600px) { + .callout { flex-direction: column; gap: 1rem; padding: 1.5rem; } +} + +/* ============================================================ + QUICKSTART TABS + ============================================================ */ +.tabs { + display: flex; gap: 0.4rem; + margin: 0 0 1rem; + border-bottom: 1px solid var(--border); + flex-wrap: wrap; +} +.tab { + background: transparent; + border: none; + font-family: var(--mono); + font-size: 0.9rem; + color: var(--text-muted); + padding: 0.7rem 1.1rem; + cursor: pointer; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + transition: all .15s ease; +} +.tab:hover { color: var(--text); } +.tab.active { + color: var(--accent-hot); + border-bottom-color: var(--accent); +} +.tab-panel { display: none; } +.tab-panel.active { display: block; } + +pre.code { + background: var(--bg-2); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.1rem 1.3rem; + overflow-x: auto; + font-size: 0.88rem; + line-height: 1.6; + color: var(--text); + margin: 0; +} +pre.code .cmt { color: var(--text-dim); font-style: italic; } +pre.code .prompt { color: var(--accent-hot); user-select: none; } + +/* ============================================================ + TIMELINE / ROADMAP + ============================================================ */ +.section-timeline { + background: + radial-gradient(ellipse at center, rgba(168, 85, 247, 0.03), transparent 60%); + border-top: 1px solid var(--border-soft); +} +.timeline { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.25rem; +} +.tl-col { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.5rem 1.4rem; + position: relative; + overflow: hidden; +} +.tl-col::before { + content: ""; + position: absolute; + top: 0; left: 0; + width: 4px; height: 100%; +} +.tl-shipped::before { background: var(--accent); } +.tl-active::before { background: var(--warning); } +.tl-next::before { background: var(--violet); } +.tl-tag { + display: inline-block; + font-family: var(--mono); + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.14em; + padding: 0.25rem 0.7rem; + border-radius: 999px; + margin-bottom: 1rem; +} +.tl-shipped .tl-tag { background: rgba(16, 185, 129, 0.1); color: var(--accent-hot); } +.tl-active .tl-tag { background: rgba(245, 158, 11, 0.1); color: var(--warning); } +.tl-next .tl-tag { background: rgba(168, 85, 247, 0.1); color: var(--violet); } +.tl-col ul { list-style: none; padding: 0; margin: 0; } +.tl-col li { + padding: 0.5rem 0; + font-size: 0.9rem; + color: var(--text-soft); + border-bottom: 1px solid var(--border-soft); +} +.tl-col li:last-child { border-bottom: none; } +.tl-col li strong { color: var(--text); } +.tl-foot { margin-top: 1.5rem; color: var(--text-muted); font-size: 0.9rem; } + +@media (max-width: 880px) { + .timeline { grid-template-columns: 1fr; } +} + +/* ============================================================ + FOOTER + ============================================================ */ +.footer { + margin-top: 4rem; + padding-top: 3rem; + border-top: 1px solid var(--border-soft); + background: linear-gradient(180deg, transparent 0%, rgba(168, 85, 247, 0.04) 100%); +} +.footer-inner { + display: grid; + grid-template-columns: 1.4fr 1fr 1fr 1fr; + gap: 2rem; + padding-bottom: 3rem; +} +.footer-brand { + font-family: var(--mono); + font-size: 1rem; + font-weight: 700; + letter-spacing: 0.05em; + color: var(--text); + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.75rem; +} +.footer-tag { + color: var(--text-muted); + font-size: 0.9rem; + max-width: 320px; +} +.footer-col h4 { + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.14em; + color: var(--text-dim); + margin: 0.4rem 0 0.9rem; +} +.footer-col ul { list-style: none; padding: 0; margin: 0; } +.footer-col li { margin-bottom: 0.6rem; } +.footer-col a { + color: var(--text-muted); + font-size: 0.93rem; +} +.footer-col a:hover { color: var(--text); } +.footer-bottom { + border-top: 1px solid var(--border-soft); + padding: 2rem 1.5rem; + color: var(--text-dim); + font-size: 0.86rem; +} +.footer-bottom p { margin: 0.5rem 0; } +.footer-meta { color: var(--text-muted); } + +@media (max-width: 800px) { + .footer-inner { grid-template-columns: 1fr 1fr; } +} +@media (max-width: 500px) { + .footer-inner { grid-template-columns: 1fr; } +} + +/* selection highlight */ +::selection { background: rgba(16, 185, 129, 0.3); color: #fff; } + +/* ═══════════════════ OVERWATCH additions ═══════════════════ */ + +.phone { + display: block; max-width: 100%; height: auto; + border-radius: 30px; + border: 1px solid var(--border); + background: #000; + box-shadow: 0 40px 90px -25px rgba(0,0,0,.75), 0 0 0 1px rgba(255,255,255,.03) inset; +} +.phone-hero { display: flex; justify-content: center; margin: 2.6rem 0 0.4rem; } +.phone-hero .phone { width: 300px; } + +.feature-split { + display: grid; grid-template-columns: minmax(0, 300px) 1fr; + gap: 3.2rem; align-items: center; margin-top: 2.6rem; +} +.feature-split .phone-frame { display: flex; justify-content: center; } +.feature-split .phone { width: 285px; } +@media (max-width: 860px) { + .feature-split { grid-template-columns: 1fr; gap: 2.2rem; justify-items: center; } + .feature-split .phone-frame { order: -1; } + .phone-hero .phone, .feature-split .phone { width: 256px; } +} + +/* source-color legend dots (inline in annotation text) */ +.legend-dot { + display: inline-block; width: 9px; height: 9px; border-radius: 50%; + margin: 0 3px 0 6px; vertical-align: middle; +} +.legend-dot.red { background: #ef4444; box-shadow: 0 0 8px #ef4444; } +.legend-dot.blue { background: #3b82f6; box-shadow: 0 0 8px #3b82f6; } +.legend-dot.purple { background: #a855f7; box-shadow: 0 0 8px #a855f7; } + +/* threat tiers */ +.tiers { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-top: 2.2rem; } +@media (max-width: 720px) { .tiers { grid-template-columns: repeat(2, 1fr); } } +.tier { + background: var(--surface); border: 1px solid var(--border); + border-top: 3px solid var(--tier-c, var(--accent)); + border-radius: var(--radius-lg); padding: 1.4rem 1.25rem; +} +.tier-range { font-family: var(--mono); font-size: .82rem; color: var(--text-muted); } +.tier-name { font-family: var(--mono); font-weight: 700; font-size: 1.3rem; letter-spacing: .06em; margin: .1rem 0 .55rem; color: var(--tier-c, var(--accent)); } +.tier p { font-size: .9rem; color: var(--text-soft); margin: 0; line-height: 1.5; } +.tier-green { --tier-c: #22c55e; } +.tier-yellow { --tier-c: #eab308; } +.tier-orange { --tier-c: #f97316; } +.tier-red { --tier-c: #ef4444; } + +.bento-card.bento-cam { border-color: rgba(239, 68, 68, .28); } + +/* download steps: stack the timeline columns inside the split */ +.dl-steps { grid-template-columns: 1fr !important; gap: 1rem; } +.dl-steps .tl-col { margin: 0; }