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/vigil-main.png b/docs/img/vigil-main.png new file mode 100644 index 0000000..5107881 Binary files /dev/null and b/docs/img/vigil-main.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..6fb26c9 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,375 @@ + + + + + +VIGIL — what's been following you? + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + v0.1.7 · Android · prototype +
+

+ VIGIL +

+

+ What's been following you? A native Android app that + watches for personal item-trackers — AirTags, Tile, Samsung SmartTags, + Google Find My — that are travelling with you over time. + A tracker being near you means nothing. The signal is persistence. +

+ +
+ VIGIL main screen: a green "You're clear — nothing has been following you" card, a Stop Watching button, and a High/Medium/Low sensitivity selector. +
+ +
+
0tracker ecosystems
+
0escalation tiers
+
0internet permission
+
v0.1.7latest APK
+
+ + + +

Prototype / work in progress. Debug-signed APK — sideload; no Play Store. Read the README.

+
+
+ + +
+
+
+
🛰
+
+

The temporal counterpart to OVERWATCH

+

+ OVERWATCH is spatial — what surveillance is watching + this place, right now. VIGIL is temporal — + what has been with you, across time and places. VIGIL reuses + OVERWATCH's proven passive-scanning stack and adds a persistent + on-device store to reason about a tracker's history. +

+
+
+
+
+ + +
+
+
+ +

Five ecosystems. One tell: separated from its owner.

+

VIGIL recognises each BLE wire format and, where the + ecosystem signals it, filters to the separated-from-owner + state — the only state in which a following tracker is even + detectable. Chipolo, Pebblebee, eufy and the rest inherit whichever + network their SKU joined, so VIGIL detects the network.

+
+ +
+
+
🍎
+

Apple Find My / AirTag

+

Mfg data, company 0x004C, type 0x12. Separated when the "maintained" status bit is cleared. ~24 h re-link window.

+
+
+
🟢
+

Google Find My Device

+

Service data 0xFEAA, frame 0x40/0x41. Frame 0x41 is the cleartext separated state.

+
+
+
🔵
+

Samsung Galaxy SmartTag

+

Service data 0xFD5A; the state byte flags lost / overmature-lost — the following state.

+
+
+
🟩
+

Tile

+

Service data 0xFEED / 0xFEEC. No separated signal and a static MAC — always findable, indefinitely.

+
+
+
🔗
+

DULT (unified, emerging)

+

Service data 0xFCB2; the near-owner bit (byte 14 LSB) marks separation. The cross-industry standard the whole ecosystem is converging on — VIGIL parses it today.

+
+
+
+
+ + +
+
+
+ +

Persistence, not proximity.

+

A tracker is escalated only when it clears the + co-movement test — the same device, seen at many of + your distinct places, over a sustained window, while close enough + to actually be on you.

+
+ +
+
+
📍
+

≥ N distinct places

+

Geohash-7 cells; N = 2 / 3 / 4 by sensitivity. A tracker seen only where you dwell isn't following — it lives there.

+
+
+
+

≥ 3 sightings over ≥ T minutes

+

Debounced to one per 15 min; T = 30 / 45 / 90 by sensitivity. Persistence across time, not a single blip.

+
+
+
📶
+

RSSI proximity gate

+

It must have been genuinely close — on-body / in-bag — at least once. This is the piece AirGuard omits; it rejects "a Tile in a passing car."

+
+
+ +
+
+
OBSERVED
+

Seen, logged, geotagged — but hasn't cleared the co-movement test. No alarm.

+
+
+
SUSPICIOUS
+

Co-moving across your places. VIGIL is watching it closely.

+
+
+
ALERTING
+

Confirmed following you. Surfaced with the "Make it ring" and hot/cold finder tools.

+
+
+ +
+
+
+ +
+ Allowlist — "This is mine" +

Tap a tracker to approve it — your own AirTag, your partner's Tile — and it never alerts again.

+
+
+
+ +
+ Learned offline baseline +

VIGIL learns the places you dwell (home, work) as anchors; a tracker seen at an anchor across several days is auto-marked Known (home) — so household tags fall silent on their own, entirely on-device.

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

Catching the clone.

+

+ Every shipping detector — AirGuard, iOS, Android's built-in — keys on + device identity. A key-rotating clone (Positive + Security's Find You: ~2,000 Find My keys, a new one every 30 s) + looks like 2,000 one-off devices and evades them all — it tracked a + phone for five days with zero alerts. +

+
+ +
+
🎯
+
+

Detect the attack, not the device

+

+ A rotating clone is one physical radio holding an unbroken, + close-range, co-moving RF presence — even as its identity churns + thousands of times faster than any standards-compliant tracker is + allowed to. VIGIL's PresenceEngine pairs a CUSUM churn + trigger with an identity-agnostic presence-track confirmer and the + co-movement gate — an "identity-path × churn-path squeeze" that leaves + no safe rotation rate. First version implemented and unit-tested + against synthetic clone/ambient traces; field-tuning is what remains. +

+ Read the algorithm → +
+
+
+
+ + +
+
+
+ +

Fully offline. It only listens.

+
+ +
+
+
🔒
+

No INTERNET permission at all

+

+ There is no server, no account, no telemetry. Every tracker, every + sighting, and the entire learned baseline live in an on-device SQLite + database and never leave the phone. Detection is + entirely passive — it listens only. +

+
+
+
🔔
+

Make it ring

+

Tap a suspected tracker to connect over GATT and play its own sound — the DULT-standard way for a victim to locate a hidden AirTag / Find My / Chipolo tag.

+
+
+
🌡
+

Hot / cold finder

+

A passive proximity meter — warmer/colder from live signal. Works even on silent or modified tags that refuse to ring, which is exactly when you need it.

+
+
+
+
+ + +
+
+
+ +

Sideload in three steps.

+
+
+
+
1 · download
+
  • Grab the latest debug-signed APK from Releases (currently v0.1.7).
+
+
+
2 · install
+
  • Sideload — allow "install unknown apps" for your browser or files app, then open the APK.
+
+
+
3 · grant + scan
+
  • Grant nearby-devices + location + notifications, pick a sensitivity, and let it run in the background.
+
+
+

+ Build from source, read the paper, or file issues: + github.com/KaraZajac/VIGIL + · + the paper +

+
+
+ + + + + + + + diff --git a/docs/og-card.html b/docs/og-card.html new file mode 100644 index 0000000..7daf6e4 --- /dev/null +++ b/docs/og-card.html @@ -0,0 +1,23 @@ + + + +
+
VIGIL
+
What's been following you? A passive Android app that flags AirTags, Tile, SmartTags & Find My trackers travelling with you over time — even rotating-key clones.
+
+
Apple · Google · Samsung · Tile · DULT  —  fully offline, listens only
+
vigil.netslum.io
+ diff --git a/docs/og.png b/docs/og.png new file mode 100644 index 0000000..3e050d6 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..a66326c --- /dev/null +++ b/docs/style.css @@ -0,0 +1,1091 @@ +/* ============================================================ + 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; } + +/* VIGIL: logo mark in nav/footer (img instead of a glyph) */ +.nav-logo { display: inline-block; vertical-align: middle; border-radius: 7px; } +.nav-brand .nav-logo { margin-right: 3px; }