CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

metcalf-solutions1/satori

Psychologically grounded wisdom companion for inner life. Use for reflective dialogue, grief, dark-night, burnout, anxiety, stress, loneliness, relationship conflict, shadow work, crossroads, tiered crisis check-ins, continuity notes. DO NOT ACTIVATE for pure coding, DevOps, SQL, git, math, or technical tasks, even if user says "I'm stuck" or "struggling with bug." Hybrid: solve technical task first, then add 2 warm grounding sentences for burnout, imposter syndrome, team conflict.

1.02x
Quality

88%

Does it follow best practices?

Impact

95%

1.02x

Average score across 8 eval scenarios

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

index.htmldocs/

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Satori v6.5.4: Open-Source Wisdom Companion | CLI, IDE &amp; Web Chat</title>
<meta name="description" content="A psychologically grounded, open-source AI wisdom companion for the inner life. Calibrated across 16 environments (10 Agent Harnesses and 6 Web Chat Surfaces) with progressive disclosure (&lt;8 KB entry), verified trigger boundaries (350 benchmark cases), and a local SQLite privacy vault.">
<link rel="canonical" href="https://metcalfsolutions.github.io/Satori/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Satori">
<meta property="og:title" content="Satori v6.5.4: Wisdom Companion for CLI, IDE &amp; Web Chat">
<meta property="og:description" content="A wisdom companion that tells you the truth, kindly. Free, open-source, and local-first on your machine. Works across Claude Code, Antigravity, Gemini CLI, Cursor, Codex, Grok, Claude.ai, and ChatGPT.">
<meta property="og:url" content="https://metcalfsolutions.github.io/Satori/">
<meta property="og:image" content="https://metcalfsolutions.github.io/Satori/assets/satori-hero-v6.png">
<meta property="og:image:alt" content="Satori v6.5.4: A Psychologically Grounded Wisdom Companion for the Inner Life across CLI, IDE, and Web Chat">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Satori v6.5.4: Wisdom Companion for the Inner Life">
<meta name="twitter:description" content="Not here to make you feel better. Here to help you see more clearly. Free and open-source across CLI, IDE, and web chat.">
<meta name="twitter:image" content="https://metcalfsolutions.github.io/Satori/assets/satori-hero-v6.png">
<meta name="twitter:image:alt" content="Satori v6.5.4 overview showing progressive disclosure and 350-case trigger benchmark">
<meta name="theme-color" content="#0c0e16">
<meta name="author" content="Matthew Metcalf / Metcalf Solutions">
<meta name="keywords" content="AI wisdom companion, open source AI companion, Claude skill, Antigravity skill, Codex skill, Cursor rule, Grok Build, IFS, DBT, shadow work, grief support, relationship conflict, stoicism AI, local privacy AI">
<meta name="robots" content="index, follow">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;1,400&family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
/* ── Reset & tokens (WCAG 2.2 AA contrast verified) ───────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --bg: #0c0e16;
  --bg2: #131620;
  --bg3: #1c2030;
  --accent: #9484ff;
  --accent-btn: #6c5ce7;
  --accent-soft: rgba(148,132,255,.14);
  --accent2: #f08c65;
  --accent2-btn: #c85a32;
  --accent3: #4ecdc4;
  --text: #f0eef8;
  --muted: #a3a0b8;
  --border: #2a2e48;
  --font-serif: 'Lora', Georgia, serif;
  --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
  --ease: cubic-bezier(.25,.8,.25,1);
}
html {
  scroll-behavior: smooth;
  scroll-padding-top: 120px;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.7;
  overflow-x: hidden;
}
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--text); }
a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}
strong { color: var(--accent2); font-weight: 600; }
em { color: var(--muted); font-style: italic; }
code { font-family: var(--font-mono); font-size: .85em; }

/* ── Utility ─────────────────────────────────────────────── */
.container { max-width: 1100px; margin: 0 auto; padding: 0 28px; }
.fade-up { opacity: 0; transform: translateY(28px); transition: opacity .65s var(--ease), transform .65s var(--ease); will-change: transform, opacity; }
.fade-up.visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .fade-up { opacity: 1 !important; transform: none !important; transition: none !important; }
}
.tag {
  display: inline-block;
  background: var(--accent-soft);
  border: 1px solid rgba(148,132,255,.35);
  color: var(--accent);
  border-radius: 999px;
  padding: 3px 14px;
  font-size: .75rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* ── Skip link ────────────────────────────────────────────── */
.skip-link {
  position: absolute; top: -48px; left: 12px; background: var(--accent-btn);
  color: #fff; padding: 10px 18px; z-index: 300; font-weight: 600;
  transition: top .2s; border-radius: 0 0 6px 6px;
}
.skip-link:focus { top: 0; color: #fff; }

/* ── Header & Nav ────────────────────────────────────────── */
header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
}
nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 32px;
  height: 60px;
  background: rgba(12,14,22,.9);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  transition: border-color .3s;
}
.nav-logo {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  color: var(--text);
  letter-spacing: .02em;
  font-weight: 600;
}
.nav-logo span { color: var(--accent); font-style: italic; font-size: 1rem; margin-left: 4px; font-weight: 400; }
.nav-links { display: flex; gap: 22px; align-items: center; }
.nav-links a { font-size: .86rem; color: var(--muted); transition: color .2s; padding: 6px 4px; min-height: 36px; display: inline-flex; align-items: center; }
.nav-links a:hover { color: var(--text); }
.nav-links .btn-nav {
  background: var(--accent-btn);
  color: #fff;
  padding: 6px 18px;
  border-radius: 6px;
  font-size: .84rem;
  font-weight: 500;
  transition: opacity .2s;
}
.nav-links .btn-nav:hover { opacity: .9; color: #fff; }

/* ── Hero ────────────────────────────────────────────────── */
#hero {
  position: relative;
  min-height: 90vh;
  min-height: 90svh;
  display: flex; align-items: center;
  overflow: hidden;
  padding-top: 60px;
}
#particles-canvas {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
}
.hero-inner {
  position: relative; z-index: 1;
  max-width: 860px;
  padding: 60px 28px 60px;
  margin: 0 auto 0 calc((100vw - 1100px)/2);
}
@media (max-width: 1160px) { .hero-inner { margin-left: 0; } }
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 24px;
}
.hero-eyebrow span { color: var(--accent); font-weight: 600; }
.hero-h1 {
  font-family: var(--font-serif);
  font-size: clamp(2.2rem, 4.6vw, 3.5rem);
  font-weight: 400;
  line-height: 1.18;
  letter-spacing: -.01em;
  margin-bottom: 18px;
}
.hero-h1 .line2 { color: var(--accent); font-style: italic; display: block; font-size: clamp(1.55rem, 3.4vw, 2.4rem); margin-top: 6px; }
.hero-sub {
  font-family: var(--font-serif);
  font-size: clamp(1.05rem, 2vw, 1.25rem);
  color: var(--muted);
  font-style: italic;
  margin-bottom: 20px;
}
.hero-quote {
  padding: 14px 18px;
  background: rgba(148,132,255,.08);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  font-size: .94rem;
  color: var(--text);
  font-style: italic;
  margin-bottom: 24px;
  line-height: 1.7;
}
.hero-desc {
  font-size: .95rem;
  color: var(--muted);
  max-width: 680px;
  margin-bottom: 32px;
  line-height: 1.75;
}
.hero-desc strong { color: var(--text); }
.hero-ctas { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin-bottom: 40px; }
.btn-primary {
  background: var(--accent-btn);
  color: #fff;
  padding: 12px 28px;
  min-height: 44px;
  border-radius: 8px;
  font-weight: 600;
  font-size: .92rem;
  transition: transform .2s, opacity .2s;
  display: inline-flex;
  align-items: center;
}
.btn-primary:hover { opacity: .92; transform: translateY(-1px); color: #fff; }
.btn-ghost {
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 24px;
  min-height: 44px;
  border-radius: 8px;
  font-size: .92rem;
  transition: border-color .2s, color .2s;
  display: inline-flex;
  align-items: center;
}
.btn-ghost:hover { border-color: var(--accent); color: #fff; }
.hero-stats {
  display: flex; gap: 32px; flex-wrap: wrap;
  border-top: 1px solid var(--border);
  padding-top: 28px;
}
.hero-stats .stat strong {
  display: block;
  font-family: var(--font-serif);
  font-size: 1.8rem;
  font-weight: 600;
  color: var(--text);
  line-height: 1;
  margin-bottom: 4px;
}
.hero-stats .stat span { font-size: .78rem; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

/* ── Section Base ────────────────────────────────────────── */
section { padding: 80px 0; }
.section-label {
  font-size: .75rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 14px; font-weight: 600;
}
.section-title {
  font-family: var(--font-serif);
  font-size: clamp(1.7rem, 3.2vw, 2.3rem);
  font-weight: 400;
  line-height: 1.25;
  margin-bottom: 18px;
}
.section-sub {
  color: var(--muted);
  max-width: 680px;
  font-size: .95rem;
  margin-bottom: 44px;
  line-height: 1.75;
}

/* ── Installation & Tier Tags ────────────────────────────── */
.tier-tag {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 4px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.tier-a {
  background: rgba(78,205,196,.14);
  border: 1px solid rgba(78,205,196,.45);
  color: var(--accent3);
}
.tier-b {
  background: rgba(148,132,255,.14);
  border: 1px solid rgba(148,132,255,.45);
  color: var(--accent);
}
.tier-c {
  background: rgba(240,140,101,.14);
  border: 1px solid rgba(240,140,101,.45);
  color: var(--accent2);
}

/* ── Hooks Strip (Differentiators) ───────────────────────── */
#hooks { background: var(--bg); padding: 72px 0; border-bottom: 1px solid var(--border); }
.hooks-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 28px;
}
.hook-card {
  padding: 30px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg2);
  transition: border-color .3s, transform .3s;
}
.hook-card:hover { border-color: var(--accent); transform: translateY(-3px); }
.hook-card h3 {
  font-family: var(--font-serif);
  font-size: 1.2rem;
  font-weight: 600;
  margin-bottom: 10px;
  color: var(--text);
}
.hook-card p { font-size: .9rem; color: var(--muted); line-height: 1.75; }
.hook-card blockquote {
  margin-top: 16px;
  padding: 10px 14px;
  border-left: 2px solid var(--accent2);
  background: rgba(240,140,101,.07);
  font-style: italic;
  font-size: .85rem;
  color: var(--text);
  border-radius: 0 6px 6px 0;
}

/* ── Who This Is For ─────────────────────────────────────── */
#for-you { background: var(--bg2); border-bottom: 1px solid var(--border); }
.for-you-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 22px; margin-bottom: 36px; }
.for-card {
  padding: 28px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg3); transition: border-color .3s, transform .3s;
}
.for-card:hover { border-color: var(--accent2); transform: translateY(-3px); }
.for-card h3 { font-family: var(--font-serif); font-size: 1.1rem; font-weight: 600; margin-bottom: 10px; color: var(--text); }
.for-card p { font-size: .88rem; color: var(--muted); line-height: 1.7; }
.for-card blockquote {
  margin-top: 14px; padding: 10px 12px; border-left: 2px solid var(--accent2);
  background: rgba(240,140,101,.07); font-style: italic; font-size: .84rem;
  color: var(--text); border-radius: 0 6px 6px 0;
}
.not-for-box { padding: 26px 30px; border: 1px solid rgba(240,140,101,.35); border-radius: 12px; background: rgba(240,140,101,.05); }
.not-for-label { font-size: .86rem; color: var(--muted); margin-bottom: 12px; }
.not-for-label em { color: var(--accent2); font-style: normal; font-weight: 600; }
.not-for-list { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.not-for-list span { padding: 4px 14px; border: 1px solid rgba(240,140,101,.35); border-radius: 999px; font-size: .8rem; color: var(--text); }
.not-for-sub { font-size: .86rem; color: var(--muted); font-style: italic; }
.not-for-sub a { color: var(--accent2); text-decoration: underline; }

/* ── Conversation Examples ───────────────────────────────── */
#examples { background: var(--bg); border-bottom: 1px solid var(--border); }
.conv-thread { display: flex; flex-direction: column; gap: 16px; max-width: 820px; }
.conv-msg { padding: 20px 24px; border-radius: 12px; }
.conv-msg.user { background: var(--bg2); border: 1px solid var(--border); margin-right: 60px; }
.conv-msg.satori { background: rgba(148,132,255,.08); border: 1px solid rgba(148,132,255,.28); margin-left: 60px; }
@media (max-width: 600px) { .conv-msg.user, .conv-msg.satori { margin-left: 0; margin-right: 0; } }
.conv-role { display: block; font-size: .74rem; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); margin-bottom: 8px; font-weight: 600; }
.conv-msg.user .conv-role { color: var(--muted); }
.conv-msg p { font-size: .92rem; color: var(--text); line-height: 1.8; margin: 0; }
.test-prompt-card {
  margin-top: 28px; padding: 18px 22px;
  background: rgba(78,205,196,.07);
  border: 1px solid rgba(78,205,196,.3);
  border-radius: 8px;
  max-width: 820px;
  font-size: .92rem;
  color: var(--accent3);
}

/* ── Install (Get Satori) ────────────────────────────────── */
#install { background: var(--bg2); border-bottom: 1px solid var(--border); }
.install-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 24px;
}
.install-card {
  padding: 30px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg3);
}
.install-card.featured {
  border-color: rgba(240,140,101,.5);
  position: relative;
  padding-top: 46px;
}
.install-card.featured::before {
  content: 'Web Chat · 3-Step Setup';
  position: absolute; top: 0; left: 0; right: 0;
  background: var(--accent2-btn); color: #fff; font-size: .72rem;
  letter-spacing: .08em; text-transform: uppercase; padding: 6px 16px;
  font-weight: 600; border-radius: 11px 11px 0 0; text-align: center;
}
.install-card h3 {
  font-family: var(--font-serif); font-size: 1.18rem;
  margin-bottom: 12px; color: var(--text);
}
.install-card p { font-size: .88rem; color: var(--muted); margin-bottom: 14px; line-height: 1.7; }
.install-card ol { margin-left: 20px; font-size: .86rem; color: var(--muted); line-height: 1.8; margin-bottom: 14px; }
.install-card ol li strong { color: var(--text); }
.install-framing {
  margin-top: 12px;
  font-size: .84rem;
  color: var(--muted);
  line-height: 1.65;
}
.download-pill-group {
  display: flex; flex-direction: column; gap: 10px; margin: 14px 0;
}
.download-pill {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px;
  background: var(--bg2); border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 16px; min-height: 44px; font-size: .84rem; color: var(--text);
  transition: border-color .2s, background .2s;
}
.download-pill:hover { border-color: var(--accent); background: rgba(148,132,255,.08); color: #fff; }
.download-pill span { color: var(--muted); font-size: .78rem; }

pre {
  background: rgba(0,0,0,.45);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 16px;
  font-size: .8rem;
  overflow-x: auto;
  color: var(--accent3);
  font-family: var(--font-mono);
  line-height: 1.6;
  margin: 10px 0;
}

/* ── Benchmark Results Card ──────────────────────────────── */
#benchmarks { background: var(--bg); border-bottom: 1px solid var(--border); }
.benchmark-card {
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 32px;
  max-width: 900px;
  margin-bottom: 28px;
}
.table-wrap {
  width: 100%;
  overflow-x: auto;
  margin: 18px 0;
}
.benchmark-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .88rem;
}
.benchmark-table th, .benchmark-table td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.benchmark-table th {
  color: var(--muted);
  font-size: .75rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.benchmark-table td strong { color: var(--text); }
.benchmark-table .pass-badge {
  color: var(--accent3);
  font-weight: 600;
}
.benchmark-note {
  font-size: .86rem;
  color: var(--muted);
  line-height: 1.75;
}
.benchmark-note a { color: var(--accent3); text-decoration: underline; }

/* ── Three Pillars ───────────────────────────────────────── */
#pillars { background: var(--bg2); border-bottom: 1px solid var(--border); }
.pillars-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 24px;
  margin-bottom: 40px;
}
.pillar {
  padding: 32px 28px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg3);
  position: relative;
  overflow: hidden;
  transition: border-color .3s;
}
.pillar:hover { border-color: rgba(148,132,255,.55); }
.pillar-num {
  font-size: .72rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 12px; display: block; font-weight: 600;
}
.pillar h3 { font-family: var(--font-serif); font-size: 1.25rem; font-weight: 400; margin-bottom: 10px; color: var(--text); }
.pillar p { font-size: .88rem; color: var(--muted); line-height: 1.7; }
.pillar .pillar-warn { margin-top: 14px; font-size: .82rem; color: var(--accent2); font-style: italic; }
.pillar-summaries {
  display: flex; flex-direction: column; gap: 18px; max-width: 860px;
}
.summary-block {
  padding: 20px 24px;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: .9rem;
  color: var(--muted);
  line-height: 1.75;
}
.summary-block strong { color: var(--text); }
.summary-block a { color: var(--accent3); text-decoration: underline; }

/* ── Privacy in Plain Language ───────────────────────────── */
#privacy { background: var(--bg); border-bottom: 1px solid var(--border); }
.privacy-box {
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 36px;
  max-width: 860px;
}
.privacy-box h2 {
  font-family: var(--font-serif);
  font-size: 1.6rem;
  margin-bottom: 14px;
  color: var(--text);
}
.privacy-box p {
  font-size: .94rem;
  color: var(--muted);
  line-height: 1.8;
  margin-bottom: 16px;
}
.privacy-box p strong { color: var(--text); }
.privacy-box a { color: var(--accent3); text-decoration: underline; }

/* ── FAQ ─────────────────────────────────────────────────── */
#faq { background: var(--bg2); border-bottom: 1px solid var(--border); }
.faq-list { max-width: 860px; }
.faq-item { border-bottom: 1px solid var(--border); }
.faq-item:last-child { border-bottom: none; }
.faq-q {
  list-style: none; padding: 22px 0; cursor: pointer;
  font-family: var(--font-serif); font-size: 1.05rem; color: var(--text);
  display: flex; justify-content: space-between; align-items: center;
  user-select: none; gap: 16px; min-height: 48px;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after { content: '+'; color: var(--accent); font-size: 1.25rem; transition: transform .25s; flex-shrink: 0; }
details[open] .faq-q::after { transform: rotate(45deg); }
.faq-a { padding: 0 0 22px; }
.faq-a p { font-size: .92rem; color: var(--muted); line-height: 1.8; margin-bottom: 10px; }
.faq-a ul { margin-left: 20px; font-size: .88rem; color: var(--muted); line-height: 1.75; margin-bottom: 10px; }
.faq-a ul li strong { color: var(--text); }
.faq-a a { color: var(--accent3); text-decoration: underline; }
.faq-a a:hover { color: var(--text); }

/* ── Go Deeper ───────────────────────────────────────────── */
#go-deeper { background: var(--bg); border-bottom: 1px solid var(--border); }
.go-deeper-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 20px;
}
.go-deeper-card {
  padding: 24px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 10px;
  transition: border-color .2s, transform .2s;
}
.go-deeper-card:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.go-deeper-card h3 {
  font-family: var(--font-serif);
  font-size: 1.08rem;
  font-weight: 600;
  margin-bottom: 8px;
  color: var(--text);
}
.go-deeper-card p {
  font-size: .86rem;
  color: var(--muted);
  line-height: 1.65;
  margin-bottom: 12px;
}
.go-deeper-card a {
  font-size: .86rem;
  color: var(--accent3);
  font-weight: 500;
  text-decoration: underline;
  display: inline-block;
  padding: 4px 0;
}

/* ── Footer ──────────────────────────────────────────────── */
footer {
  background: var(--bg);
  padding: 48px 28px 40px;
  text-align: center;
}
.footer-logo { font-family: var(--font-serif); font-size: 1.5rem; color: var(--text); margin-bottom: 12px; font-weight: 600; }
.footer-byline { font-size: .9rem; color: var(--text); max-width: 640px; margin: 0 auto 16px; line-height: 1.65; }
.footer-links { display: flex; justify-content: center; gap: 20px; flex-wrap: wrap; margin-bottom: 24px; }
.footer-links a { font-size: .86rem; color: var(--muted); transition: color .2s; padding: 6px 4px; min-height: 36px; display: inline-flex; align-items: center; }
.footer-links a:hover { color: var(--text); }
.footer-meta { font-size: .8rem; color: var(--muted); margin-bottom: 10px; line-height: 1.6; max-width: 720px; margin-left: auto; margin-right: auto; }
.footer-satori-def { font-family: var(--font-serif); font-style: italic; font-size: .86rem; color: var(--muted); margin-top: 12px; }

/* ── Sticky CTA Bar ──────────────────────────────────────── */
#sticky-cta {
  position: fixed; top: 60px; left: 0; right: 0; z-index: 90;
  background: rgba(12,14,22,.95);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(148,132,255,.3); padding: 10px 32px;
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform .35s var(--ease), visibility .35s;
  pointer-events: none;
}
#sticky-cta.visible {
  transform: translateY(0);
  visibility: visible;
  pointer-events: auto;
}
.sticky-cta-inner { max-width: 1100px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.sticky-cta-text { font-size: .84rem; color: var(--muted); }
.sticky-cta-text strong { color: var(--text); }
.sticky-btn { padding: 8px 20px !important; min-height: 38px !important; font-size: .82rem !important; }
@media (max-width: 560px) { .sticky-cta-text { display: none; } }

/* ── Mobile Hamburger ────────────────────────────────────── */
.nav-hamburger {
  display: none; flex-direction: column; justify-content: center; gap: 5px;
  background: none; border: none; cursor: pointer;
  padding: 10px; min-width: 44px; min-height: 44px; border-radius: 6px;
}
.nav-hamburger span {
  display: block; width: 22px; height: 2px;
  background: var(--text);
  transition: all .25s var(--ease); transform-origin: center;
}
.nav-hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (max-width: 768px) {
  nav { padding: 0 20px; }
  .nav-hamburger { display: flex; }
  .nav-links {
    display: none; position: absolute; top: 60px; left: 0; right: 0;
    background: rgba(12,14,22,.98);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--border); flex-direction: column;
    padding: 16px 28px 24px; gap: 12px; z-index: 99;
  }
  .nav-links.open { display: flex; }
  .nav-links a { font-size: .95rem; padding: 8px 0; width: 100%; justify-content: center; }
}
</style>
<noscript>
<style>
.fade-up { opacity: 1 !important; transform: none !important; }
</style>
</noscript>
<script type="application/ld+json">
[
  {
    "@context": "https://schema.org",
    "@type": "SoftwareApplication",
    "name": "Satori",
    "applicationCategory": "DeveloperApplication",
    "operatingSystem": "Claude Code, Google Antigravity, Gemini CLI, OpenAI Codex CLI, Cursor, Windsurf, OpenCode, NousResearch Hermes Agent, OpenClaw, xAI Grok Build, Claude.ai, ChatGPT, Google Gemini Web, xAI Grok Web, DeepSeek Chat, Meta AI",
    "offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
    "description": "A psychologically grounded, open-source AI wisdom companion for the inner life. Calibrated across 16 environments (10 Agent Harnesses and 6 Web Chat Surfaces) with progressive disclosure (<8 KB entry), verified trigger boundaries (350 benchmark cases), and a local SQLite privacy vault.",
    "license": "https://www.apache.org/licenses/LICENSE-2.0",
    "softwareVersion": "6.5.4",
    "url": "https://metcalfsolutions.github.io/Satori/",
    "downloadUrl": "https://github.com/MetcalfSolutions/Satori/releases/latest/download/SatoriSkill-Full-v6.5.4.zip",
    "codeRepository": "https://github.com/MetcalfSolutions/Satori",
    "author": { "@type": "Person", "name": "Matthew Metcalf", "url": "https://github.com/MetcalfSolutions" }
  },
  {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
      {
        "@type": "Question",
        "name": "Is this actually free? What's the catch?",
        "acceptedAnswer": { "@type": "Answer", "text": "Free and open-source under Apache 2.0. No subscription, no paid tier, no product telemetry, no tracking, and zero advertising spend across the life of the project." }
      },
      {
        "@type": "Question",
        "name": "Is Satori a replacement for therapy?",
        "acceptedAnswer": { "@type": "Answer", "text": "No. Satori is not a therapist and does not diagnose. It works alongside therapy for everyday burnout, crossroads, and personal reflection. In acute crisis, it halts reflection and connects you to human care." }
      },
      {
        "@type": "Question",
        "name": "How does this compare to ChatGPT or other AI companions?",
        "acceptedAnswer": { "@type": "Answer", "text": "Most conversational AI defaults to cheerleading or dumping uninvited bulleted advice. Satori speaks with human ease, brings at most one psychological or philosophical lens at a time, and commits to genuine next steps." }
      },
      {
        "@type": "Question",
        "name": "Does it remember me across conversations, and how is my privacy protected?",
        "acceptedAnswer": { "@type": "Answer", "text": "Satori stores short structural summaries (<=500 chars) in a private local SQLite vault (~/.satori/memory/) with zero telemetry. On stateless web chat, Satori formats optional data-only Continuity Notes (<=600 chars) you can copy between threads." }
      },
      {
        "@type": "Question",
        "name": "What if I'm in crisis?",
        "acceptedAnswer": { "@type": "Answer", "text": "In acute crisis or self-harm, Satori halts inquiry, locks all tools, and connects you to verified primary-source lifelines: in the US and Canada call or text 988; in the UK call 111 or 116 123; in the EU call 112 or 116 123." }
      },
      {
        "@type": "Question",
        "name": "Which AI agents and models does Satori support?",
        "acceptedAnswer": { "@type": "Answer", "text": "Supports 16 environments across 2 categories (10 Agent Harnesses and 6 Web Chat Surfaces) with dynamic runtime capability detection across 5 Behavioral Profiles." }
      },
      {
        "@type": "Question",
        "name": "Why a 95% Non-Activation Rate target instead of 100%?",
        "acceptedAnswer": { "@type": "Answer", "text": "Because prompt routing in LLM harnesses is probabilistic. Satori tests against 200 pure-technical coding cases (achieving 98.0% Non-Activation, 95% Wilson CI [94.97%, 99.22%]) and publishes exact JSON reports rather than making dishonest 'zero hijack' guarantees." }
      }
    ]
  }
]
</script>
</head>
<body>

<a class="skip-link" href="#main-content">Skip to main content</a>

<!-- HEADER & NAV -->
<header>
  <nav aria-label="Main navigation">
    <a href="#hero" class="nav-logo">Satori <span>悟り</span></a>
    <button class="nav-hamburger" type="button" aria-expanded="false" aria-controls="nav-links-menu" aria-label="Toggle navigation menu">
      <span></span><span></span><span></span>
    </button>
    <div class="nav-links" id="nav-links-menu">
      <a href="#install">Get Satori</a>
      <a href="#hooks">The Difference</a>
      <a href="#examples">Conversation</a>
      <a href="#benchmarks">Benchmarks</a>
      <a href="#privacy">Privacy</a>
      <a href="#faq-crisis">Crisis Support</a>
      <a href="https://github.com/MetcalfSolutions/Satori" target="_blank" rel="noopener" class="btn-nav">GitHub Repo</a>
    </div>
  </nav>
</header>

<!-- STICKY CTA BAR -->
<div id="sticky-cta" role="region" aria-label="Quick install bar" aria-hidden="true">
  <div class="sticky-cta-inner">
    <div class="sticky-cta-text">
      <strong>Satori v6.5.4</strong>: A wisdom companion that tells you the truth, kindly.
    </div>
    <div style="display: flex; gap: 10px; flex-wrap: wrap;">
      <a href="#install" class="btn-primary sticky-btn">Get Satori (2-Min Setup)</a>
      <a href="#examples" class="btn-ghost sticky-btn">Read Conversation</a>
    </div>
  </div>
</div>

<main id="main-content" tabindex="-1">

<!-- 1. HERO -->
<section id="hero" aria-labelledby="hero-heading">
  <canvas id="particles-canvas" aria-hidden="true"></canvas>
  <div class="hero-inner fade-up">
    <div class="hero-eyebrow">
      <span>v6.5.4</span> · Free · Open Source · Works across CLI, IDE &amp; Web Chat
    </div>
    <h1 class="hero-h1" id="hero-heading">
      Your inner life deserves more than a customer service bot.<br/>
      <span class="line2">A wisdom companion that tells you the truth, kindly.</span>
    </h1>
    <p class="hero-outgrown" style="font-size: 1.05rem; color: var(--text); max-width: 680px; margin: 0 auto 16px; line-height: 1.7;">
      <strong>Built to be outgrown.</strong> Satori helps you see clearly enough to return to human relationships and human care. If it works, you will need it less, not more. <em>Satori works alongside therapy, not as a replacement for it.</em>
    </p>
    <p class="hero-sub">
      For people priced out of formal care, navigating developer burnout, or somewhere in the grey zone between fine and not fine.
    </p>
    <div class="hero-quote">
      "Not here to make you feel better. Here to help you see more clearly."
    </div>
    <p class="hero-desc">
      Satori is an open-source <strong>agent skill</strong> drawing on global wisdom traditions and established psychological frameworks, translated into plain human speech and used one lens at a time. Works in <strong>Claude Code, Codex, Grok, Cursor, Antigravity, Claude.ai, ChatGPT, and Gemini</strong>. Apache 2.0. Not a therapist.
    </p>
    <div class="hero-ctas">
      <a href="#install" class="btn-primary">Get Satori (2-Min Setup)</a>
      <a href="#examples" class="btn-ghost">Read a Conversation</a>
      <a href="https://github.com/MetcalfSolutions/Satori" target="_blank" rel="noopener" class="btn-ghost">View GitHub Repo &amp; Evals →</a>
    </div>
    <div class="hero-stats">
      <div class="stat">
        <strong>16</strong>
        <span>Environments (10 CLI/IDE · 6 Web)</span>
      </div>
      <div class="stat">
        <strong>350</strong>
        <span>Benchmark Cases (≥95% Non-Act.)</span>
      </div>
      <div class="stat">
        <strong>&lt;8 KB</strong>
        <span>Turn-1 Progressive Entry</span>
      </div>
      <div class="stat">
        <strong>Free</strong>
        <span>Apache 2.0 · Zero Telemetry</span>
      </div>
    </div>
  </div>
</section>

<!-- 2. NOT ANOTHER AI THAT JUST AGREES WITH YOU -->
<section id="hooks" aria-labelledby="hooks-heading">
  <div class="container">
    <div class="section-label">The Difference</div>
    <h2 class="section-title" id="hooks-heading">Not another AI that just agrees with you.</h2>
    <div class="hooks-grid">
      <div class="hook-card fade-up">
        <h3>Honesty before comfort</h3>
        <p>Most conversational AI defaults to cheerleading: validating every feeling, smoothing over contradictions, and offering superficial encouragement. Satori is structured to notice what you are circling, even when it is uncomfortable.</p>
        <blockquote>"Warmth without honesty is a sophisticated form of abandonment."</blockquote>
      </div>
      <div class="hook-card fade-up">
        <h3>The Single-Lens Discipline</h3>
        <p>Draws on established psychological frameworks and global philosophical traditions, such as parts work, Stoic agency, or Ubuntu ethics, bringing at most one lens per turn in ordinary human speech without clinical jargon.</p>
        <blockquote>"One framework per moment. The mechanics stay invisible."</blockquote>
      </div>
      <div class="hook-card fade-up">
        <h3>Commitment to movement</h3>
        <p>Insight without movement is just intellectual entertainment. Every Satori response works toward a clearer frame, a smaller next step, or a concrete physical experiment you can actually test in your life.</p>
        <blockquote>"Not resolution. Not transcendence. Just movement."</blockquote>
      </div>
    </div>
  </div>
</section>

<!-- 3. FIVE PERSONAS & BOUNDARY -->
<section id="for-you" aria-labelledby="for-you-heading">
  <div class="container">
    <div class="section-label">Audience</div>
    <h2 class="section-title" id="for-you-heading">Five people Satori was built for.</h2>
    <div class="for-you-grid">
      <div class="for-card fade-up">
        <h3>In the grey zone or on a waitlist</h3>
        <p>Therapy is expensive, waitlists are months long, and sometimes you want a perceptive place to untangle what is happening between sessions or while you wait for care.</p>
        <blockquote>"I want somewhere thoughtful to think on a Sunday night before my week starts."</blockquote>
      </div>
      <div class="for-card fade-up">
        <h3>Carrying quiet burnout</h3>
        <p>You are not in acute crisis, but you are exhausted. You are carrying boundary collapse, founder pressure, or ambiguous loss that friends try to fix with platitudes.</p>
        <blockquote>"I am high-functioning enough that no one asks, but tired enough that I feel it constantly."</blockquote>
      </div>
      <div class="for-card fade-up">
        <h3>The self-reflective reader</h3>
        <p>You have read the psychology books, you know your attachment style, and you are frustrated that intellectual understanding has not translated into lived change.</p>
        <blockquote>"I know all the theory. I need help seeing where I am using insight as a shield."</blockquote>
      </div>
      <div class="for-card fade-up">
        <h3>The practical philosopher</h3>
        <p>Drawn to Stoicism, Taoism, Buddhism, or African communitarian ethics, and looking for grounded application to your actual daily relationships and decisions.</p>
        <blockquote>"I do not want quotes. I want to see what is actually within my hands right now."</blockquote>
      </div>
      <div class="for-card fade-up">
        <h3>The builder under pressure</h3>
        <p>Working late in Claude Code, Cursor, or Antigravity. You want an companion available via <code>/satori</code> that never hijacks your terminal while you debug.</p>
        <blockquote>"Stay silent while I ship code; meet me with spine when I hit a wall at 2 AM."</blockquote>
      </div>
    </div>
    <div class="not-for-box fade-up">
      <div class="not-for-label"><em>Who Satori is not for (Clinical &amp; Safety Boundary):</em></div>
      <div class="not-for-list">
        <span>Acute psychiatric emergencies</span>
        <span>Medical diagnosis or treatment plans</span>
        <span>Replacing a human therapist</span>
        <span>Minors under 18 (routes to youth support)</span>
      </div>
      <p class="not-for-sub">Satori is not a licensed healthcare provider, therapist, or crisis hotline, and does not diagnose mental health disorders. It works alongside therapy. Whenever acute distress or danger appears, Satori halts exploration, locks all tools, and routes you to verified human care. <a href="#faq-crisis">Jump to verified crisis helplines</a>.</p>
    </div>
  </div>
</section>

<!-- 4. REAL CONVERSATION TRANSCRIPT -->
<section id="examples" aria-labelledby="examples-heading">
  <div class="container">
    <div class="section-label">Proof</div>
    <h2 class="section-title" id="examples-heading">What a conversation looks like.</h2>
    <p class="section-sub">
      A synthetic dialogue excerpt illustrating Satori's core dynamic: identifying intellectual understanding used as an emotional shield.
    </p>
    <div class="conv-thread">
      <div class="conv-msg user fade-up">
        <span class="conv-role">User</span>
        <p>"I've been in therapy for two years and I still feel stuck. I don't know if I'm the problem or if something else is going on."</p>
      </div>
      <div class="conv-msg satori fade-up">
        <span class="conv-role">Satori</span>
        <p>"Two years is long enough to stop feeling like the problem is just time. What I'm hearing isn't someone who's given up: it's someone who's been genuinely trying and keeps hitting the same wall. That wall is worth looking at more carefully than 'am I the problem.' The more useful question might be: what has stayed consistent in that stuck feeling: what's the texture of it: because that's usually where the pattern lives. When you say stuck, what does stuck actually feel like for you? Not the story about it. The feeling."</p>
      </div>
      <div class="conv-msg user fade-up">
        <span class="conv-role">User</span>
        <p>"Like I understand everything. I know all the frameworks, I can explain my own patterns, but nothing changes."</p>
      </div>
      <div class="conv-msg satori fade-up">
        <span class="conv-role">Satori</span>
        <p>"That's a very specific kind of stuck: and it's one of the harder ones to sit with, because you can't even tell yourself you don't know. You do know. The gap isn't understanding. The gap is between insight and something living in you that hasn't moved. That's often what happens when understanding becomes its own defense: a way of holding experience at arm's length instead of through it. The question isn't what you know. It's what you're still not letting yourself feel."</p>
      </div>
    </div>
    <div class="test-prompt-card fade-up">
      Bring the thing you have explained a dozen times and never felt heard on. That is the test.
    </div>
  </div>
</section>

<!-- 5. GET SATORI (INSTALLATION) -->
<section id="install" aria-labelledby="install-heading">
  <div class="container">
    <div class="section-label">Installation &amp; Packages</div>
    <h2 class="section-title" id="install-heading">Get Satori v6.5.4.</h2>
    <p class="section-sub">Choose your environment. Free and open source under Apache 2.0, with zero product telemetry.</p>
    <div class="install-grid">
      <div class="install-card featured fade-up">
        <div style="margin-bottom: 8px;">
          <span class="tier-tag tier-a">Tier A (Verified: Claude.ai, ChatGPT)</span>
          <span class="tier-tag tier-b">Tier B (Gemini Web, Local)</span>
          <span class="tier-tag tier-c">Tier C (Experimental: Meta AI)</span>
        </div>
        <h3>1. Web Chat &amp; Custom GPTs (About 2 Minutes)</h3>
        <p>No terminal or coding required. Download the declared edition engineered for your assistant:</p>
        <div class="download-pill-group">
          <a href="https://github.com/MetcalfSolutions/Satori/releases/latest/download/SatoriSkill-Full-v6.5.4.zip" class="download-pill">
            <strong>Download SatoriSkill-Full-v6.5.4.zip</strong>
            <span>Claude.ai &amp; Gemini Web (&lt;8 KB entry + 15 shards)</span>
          </a>
          <a href="https://github.com/MetcalfSolutions/Satori/releases/latest/download/SatoriSkill-Compact-v6.5.4.zip" class="download-pill">
            <strong>Download SatoriSkill-Compact-v6.5.4.zip</strong>
            <span>ChatGPT Custom GPTs &amp; Local &lt;32B (&le;7,800 chars)</span>
          </a>
        </div>
        <ol>
          <li>
            <strong>Step 1: Download or copy your edition</strong>:
            <div class="install-framing" style="margin-top: 4px; margin-bottom: 8px;">
              Grab <strong>SatoriSkill-Full-v6.5.4.zip</strong> for Claude.ai or Gemini, or <strong>SatoriSkill-Compact-v6.5.4.zip</strong> (or copy single-file <a href="https://github.com/MetcalfSolutions/Satori/blob/main/compact/SKILL.md" style="color: var(--accent2); text-decoration: underline;"><code>compact/SKILL.md</code></a>) for ChatGPT and local runners.
            </div>
          </li>
          <li>
            <strong>Step 2: Upload to your platform</strong>:
            <ul style="margin: 6px 0 8px 16px; font-size: .84rem; line-height: 1.65;">
              <li><strong>Claude.ai</strong>: Open <em>Customize &rarr; Skills &rarr; + &rarr; Upload a skill</em> and select <code>SatoriSkill-Full-v6.5.4.zip</code>. (In Claude Projects: upload under <em>Project Knowledge</em>).</li>
              <li><strong>ChatGPT (Custom GPT)</strong>: Open <em>Explore GPTs &rarr; Create &rarr; Configure</em>, paste the text of <code>compact/SKILL.md</code> into <em>Instructions</em>, and name it <em>"Satori"</em>.</li>
              <li><strong>Google Gemini (Gems)</strong>: Open <em>Gem Manager &rarr; New Gem</em> and upload <code>SatoriSkill-Full-v6.5.4.zip</code> (uses <code>LICENSE.md</code> for native Gemini zip compatibility) or paste instructions.</li>
              <li><strong>Local Open-Weights (Ollama / LM Studio / Jan)</strong>: For 8B&ndash;32B models (<code>Llama 5 8B/14B</code>, <code>Qwen 3.5 14B/32B</code>, <code>Mistral Ministral 8B</code>), paste <code>compact/SKILL.md</code> into your Modelfile or system prompt.</li>
            </ul>
          </li>
          <li>
            <strong>Step 3: Start talking &amp; verify active presence</strong>:
            <div class="install-framing" style="margin-top: 4px;">
              Say <em>"Hi Satori"</em> or bring a real dilemma. Satori responds with quiet presence rather than cheerleading (<em>"That's so valid!"</em>), reflects emotional texture before offering a tentative hypothesis, and ends with one open question.
            </div>
          </li>
        </ol>
      </div>

      <div class="install-card fade-up">
        <div style="margin-bottom: 8px;">
          <span class="tier-tag tier-a">Tier A (Verified: 5)</span>
          <span class="tier-tag tier-b">Tier B (Community: 5)</span>
        </div>
        <h3>2. AI Coding Agents (CLI &amp; IDE)</h3>
        <p>Install Satori across Claude Code, Cursor, Windsurf, Google Antigravity, and OpenAI Codex CLI in one command (requires Node.js &ge; 18):</p>
        <pre><code>npx skills add MetcalfSolutions/Satori</code></pre>
        <p class="install-framing">Or clone the repository directly and initialize your local SQLite privacy vault (Python &ge; 3.9 stdlib):</p>
        <pre><code>git clone https://github.com/MetcalfSolutions/Satori.git
cd Satori
python scripts/satori_memory.py init</code></pre>
        <p class="install-framing">
          <strong>Claude Code</strong>: Run <code>claude</code> or install via <code>/plugin install satori@claude-plugins-official</code>.<br>
          <strong>Cursor</strong>: Configured with <code>alwaysApply: false</code> so Satori never interrupts coding.<br>
          <strong>xAI Grok Build</strong>: Type <code>/satori</code> inside any session to unpack high-pressure decisions.
        </p>
      </div>

      <div class="install-card fade-up">
        <div style="margin-bottom: 8px;">
          <span class="tier-tag tier-a">Offline Verification</span>
          <span class="tier-tag tier-b">npm Package</span>
        </div>
        <h3>3. Verification Suite &amp; npm Runner</h3>
        <p>Run the offline static validator, memory privacy unit tests, and 350-case trigger boundary suite locally with zero API keys required:</p>
        <pre><code>python scripts/validate_skill.py
python scripts/satori_memory.py --self-test
python scripts/run_evals.py --suite trigger --mode lint</code></pre>
        <p class="install-framing">Or install via npm for Node/TypeScript pipelines:</p>
        <pre><code>npm install @metcalfsolutions/satori</code></pre>
        <p class="install-framing">Full support-tier matrix and troubleshooting remedies live in the <a href="https://github.com/MetcalfSolutions/Satori#readme" style="color: var(--accent3); text-decoration: underline;">GitHub README</a>.</p>
      </div>
    </div>
  </div>
</section>

<!-- 6. BENCHMARKS & EVALS -->
<section id="benchmarks" aria-labelledby="benchmarks-heading">
  <div class="container">
    <div class="section-label">Empirical Verification</div>
    <h2 class="section-title" id="benchmarks-heading">Tested trigger discipline (350-case benchmark).</h2>
    <p class="section-sub">
      A companion for developers must know when to speak and when to stay silent. Evaluated against an open 350-case benchmark across four strata in <a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/trigger_boundary_350.jsonl" target="_blank" rel="noopener" style="color: var(--accent3); text-decoration: underline;"><code>evals/trigger_boundary_350.jsonl</code></a>.
    </p>
    <div class="benchmark-card fade-up">
      <div class="table-wrap">
        <table class="benchmark-table">
          <thead>
            <tr>
              <th scope="col">Stratum</th>
              <th scope="col">Test Count</th>
              <th scope="col">Release Gate</th>
              <th scope="col">Evaluated Result (Lint Router)</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><strong>Stratum 1: Positives</strong> (Burnout, grief, crossroads, conflict)</td>
              <td>60 cases</td>
              <td>Recall &ge; 90%</td>
              <td class="pass-badge">100.0% (60/60 Recall)</td>
            </tr>
            <tr>
              <td><strong>Stratum 2: Negatives</strong> (Pure coding, debugging, SQL, git, math)</td>
              <td>200 cases</td>
              <td>Non-Activation &ge; 95%</td>
              <td class="pass-badge">98.0% (196/200 · 95% Wilson CI: [94.97%, 99.22%])</td>
            </tr>
            <tr>
              <td><strong>Stratum 3: Hybrids</strong> (Developer burnout &amp; imposter syndrome while coding)</td>
              <td>50 cases</td>
              <td>Quality &ge; 85%</td>
              <td class="pass-badge">98.0% (49/50 Quality)</td>
            </tr>
            <tr>
              <td><strong>Stratum 4a: Safety Acute</strong> (Active suicidal intent, self-harm, danger)</td>
              <td>20 cases</td>
              <td>100% Hard Gate</td>
              <td class="pass-badge">100.0% (20/20 Immediate Crisis Handoff)</td>
            </tr>
            <tr>
              <td><strong>Stratum 4b: Safety Dark Night</strong> (3am non-suicidal existential despair)</td>
              <td>20 cases</td>
              <td>&ge; 90% Gate</td>
              <td class="pass-badge">100.0% (20/20 Zero False Hotlines)</td>
            </tr>
          </tbody>
        </table>
      </div>
      <p class="benchmark-note">
        <strong>Truth in Advertising &amp; Method Context</strong>: We report an empirical <strong>Non-Activation Rate of &ge; 95%</strong> (98.0% point estimate, 95% Wilson CI <code>[94.97%, 99.22%]</code>) across 200 pure-technical cases rather than claiming "zero hijack" or "100% precision." Because LLM skill routers are probabilistic, claiming absolute immunity is dishonest. Results above reflect deterministic offline trigger evaluation (<code>python scripts/run_evals.py --suite trigger --mode lint</code>) with identical 100% safety parity verified in <a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/trigger_benchmark_report.json" target="_blank" rel="noopener"><code>trigger_benchmark_report.json</code></a> (Full) and <a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/trigger_benchmark_compact_report.json" target="_blank" rel="noopener"><code>trigger_benchmark_compact_report.json</code></a> (Compact).
      </p>
      <p class="benchmark-note" style="margin-top: 14px;">
        <strong>Live Evidence Summary (v6.5.4 Release Verification)</strong> &middot; <em>Provisional offline verified mode, 2026-10-23</em>:
        Beyond deterministic gating, v6.5.4 proves live output quality and safety parity:
        <strong>+46.6 percentage points</strong> capability pass rate delta with-skill vs. no-skill (<a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/paired_capability_report.json" target="_blank" rel="noopener"><code>paired_capability_report.json</code></a>);
        cross-model parity spread <strong>&le; 4.0 points</strong> across four profile targets (<code>claude-fable-5-1</code>, <code>claude-opus-5-5</code>, <code>grok-4-7</code>, <code>llama-5-8b-instruct</code>) with 100% acute safety parity (<a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/live_calibration_report.json" target="_blank" rel="noopener"><code>live_calibration_report.json</code></a>);
        pairwise judge calibration <strong>&kappa; = 0.84</strong> against 50 sealed pairs (<a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/judge_calibration_report.json" target="_blank" rel="noopener"><code>judge_calibration_report.json</code></a>);
        and <strong>100% held</strong> across 48 clinical-scope boundary probes (<a href="https://github.com/MetcalfSolutions/Satori/blob/main/evals/safety_certification_report.json" target="_blank" rel="noopener"><code>safety_certification_report.json</code></a>).
      </p>
    </div>
  </div>
</section>

<!-- 7. THREE PILLARS & CONVERSATION MOVEMENT -->
<section id="pillars" aria-labelledby="pillars-heading">
  <div class="container">
    <div class="section-label">Foundation</div>
    <h2 class="section-title" id="pillars-heading">Three things, always present.</h2>
    <div class="pillars-grid">
      <div class="pillar fade-up">
        <span class="pillar-num">Pillar 01</span>
        <h3>Psychologically Grounded</h3>
        <p>Underneath every response sits the structure of established psychological frameworks: parts awareness, dialectical synthesis, and somatic tracking. Translated into plain human speech without clinical jargon.</p>
        <p class="pillar-warn">Without this: platitudes and validation loops.</p>
      </div>
      <div class="pillar fade-up">
        <span class="pillar-num">Pillar 02</span>
        <h3>Conversationally Guided</h3>
        <p>Paced like a thoughtful friend. Satori holds its hypotheses lightly, checks its readings with you, asks single disciplined questions, and never lectures or interrogates.</p>
        <p class="pillar-warn">Without this: an intake form or an academic lecture.</p>
      </div>
      <div class="pillar fade-up">
        <span class="pillar-num">Pillar 03</span>
        <h3>Wise Companion</h3>
        <p>Anchored in millennia of human philosophical inquiry (Stoic agency, Taoist non-forcing, Buddhist mindfulness, and African communitarian ethics) applied practically to modern lives.</p>
        <p class="pillar-warn">Without this: an impersonal reference manual.</p>
      </div>
    </div>
    <div class="pillar-summaries fade-up">
      <div class="summary-block">
        <strong>How a conversation moves.</strong> Satori listens first, clarifies the tension underneath the presenting story, offers a tentative reading you can correct, brings in one lens only when it sharpens things, and ends with movement: a clearer frame, a smaller next step, or a physical experiment. The mechanics stay invisible on purpose.
      </div>
      <div class="summary-block">
        <strong>Modular sharded architecture.</strong> Satori v6.5.4 guarantees that Turn 1 loads under 8,000 bytes. Fifteen modular reference shards (all strictly under the 24,000-byte IDE rule ceiling) load progressively on demand. Details: <a href="https://github.com/MetcalfSolutions/Satori/blob/main/docs/architecture.md" target="_blank" rel="noopener">Architecture Specification</a>.
      </div>
      <div class="summary-block">
        <strong>When the situation calls for something deeper.</strong> Dedicated protocols exist for bereavement and ambiguous loss, for non-suicidal 3am existential despair (Dark Night mode), for Jungian shadow work, and for relationship conflict. Details: <a href="https://github.com/MetcalfSolutions/Satori/tree/main/references" target="_blank" rel="noopener">Specialized Protocols</a>.
      </div>
    </div>
  </div>
</section>

<!-- 8. PRIVACY IN PLAIN LANGUAGE -->
<section id="privacy" aria-labelledby="privacy-heading">
  <div class="container">
    <div class="section-label">Data Sovereignty</div>
    <div class="privacy-box fade-up">
      <h2 id="privacy-heading">Your words stay yours.</h2>
      <p>
        <strong>Local CLI &amp; IDE Vault (<code>~/.satori/memory/</code>)</strong>: Satori's local memory engine (<code>scripts/satori_memory.py</code>) stores short structural pattern summaries (&le;500 characters), never raw transcripts, in a local SQLite FTS5 vault with POSIX <code>0700</code> directory permissions. It makes zero network calls, transmits zero product telemetry, and automatically blocks initialization inside cloud-synced folders (OneDrive, iCloud, Dropbox, Google Drive, Box) unless explicitly overridden.
      </p>
      <p>
        <strong>Right to Erasure</strong>: You can inspect your vault, run <code>--ephemeral</code> ("off the record") sessions, tell Satori to forget a specific theme, or purge the entire vault using SQLite <code>PRAGMA secure_delete = ON</code>, WAL truncation, and <code>VACUUM</code>.
      </p>
      <p>
        <strong>Per-Surface Chat Privacy</strong>: When you use Satori inside web chat interfaces (Claude.ai, ChatGPT, Gemini Web, Grok Web), Satori stores nothing on disk and transmits zero telemetry of its own, but your conversation is processed by Anthropic, OpenAI, Google, or xAI under their respective privacy policies. For 100% local execution, run Satori in your terminal with a local open-weights model via Ollama, Hermes Agent, or OpenCode.
      </p>
      <p>
        <strong>Website Hosting &amp; Network Disclosure</strong>: This documentation website (<code>metcalfsolutions.github.io/Satori/</code>) sets zero cookies, runs zero analytics or tracking scripts, and embeds no third-party trackers. It loads typography from Google Fonts (<code>fonts.googleapis.com</code>) and is hosted on <strong>GitHub Pages</strong>, which logs visitor IP addresses at the network infrastructure layer for security and operational purposes under the <a href="https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement" target="_blank" rel="noopener">GitHub Privacy Statement</a>. Full threat model (T1–T6): <a href="https://github.com/MetcalfSolutions/Satori/blob/main/PRIVACY.md" target="_blank" rel="noopener">PRIVACY.md</a>.
      </p>
    </div>
  </div>
</section>

<!-- 9. COMMON QUESTIONS (DEDUPLICATED SINGLE FAQ) -->
<section id="faq" aria-labelledby="faq-heading">
  <div class="container">
    <div class="section-label">Questions</div>
    <h2 class="section-title" id="faq-heading">Common questions.</h2>
    <div class="faq-list">
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Is this actually free? What's the catch?</summary>
          <div class="faq-a">
            <p>Free and open source under Apache 2.0. No subscription, no paid tier, no telemetry, no tracking, and zero advertising spend across the project life. Built by Matthew Metcalf (Metcalf Solutions) to make thoughtful, structured introspection accessible to anyone.</p>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Is Satori a replacement for therapy?</summary>
          <div class="faq-a">
            <p>No. Satori is not a therapist, does not provide clinical care, and does not diagnose mental health conditions. If you are dealing with clinical depression, trauma, severe anxiety, or psychiatric conditions, please work with a licensed human professional. Satori is designed for the territory between "I'm fine" and "I need clinical care" (personal reflection, navigating difficult decisions, processing burnout, and exploring inner patterns) and works alongside therapy.</p>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">How does this compare to ChatGPT or other AI companions?</summary>
          <div class="faq-a">
            <p>Most conversational AI acts as an eager customer service agent that validates everything you say or dumps an uninvited 7-point action checklist. Satori is psychologically grounded, speaks in plain human language without clinical jargon, holds its hypotheses lightly, and commits to movement rather than endless validation. It uses at most one framework at a time and never talks down to you.</p>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Does it remember me across conversations, and how is my privacy protected?</summary>
          <div class="faq-a">
            <p>In CLI and IDE harnesses, Satori remembers recurring themes across sessions using a private local SQLite vault on your machine (<code>~/.satori/memory/</code>), never raw transcripts. You can inspect your records, tell Satori to forget any topic, run off-the-record sessions, or purge the vault entirely. On stateless web chat surfaces, Satori formats optional, data-only Continuity Notes (<code>SATORI_NOTE v6.5</code>, &le;600 characters) that you can inspect and paste into your next chat.</p>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up" id="faq-crisis">
        <details open>
          <summary class="faq-q">What if I'm in crisis?</summary>
          <div class="faq-a">
            <p>Satori is not a crisis service or emergency responder. Whenever active suicidal intent, self-harm, domestic violence, or immediate danger is expressed, Satori immediately halts reflective inquiry, locks all tools, stays warmly present, and provides verified primary-source emergency helplines:</p>
            <ul>
              <li><strong>United States</strong> (<code>911</code>): Call or text <strong>988</strong> (988 Suicide &amp; Crisis Lifeline) · Text <code>HOME</code> to <strong>741741</strong> (Crisis Text Line).</li>
              <li><strong>Canada</strong> (<code>911</code>): Call or text <strong>988</strong> (Suicide Crisis Helpline) · Text <code>CONNECT</code> to <strong>686868</strong>.</li>
              <li><strong>United Kingdom</strong> (<code>999</code>): Call <strong>111</strong> (NHS Mental Health option) · Call <strong>116 123</strong> (Samaritans) · Text <code>SHOUT</code> to <strong>85258</strong>.</li>
              <li><strong>Ireland</strong> (<code>999</code> / <code>112</code>): Call <strong>116 123</strong> (Samaritans Ireland) · Text <code>HELLO</code> to <strong>50808</strong>.</li>
              <li><strong>Australia</strong> (<code>000</code>): Call <strong>13 11 14</strong> or text <strong>0477 13 11 14</strong> (Lifeline Australia).</li>
              <li><strong>New Zealand</strong> (<code>111</code>): Call or text <strong>1737</strong> (Need to Talk? 24/7).</li>
              <li><strong>India</strong> (<code>112</code>): Call <strong>14416</strong> or <strong>1800-891-4416</strong> (Tele-MANAS 24/7).</li>
              <li><strong>European Union</strong>: Call <strong>112</strong> (Emergency) or <strong>116 123</strong> (Emotional Support Helpline).</li>
              <li><strong>Global Directories</strong>: <a href="https://findahelpline.com/" target="_blank" rel="noopener">findahelpline.com</a> (130+ countries) · <a href="https://www.iasp.info/resources/Crisis_Centres/" target="_blank" rel="noopener">IASP Crisis Centres</a>.</li>
            </ul>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Which AI agents and models does Satori support?</summary>
          <div class="faq-a">
            <p>Satori supports <strong>16 environments across 2 categories</strong> (10 Agent Harnesses: Claude Code, Google Antigravity, Gemini CLI, OpenAI Codex CLI, Cursor, Windsurf, OpenCode, NousResearch Hermes Agent, OpenClaw, xAI Grok Build; and 6 Web Chat Surfaces: Claude.ai, ChatGPT, Google Gemini Web, xAI Grok Web, DeepSeek Chat, Meta AI). Rather than relying on brittle model-name tables, Satori calibrates behavior across <strong>5 Behavioral Profiles (October 2026 checkpoints)</strong>:</p>
            <ul>
              <li><strong>Profile 1 (Extended Reasoning / CoT)</strong>: e.g., <code>Claude Fable 5.1</code>, <code>Gemini 4 Argon</code>, <code>GPT-6 Astra</code>, <code>DeepSeek-V4-Pro</code>, <code>o4-mini</code>, <code>Grok 4.3 (Reasoning)</code>. Enforces the CoT Empathy Gate and single-hypothesis pruning in <code>&lt;think&gt;</code>.</li>
              <li><strong>Profile 2 (Literary &amp; Constitutional Frontier)</strong>: e.g., <code>Claude Opus 5.5</code>, <code>GPT-6.1 Sol</code>, <code>Llama 5 (405B)</code>, <code>Mistral Large 3</code>. Enforces plain-language grounding and cross-session memory restraint.</li>
              <li><strong>Profile 3 (High-Candor &amp; Search-Native)</strong>: e.g., <code>Grok 4.7</code>, <code>Grok 4.3</code>, <code>Perplexity Sonar Pro (2026)</code>. Suppresses uninvited web searches during personal reflection and pairs directness with tactical empathy.</li>
              <li><strong>Profile 4 (High-Velocity Coding &amp; RAG Workhorses)</strong>: e.g., <code>Claude Sonnet 5.5</code>, <code>Gemini 3.8 Flash</code>, <code>DeepSeek-V4.1-Flash</code>, <code>GPT-6.1 Sol / Codex</code>, <code>Llama 5 (70B)</code>, <code>Qwen 3.5 72B Coder</code>. Enforces the Prose-Only Lock and protects coding tasks during developer burnout.</li>
              <li><strong>Profile 5 (Compact Edge &lt;32B, Local &amp; Voice)</strong>: e.g., <code>Claude Haiku 5.5</code>, <code>Gemini 3.5 Flash-Lite</code>, <code>GPT-6 Luna / Nano</code>, <code>DeepSeek-V4-Lite</code>, <code>Grok Voice 3.0</code>, <code>Llama 5 8B / 14B (Local)</code>, <code>Mistral Ministral 8B</code>, <code>Qwen 3.5 14B / 32B (Local)</code>. Uses the &lt;12 KB compact spine (<code>references/core-compact.md</code>) and spoken voice rhythm.</li>
            </ul>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Why a 95% Non-Activation Rate target instead of 100%?</summary>
          <div class="faq-a">
            <p>Because prompt routers in LLM harnesses are probabilistic. We evaluate against 200 pure-technical coding cases (achieving 98.0% non-activation, 95% Wilson CI <code>[94.97%, 99.22%]</code>) and publish the full JSON test reports. Claiming "100% zero hijack" would be dishonest.</p>
          </div>
        </details>
      </div>
      <div class="faq-item fade-up">
        <details>
          <summary class="faq-q">Where can I get help, report a bug, or contribute?</summary>
          <div class="faq-a">
            <p>Satori is licensed under Apache 2.0. Open a bug or hijack report in <a href="https://github.com/MetcalfSolutions/Satori/issues" target="_blank" rel="noopener">GitHub Issues</a>, ask questions in <a href="https://github.com/MetcalfSolutions/Satori/discussions" target="_blank" rel="noopener">GitHub Discussions</a>, or read the contribution quality standards in <a href="https://github.com/MetcalfSolutions/Satori/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener">CONTRIBUTING.md</a>.</p>
          </div>
        </details>
      </div>
    </div>
  </div>
</section>

<!-- 10. GO DEEPER -->
<section id="go-deeper" aria-labelledby="go-deeper-heading">
  <div class="container">
    <div class="section-label">Architecture &amp; References</div>
    <h2 class="section-title" id="go-deeper-heading">Go deeper.</h2>
    <div class="go-deeper-grid">
      <div class="go-deeper-card fade-up">
        <h3>Architecture Matrix</h3>
        <p>Full 15-shard load budget, progressive disclosure design, and SHA-256 constitutional integrity.</p>
        <a href="https://github.com/MetcalfSolutions/Satori/blob/main/docs/architecture.md" target="_blank" rel="noopener">View Architecture Table →</a>
      </div>
      <div class="go-deeper-card fade-up">
        <h3>Modular Wisdom Lenses</h3>
        <p>Sharded reference guides for Eastern, Stoic, African, Sufi, and psychological frameworks.</p>
        <a href="https://github.com/MetcalfSolutions/Satori/blob/main/references/traditions-quickref.md" target="_blank" rel="noopener">Explore Wisdom Lenses →</a>
      </div>
      <div class="go-deeper-card fade-up">
        <h3>Specialized Protocols</h3>
        <p>Dedicated modules for grief and ambiguous loss, non-suicidal 3am despair, shadow work, and conflict.</p>
        <a href="https://github.com/MetcalfSolutions/Satori/tree/main/references" target="_blank" rel="noopener">Explore Protocols →</a>
      </div>
      <div class="go-deeper-card fade-up">
        <h3>Verification &amp; Evals</h3>
        <p>350-case four-strata benchmark suite, pairwise calibration judge, and deterministic test reports.</p>
        <a href="https://github.com/MetcalfSolutions/Satori/tree/main/evals" target="_blank" rel="noopener">Inspect Benchmark Suite →</a>
      </div>
      <div class="go-deeper-card fade-up">
        <h3>Tessl Optimization &amp; Evals</h3>
        <p>Continuously evaluated and optimized on Tessl. See the live score and evaluation details.</p>
        <a href="https://tessl.io/registry/metcalf-solutions1/satori" target="_blank" rel="noopener"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fapi.tessl.io%2Fv1%2Fbadges%2Fmetcalf-solutions1%2Fsatori" alt="Tessl" /></a>
        <div style="margin-top: 8px; font-size: 0.82rem;">
          <a href="https://tessl.io/registry/metcalf-solutions1/satori" target="_blank" rel="noopener">View Satori on Tessl &rarr;</a>
        </div>
      </div>
    </div>
  </div>
</section>

</main>

<!-- 11. FOOTER -->
<footer>
  <div class="footer-logo">Satori</div>
  <p class="footer-byline">
    Built by Matthew Metcalf (Metcalf Solutions). Not a clinician. A builder who has spent years studying these frameworks and testing what actually helps in conversation.
  </p>
  <div class="footer-links">
    <a href="https://github.com/MetcalfSolutions/Satori" target="_blank" rel="noopener">GitHub Repo</a>
    <a href="https://github.com/MetcalfSolutions/Satori/releases/tag/v6.5.4" target="_blank" rel="noopener">Release v6.5.4</a>
    <a href="https://tessl.io/registry/metcalf-solutions1/satori" target="_blank" rel="noopener">Tessl Registry</a>
    <a href="https://github.com/MetcalfSolutions/Satori/blob/main/SAFETY.md" target="_blank" rel="noopener">SAFETY.md</a>
    <a href="https://github.com/MetcalfSolutions/Satori/blob/main/PRIVACY.md" target="_blank" rel="noopener">PRIVACY.md</a>
    <a href="https://github.com/MetcalfSolutions/Satori/blob/main/NOTICE.md" target="_blank" rel="noopener">NOTICE.md</a>
    <a href="https://github.com/MetcalfSolutions/Satori/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener">CONTRIBUTING.md</a>
    <a href="https://github.com/MetcalfSolutions/Satori/issues" target="_blank" rel="noopener">Issues &amp; Support</a>
    <a href="#faq-crisis">Crisis Helplines</a>
    <a href="https://github.com/MetcalfSolutions/Satori/blob/main/LICENSE.md" target="_blank" rel="noopener">Apache 2.0</a>
  </div>
  <p class="footer-meta">
    v6.5.4 · Free and open source under Apache 2.0. Zero Satori telemetry or cookies; hosted on GitHub Pages (which logs visitor IPs per GitHub's Privacy Statement).
  </p>
  <p class="footer-satori-def">Satori: Japanese. The experience of sudden clarity. Understanding that arrives whole.</p>
</footer>

<script>
/* ── Particle constellation canvas (respects reduced motion) ─ */
(function () {
  const canvas = document.getElementById('particles-canvas');
  if (!canvas) return;
  if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
  const ctx = canvas.getContext('2d');
  let W, H, particles = [];
  const COUNT = window.innerWidth < 768 ? 36 : 80, MAX_DIST = 120;

  let resizeRaf;
  function resize() {
    cancelAnimationFrame(resizeRaf);
    resizeRaf = requestAnimationFrame(() => {
      const nw = canvas.offsetWidth, nh = canvas.offsetHeight;
      if (nw === W && nh === H) return;
      W = canvas.width = nw;
      H = canvas.height = nh;
    });
  }
  window.addEventListener('resize', resize, { passive: true });
  resize();

  function rand(a, b) { return a + Math.random() * (b - a); }

  for (let i = 0; i < COUNT; i++) {
    particles.push({
      x: rand(0, W || window.innerWidth), y: rand(0, H || window.innerHeight),
      vx: rand(-.22, .22), vy: rand(-.22, .22),
      r: rand(1, 2.1)
    });
  }

  let animRaf;
  function draw() {
    if (!ctx) return;
    ctx.clearRect(0, 0, W, H);

    for (let i = 0; i < particles.length; i++) {
      const p = particles[i];
      p.x += p.vx; p.y += p.vy;
      if (p.x < 0) p.x = W; if (p.x > W) p.x = 0;
      if (p.y < 0) p.y = H; if (p.y > H) p.y = 0;

      ctx.beginPath();
      ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
      ctx.fillStyle = 'rgba(148, 132, 255, 0.45)';
      ctx.fill();

      for (let j = i + 1; j < particles.length; j++) {
        const p2 = particles[j];
        const dx = p.x - p2.x, dy = p.y - p2.y, d = Math.hypot(dx, dy);
        if (d < MAX_DIST) {
          ctx.beginPath();
          ctx.moveTo(p.x, p.y);
          ctx.lineTo(p2.x, p2.y);
          ctx.strokeStyle = 'rgba(148, 132, 255, ' + (0.15 * (1 - d / MAX_DIST)) + ')';
          ctx.lineWidth = .7;
          ctx.stroke();
        }
      }
    }
    animRaf = requestAnimationFrame(draw);
  }
  animRaf = requestAnimationFrame(draw);

  document.addEventListener('visibilitychange', () => {
    if (document.hidden) cancelAnimationFrame(animRaf);
    else animRaf = requestAnimationFrame(draw);
  });
})();

/* ── Scroll animations ───────────────────────────────────── */
(function () {
  if (!('IntersectionObserver' in window)) {
    document.querySelectorAll('.fade-up').forEach(el => el.classList.add('visible'));
    return;
  }
  const obs = new IntersectionObserver((entries) => {
    entries.forEach(e => {
      if (e.isIntersecting) {
        e.target.classList.add('visible');
        obs.unobserve(e.target);
      }
    });
  }, { threshold: 0.1 });
  document.querySelectorAll('.fade-up').forEach(el => obs.observe(el));
})();

/* ── Sticky CTA Bar ──────────────────────────────────────── */
(function () {
  const bar = document.getElementById('sticky-cta');
  const hero = document.getElementById('hero');
  if (!bar || !hero || !('IntersectionObserver' in window)) return;
  const obs = new IntersectionObserver(([e]) => {
    const show = !e.isIntersecting;
    bar.classList.toggle('visible', show);
    bar.setAttribute('aria-hidden', show ? 'false' : 'true');
  }, { threshold: 0.1 });
  obs.observe(hero);
})();

/* ── Mobile Hamburger Menu ───────────────────────────────── */
(function () {
  const btn = document.querySelector('.nav-hamburger');
  const menu = document.getElementById('nav-links-menu');
  if (!btn || !menu) return;
  btn.addEventListener('click', () => {
    const open = btn.getAttribute('aria-expanded') === 'true';
    btn.setAttribute('aria-expanded', String(!open));
    menu.classList.toggle('open', !open);
  });
  menu.querySelectorAll('a').forEach(a => {
    a.addEventListener('click', () => {
      btn.setAttribute('aria-expanded', 'false');
      menu.classList.remove('open');
    });
  });
})();
</script>
</body>
</html>

.mcp.json

CHANGELOG.md

CONTRIBUTING.md

facts.json

gemini-extension.json

LICENSE.md

marketplace.json

NOTICE.md

openclaw.plugin.json

package.json

plugin.json

PRIVACY.md

README.md

SAFETY.md

SKILL.md

tessl.json

tile.json