solace / landing.html
ogNla's picture
feat: initial Solace AI therapy companion app
0242046
Raw
History Blame Contribute Delete
40.8 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Solace — A companion that listens</title>
<meta name="description" content="Solace is an AI therapy companion that runs in the browser and connects to a Reachy Mini robot. It listens, feels your tone, and responds with empathy." />
<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=Instrument+Serif:ital@0;1&family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<style>
:root {
--bg: #FAFAF7;
--bg-2: #F4F2EC;
--paper: #FFFFFF;
--ink: #1B1D1B;
--ink-2: #3A3D3A;
--muted: #8A8D88;
--muted-2: #B8BAB4;
--line: rgba(27, 29, 27, 0.08);
--line-2: rgba(27, 29, 27, 0.04);
--sage: #4A9B8F;
--sage-deep: #2F6F66;
--sage-soft: #D9E8E4;
--sage-tint: #EEF5F2;
--warn: #C8553D;
--shadow-sm: 0 1px 2px rgba(27,29,27,.04), 0 1px 1px rgba(27,29,27,.03);
--shadow-md: 0 8px 24px rgba(27,29,27,.06), 0 2px 6px rgba(27,29,27,.04);
--shadow-lg: 0 30px 60px rgba(27,29,27,.08), 0 10px 24px rgba(27,29,27,.06);
--radius-sm: 10px;
--radius-md: 16px;
--radius-lg: 24px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
html, body { margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--ink);
font-family: "Plus Jakarta Sans", system-ui, -apple-system, sans-serif;
font-size: 16px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: hidden;
}
.serif { font-family: "Instrument Serif", Georgia, serif; font-weight: 400; }
.mono { font-family: "JetBrains Mono", ui-monospace, monospace; }
em.sage { font-family: "Instrument Serif", Georgia, serif; font-style: italic; color: var(--sage-deep); font-weight: 400; }
.wrap {
width: 100%;
max-width: 1240px;
margin: 0 auto;
padding: 0 32px;
}
/* ═══════════════════════════════════════════════════
BRAND
═══════════════════════════════════════════════════ */
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
color: var(--ink);
text-decoration: none;
}
.brand-mark {
width: 26px; height: 26px;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #6FB8AD 0%, var(--sage) 55%, var(--sage-deep) 100%);
box-shadow: inset 0 -3px 6px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.08);
transition: filter .4s ease, transform .4s ease;
}
.brand:hover .brand-mark { filter: hue-rotate(-8deg) brightness(1.05); transform: rotate(8deg); }
.brand-word {
font-family: "Instrument Serif", serif;
font-size: 22px;
letter-spacing: -0.01em;
}
/* ═══════════════════════════════════════════════════
NAVBAR
═══════════════════════════════════════════════════ */
.nav {
position: sticky;
top: 0;
z-index: 50;
background: transparent;
transition: background .3s ease, backdrop-filter .3s ease, border-color .3s ease, box-shadow .3s ease;
border-bottom: 1px solid transparent;
}
.nav.scrolled {
background: rgba(250, 250, 247, 0.72);
backdrop-filter: saturate(140%) blur(14px);
-webkit-backdrop-filter: saturate(140%) blur(14px);
border-bottom-color: var(--line);
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 0;
}
.nav-links {
display: flex;
align-items: center;
gap: 28px;
}
.nav-links a {
color: var(--ink-2);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: color .2s ease;
}
.nav-links a:hover { color: var(--ink); }
/* ── Buttons ── */
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 20px;
border-radius: 999px;
font-family: inherit;
font-size: 14px;
font-weight: 500;
cursor: pointer;
text-decoration: none;
border: 1px solid transparent;
transition: transform .2s ease, background .2s ease, box-shadow .25s ease, border-color .2s ease, color .2s ease;
letter-spacing: 0.005em;
line-height: 1;
}
.btn .arrow {
font-family: "Instrument Serif", serif;
font-style: italic;
font-size: 18px;
line-height: 0.9;
}
.btn-dark {
background: var(--ink);
color: white;
}
.btn-dark:hover {
background: #000;
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(27,29,27,.18);
}
.btn-ghost {
background: transparent;
color: var(--sage-deep);
border-color: var(--sage);
}
.btn-ghost:hover {
background: var(--sage-tint);
transform: scale(1.02);
}
.btn-lg { padding: 16px 26px; font-size: 15px; }
/* ═══════════════════════════════════════════════════
HERO
═══════════════════════════════════════════════════ */
.hero {
position: relative;
padding: 88px 0 120px;
overflow: hidden;
}
.hero-inner {
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 56px;
align-items: center;
}
.hero-text {
position: relative;
z-index: 2;
}
.eyebrow {
font-family: "JetBrains Mono", monospace;
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 10px;
opacity: 0;
animation: rise .8s ease-out .0s forwards;
}
.eyebrow::before {
content: "";
width: 24px; height: 1px; background: var(--muted-2);
}
.h1 {
font-family: "Instrument Serif", serif;
font-weight: 400;
font-size: clamp(48px, 7.6vw, 84px);
line-height: 1.02;
letter-spacing: -0.015em;
margin: 16px 0 22px;
text-wrap: balance;
opacity: 0;
animation: rise .9s ease-out .15s forwards;
}
.h1 em { font-style: italic; color: var(--sage-deep); }
.lede {
font-size: 18px;
color: var(--ink-2);
max-width: 480px;
line-height: 1.55;
margin: 0 0 32px;
text-wrap: pretty;
opacity: 0;
animation: rise .9s ease-out .3s forwards;
}
.hero-ctas {
display: flex;
gap: 12px;
flex-wrap: wrap;
opacity: 0;
animation: rise .9s ease-out .45s forwards;
}
@keyframes rise {
from { opacity: 0; transform: translateY(14px); }
to { opacity: 1; transform: translateY(0); }
}
.hero-meta {
margin-top: 36px;
display: flex;
align-items: center;
gap: 14px;
color: var(--muted);
font-size: 12px;
opacity: 0;
animation: rise 1s ease-out .6s forwards;
}
.hero-meta .sep { width: 4px; height: 4px; border-radius: 50%; background: var(--muted-2); }
/* ── Hero stage (robot + rings) ── */
.hero-stage {
position: relative;
height: 540px;
display: flex;
align-items: center;
justify-content: center;
}
.hero-stage .ring {
position: absolute;
left: 50%; top: 50%;
border-radius: 50%;
transform: translate(-50%, -50%);
border: 1px solid rgba(74,155,143,.22);
pointer-events: none;
animation: breathe 5s ease-in-out infinite;
}
.hero-stage .ring.r1 { width: 320px; height: 320px; animation-delay: 0s; opacity: .22; }
.hero-stage .ring.r2 { width: 460px; height: 460px; animation-delay: .5s; opacity: .14; }
.hero-stage .ring.r3 { width: 620px; height: 620px; animation-delay: 1s; opacity: .08; }
.hero-stage .ring.r4 { width: 800px; height: 800px; animation-delay: 1.5s; opacity: .04; }
@keyframes breathe {
0%, 100% { transform: translate(-50%,-50%) scale(1); }
50% { transform: translate(-50%,-50%) scale(1.06); }
}
.hero-bg-tint {
position: absolute;
inset: -10% -5%;
background:
radial-gradient(40% 30% at 60% 40%, rgba(74,155,143,.06) 0%, transparent 60%),
radial-gradient(30% 25% at 30% 70%, rgba(74,155,143,.04) 0%, transparent 60%);
pointer-events: none;
z-index: 0;
}
/* Robot — original geometric Reachy stand-in */
.robot {
position: relative;
width: 240px; height: 280px;
animation: bob 6s ease-in-out infinite;
z-index: 2;
}
@keyframes bob {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
.robot .base {
position: absolute;
bottom: 0; left: 50%;
transform: translateX(-50%);
width: 160px; height: 64px;
border-radius: 22px 22px 30px 30px / 16px 16px 30px 30px;
background: linear-gradient(180deg, #F7F4ED 0%, #E5E0D2 100%);
box-shadow: inset 0 -8px 14px rgba(0,0,0,.06), 0 16px 28px rgba(0,0,0,.1);
}
.robot .neck {
position: absolute;
bottom: 56px; left: 50%;
transform: translateX(-50%);
width: 22px; height: 34px;
background: #C9C3B1;
border-radius: 4px;
box-shadow: inset -2px 0 2px rgba(0,0,0,.1);
}
.robot .head {
position: absolute;
bottom: 86px; left: 50%;
transform: translateX(-50%);
width: 174px; height: 150px;
border-radius: 50% 50% 44% 44% / 60% 60% 40% 40%;
background: linear-gradient(180deg, #FBF9F2 0%, #ECE7D7 100%);
box-shadow: inset 0 -10px 18px rgba(0,0,0,.06), 0 20px 36px rgba(0,0,0,.12);
}
.robot .visor {
position: absolute;
top: 38px; left: 50%;
transform: translateX(-50%);
width: 126px; height: 58px;
border-radius: 32px;
background: linear-gradient(180deg, #1B1D1B 0%, #2B2E2B 100%);
box-shadow: inset 0 2px 4px rgba(255,255,255,.08), 0 2px 4px rgba(0,0,0,.2);
display: flex;
align-items: center;
justify-content: center;
gap: 22px;
}
.robot .eye {
width: 12px; height: 12px;
border-radius: 50%;
background: var(--sage);
box-shadow: 0 0 10px rgba(74,155,143,.7);
animation: blink 5.2s ease-in-out infinite;
}
.robot .eye.right { animation-delay: .15s; }
@keyframes blink {
0%, 92%, 100% { transform: scaleY(1); }
94%, 98% { transform: scaleY(.1); }
}
.robot .antenna {
position: absolute;
top: -16px; left: 50%;
transform: translateX(-50%);
width: 2px; height: 20px;
background: #C9C3B1;
}
.robot .antenna::after {
content: "";
position: absolute;
top: -6px; left: 50%;
transform: translateX(-50%);
width: 8px; height: 8px;
border-radius: 50%;
background: var(--sage);
box-shadow: 0 0 8px rgba(74,155,143,.7);
}
/* secondary "ear" antennas */
.robot .ear {
position: absolute;
top: 36px; width: 6px; height: 26px;
background: #C9C3B1;
border-radius: 3px;
box-shadow: inset -1px 0 2px rgba(0,0,0,.1);
}
.robot .ear.left { left: -2px; transform: rotate(-12deg); }
.robot .ear.right { right: -2px; transform: rotate(12deg); }
.robot .ear::after {
content: "";
position: absolute;
top: -4px; left: 50%;
transform: translateX(-50%);
width: 5px; height: 5px;
border-radius: 50%;
background: var(--sage-soft);
}
/* floating mood chip on hero */
.float-chip {
position: absolute;
background: rgba(255,255,255,.85);
backdrop-filter: blur(8px);
border: 1px solid var(--line);
padding: 7px 13px;
border-radius: 999px;
font-size: 12px;
color: var(--ink-2);
box-shadow: var(--shadow-sm);
display: inline-flex;
align-items: center;
gap: 8px;
z-index: 3;
opacity: 0;
animation: float-in .9s ease-out 1s forwards, drift 8s ease-in-out 1.6s infinite;
}
@keyframes float-in {
from { opacity: 0; transform: translateY(8px) scale(.95); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes drift {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
}
.float-chip .dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--sage);
box-shadow: 0 0 0 0 rgba(74,155,143,.5);
animation: pulse-dot 2.2s ease-out infinite;
}
@keyframes pulse-dot {
0% { box-shadow: 0 0 0 0 rgba(74,155,143,.5); }
70% { box-shadow: 0 0 0 8px rgba(74,155,143,0); }
100% { box-shadow: 0 0 0 0 rgba(74,155,143,0); }
}
.float-chip.top { top: 14%; left: 4%; }
.float-chip.bottom { bottom: 18%; right: 2%; animation-delay: 1.2s, 2s; }
.float-chip.mid { top: 50%; right: -2%; animation-delay: 1.4s, 2.4s; }
/* ═══════════════════════════════════════════════════
SECTIONS — shared
═══════════════════════════════════════════════════ */
section { position: relative; }
.section {
padding: 120px 0;
}
.section-tag {
display: inline-flex;
align-items: center;
gap: 10px;
font-family: "JetBrains Mono", monospace;
font-size: 11px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--muted);
font-weight: 500;
margin-bottom: 18px;
}
.section-tag::before {
content: "";
width: 20px; height: 1px; background: var(--muted-2);
}
.section-h {
font-family: "Instrument Serif", serif;
font-size: clamp(38px, 5vw, 60px);
line-height: 1.05;
letter-spacing: -0.012em;
margin: 0 0 20px;
max-width: 760px;
text-wrap: balance;
}
.section-h em { font-style: italic; color: var(--sage-deep); }
.section-lede {
font-size: 18px;
color: var(--muted);
max-width: 540px;
line-height: 1.55;
margin: 0 0 56px;
text-wrap: pretty;
}
/* Reveal-on-scroll */
.reveal {
opacity: 0;
transform: translateY(16px);
transition: opacity .65s ease-out, transform .65s ease-out;
transition-delay: var(--rd, 0s);
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* ═══════════════════════════════════════════════════
HOW IT WORKS
═══════════════════════════════════════════════════ */
.how-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.how-card {
position: relative;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--radius-lg);
padding: 32px 28px;
box-shadow: var(--shadow-sm);
transition: transform .3s ease, box-shadow .3s ease;
overflow: hidden;
}
.how-card::before {
content: "";
position: absolute;
top: 0; left: 0; height: 2px;
width: 0;
background: linear-gradient(90deg, transparent, var(--sage), transparent);
transition: width .5s ease;
}
.how-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.how-card:hover::before { width: 100%; }
.how-icon {
width: 52px; height: 52px;
border-radius: 14px;
background: var(--sage-tint);
border: 1px solid var(--sage-soft);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
color: var(--sage-deep);
}
.how-icon svg { width: 24px; height: 24px; }
.how-num {
position: absolute;
top: 24px; right: 28px;
font-family: "JetBrains Mono", monospace;
font-size: 11px;
color: var(--muted-2);
letter-spacing: 0.08em;
}
.how-title {
font-family: "Instrument Serif", serif;
font-size: 30px;
margin: 0 0 12px;
letter-spacing: -0.005em;
}
.how-title em { font-style: italic; color: var(--sage-deep); }
.how-desc {
color: var(--ink-2);
font-size: 15px;
line-height: 1.6;
margin: 0;
text-wrap: pretty;
}
/* ═══════════════════════════════════════════════════
WHY IT MATTERS
═══════════════════════════════════════════════════ */
.why {
background: var(--bg-2);
padding: 120px 0;
position: relative;
}
.why::before, .why::after {
content: "";
position: absolute;
left: 0; right: 0; height: 64px;
background: linear-gradient(180deg, var(--bg), transparent);
top: 0; pointer-events: none;
}
.why::after { top: auto; bottom: 0; transform: scaleY(-1); }
.why-quote {
font-family: "Instrument Serif", serif;
font-style: italic;
font-size: clamp(30px, 4vw, 44px);
line-height: 1.2;
letter-spacing: -0.005em;
max-width: 860px;
margin: 0 0 64px;
color: var(--ink);
text-wrap: balance;
}
.why-quote::before {
content: "“";
display: block;
font-size: 80px;
line-height: 0.3;
color: var(--sage);
opacity: .55;
margin-bottom: 18px;
}
.why-quote b { font-style: italic; color: var(--sage-deep); font-weight: 400; }
.why-grid {
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 64px;
align-items: start;
}
.why-text p {
color: var(--ink-2);
font-size: 16.5px;
line-height: 1.65;
margin: 0 0 16px;
text-wrap: pretty;
}
.why-text p:last-child { margin-bottom: 0; color: var(--ink); }
.why-stats {
display: flex;
flex-direction: column;
gap: 14px;
}
.stat-chip {
display: grid;
grid-template-columns: 120px 1fr;
align-items: center;
gap: 22px;
padding: 22px 24px;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
transition: transform .3s ease;
}
.stat-chip:hover { transform: translateX(4px); }
.stat-num {
font-family: "Instrument Serif", serif;
font-size: 56px;
line-height: 1;
color: var(--sage-deep);
letter-spacing: -0.02em;
font-feature-settings: "tnum";
}
.stat-num em { font-style: italic; }
.stat-num .unit { font-size: 22px; color: var(--muted); margin-left: 4px; }
.stat-label {
color: var(--ink-2);
font-size: 14px;
line-height: 1.5;
text-wrap: pretty;
}
/* ═══════════════════════════════════════════════════
FIRST SESSION (steps)
═══════════════════════════════════════════════════ */
.steps {
display: flex;
flex-direction: column;
gap: 4px;
max-width: 880px;
}
.step {
position: relative;
display: grid;
grid-template-columns: 120px 1fr;
gap: 24px;
padding: 36px 0 36px 28px;
border-left: 1px solid var(--sage-soft);
transition: border-color .3s ease, padding-left .3s ease;
}
.step + .step { margin-top: -1px; }
.step:hover {
border-left-color: var(--sage);
padding-left: 32px;
}
.step:hover .step-num em { color: var(--sage); }
.step-num {
font-family: "Instrument Serif", serif;
font-size: 72px;
line-height: 0.85;
color: var(--sage-deep);
letter-spacing: -0.02em;
}
.step-num em { font-style: italic; transition: color .25s ease; }
.step-body h3 {
font-family: "Instrument Serif", serif;
font-weight: 400;
font-size: 32px;
margin: 6px 0 10px;
letter-spacing: -0.005em;
}
.step-body p {
color: var(--ink-2);
font-size: 16px;
line-height: 1.6;
margin: 0;
max-width: 560px;
text-wrap: pretty;
}
.step-body p code {
font-family: "JetBrains Mono", monospace;
font-size: 13px;
background: var(--sage-tint);
color: var(--sage-deep);
padding: 2px 7px;
border-radius: 5px;
}
/* ═══════════════════════════════════════════════════
POWERED BY (dark)
═══════════════════════════════════════════════════ */
.dark {
background: var(--ink);
color: #EDEFEB;
padding: 120px 0;
position: relative;
overflow: hidden;
}
.dark::before {
content: "";
position: absolute;
top: 50%; left: 50%;
width: 800px; height: 800px;
transform: translate(-50%, -50%);
background: radial-gradient(circle, rgba(74,155,143,.08) 0%, transparent 60%);
pointer-events: none;
}
.dark .section-tag { color: rgba(255,255,255,.5); }
.dark .section-tag::before { background: rgba(255,255,255,.25); }
.dark .section-h { color: #FAFAF7; }
.dark .section-h em { color: var(--sage); }
.dark-grid {
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 56px;
align-items: start;
position: relative;
z-index: 2;
}
.dark p {
color: rgba(237,239,235,.78);
font-size: 17px;
line-height: 1.65;
margin: 0;
text-wrap: pretty;
}
.tech-pills {
display: flex;
flex-direction: column;
gap: 14px;
}
.tech-pill {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
padding: 18px 22px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.08);
border-radius: var(--radius-md);
transition: background .25s ease, border-color .25s ease;
}
.tech-pill:hover {
background: rgba(74,155,143,.08);
border-color: rgba(74,155,143,.35);
}
.tech-pill .name {
font-family: "Instrument Serif", serif;
font-size: 22px;
color: #FAFAF7;
}
.tech-pill .role {
font-family: "JetBrains Mono", monospace;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.1em;
color: rgba(255,255,255,.5);
}
.dark-footnote {
margin-top: 40px;
font-family: "JetBrains Mono", monospace;
font-size: 12px;
color: rgba(255,255,255,.4);
letter-spacing: 0.04em;
}
.dark-footnote .dot { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: rgba(255,255,255,.3); margin: 0 8px; vertical-align: middle; }
/* ═══════════════════════════════════════════════════
FOOTER
═══════════════════════════════════════════════════ */
footer {
padding: 72px 0 48px;
border-top: 1px solid var(--line);
}
.foot-top {
display: grid;
grid-template-columns: 1.3fr 1fr;
gap: 48px;
align-items: start;
padding-bottom: 48px;
border-bottom: 1px solid var(--line-2);
}
.foot-tag {
font-family: "Instrument Serif", serif;
font-style: italic;
font-size: 30px;
color: var(--ink);
line-height: 1.2;
margin: 14px 0 0;
}
.foot-links {
display: flex;
flex-direction: column;
gap: 10px;
}
.foot-links-title {
font-family: "JetBrains Mono", monospace;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.14em;
color: var(--muted);
margin-bottom: 8px;
}
.foot-links a {
color: var(--ink-2);
text-decoration: none;
font-size: 15px;
transition: color .2s ease;
width: fit-content;
}
.foot-links a:hover { color: var(--sage-deep); }
.foot-links a .ext {
margin-left: 6px;
font-size: 11px;
color: var(--muted-2);
}
.foot-bottom {
padding-top: 28px;
display: flex;
justify-content: space-between;
align-items: flex-end;
gap: 24px;
flex-wrap: wrap;
}
.foot-disclaimer {
font-size: 12px;
color: var(--muted);
max-width: 620px;
line-height: 1.6;
}
.foot-disclaimer b { color: var(--ink-2); font-weight: 500; }
.foot-copy {
font-family: "JetBrains Mono", monospace;
font-size: 11px;
color: var(--muted-2);
letter-spacing: 0.04em;
text-align: right;
}
/* ═══════════════════════════════════════════════════
RESPONSIVE
═══════════════════════════════════════════════════ */
@media (max-width: 980px) {
.wrap { padding: 0 24px; }
.nav-links { display: none; }
.hero { padding: 56px 0 80px; }
.hero-inner { grid-template-columns: 1fr; gap: 24px; }
.hero-stage { height: 460px; order: -1; }
.hero-stage .ring.r1 { width: 260px; height: 260px; }
.hero-stage .ring.r2 { width: 360px; height: 360px; }
.hero-stage .ring.r3 { width: 480px; height: 480px; }
.hero-stage .ring.r4 { width: 600px; height: 600px; }
.section, .why, .dark { padding: 80px 0; }
.how-cards { grid-template-columns: 1fr; }
.why-grid { grid-template-columns: 1fr; gap: 36px; }
.dark-grid { grid-template-columns: 1fr; gap: 36px; }
.foot-top { grid-template-columns: 1fr; gap: 28px; }
}
@media (max-width: 480px) {
.wrap { padding: 0 20px; }
.nav-inner { padding: 14px 0; }
.nav .btn { padding: 10px 14px; font-size: 13px; }
.hero { padding: 32px 0 56px; }
.hero-stage { height: 380px; }
.robot { transform: scale(.78); }
.hero-ctas { width: 100%; }
.hero-ctas .btn { flex: 1; justify-content: center; }
.step { grid-template-columns: 1fr; gap: 4px; padding-left: 20px; }
.step-num { font-size: 48px; }
.step-body h3 { font-size: 24px; }
.stat-chip { grid-template-columns: 96px 1fr; padding: 18px 18px; gap: 16px; }
.stat-num { font-size: 42px; }
.float-chip.top { top: 6%; left: 2%; }
.float-chip.bottom { bottom: 8%; right: 2%; }
.float-chip.mid { display: none; }
.foot-bottom { flex-direction: column; align-items: flex-start; }
.foot-copy { text-align: left; }
}
/* Respect motion preference */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01s !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01s !important;
}
}
</style>
</head>
<body>
<!-- ─────────── NAV ─────────── -->
<nav class="nav" id="nav">
<div class="wrap nav-inner">
<a class="brand" href="#top" aria-label="Solace home">
<span class="brand-mark"></span>
<span class="brand-word">Solace</span>
</a>
<div class="nav-links">
<a href="#how">How it works</a>
<a href="#why">Why it matters</a>
<a href="#start">First session</a>
<a href="#stack">Stack</a>
</div>
<a class="btn btn-dark" href="index.html">Open App <span class="arrow"></span></a>
</div>
</nav>
<!-- ─────────── HERO ─────────── -->
<header class="hero" id="top">
<div class="hero-bg-tint"></div>
<div class="wrap hero-inner">
<div class="hero-text">
<div class="eyebrow">AI · Robot · Therapy</div>
<h1 class="h1">A companion that <em>truly listens.</em></h1>
<p class="lede">Speak freely to Reachy Mini. Solace hears your words, feels your tone, and responds — in motion and in voice — with genuine empathy.</p>
<div class="hero-ctas">
<a class="btn btn-dark btn-lg" href="index.html">Start a session <span class="arrow"></span></a>
<a class="btn btn-ghost btn-lg" href="#how">Watch it work</a>
</div>
<div class="hero-meta">
<span class="mono">No account</span>
<span class="sep"></span>
<span class="mono">No tracking</span>
<span class="sep"></span>
<span class="mono">Runs in browser</span>
</div>
</div>
<div class="hero-stage" aria-hidden="true">
<div class="ring r4"></div>
<div class="ring r3"></div>
<div class="ring r2"></div>
<div class="ring r1"></div>
<div class="robot">
<div class="antenna"></div>
<div class="ear left"></div>
<div class="ear right"></div>
<div class="head">
<div class="visor">
<span class="eye left"></span>
<span class="eye right"></span>
</div>
</div>
<div class="neck"></div>
<div class="base"></div>
</div>
<div class="float-chip top"><span class="dot"></span>Listening…</div>
<div class="float-chip mid">🌿 Calm &amp; steady</div>
<div class="float-chip bottom"><span class="dot" style="background:var(--warn);box-shadow:0 0 0 0 rgba(200,85,61,.5)"></span>Speaking</div>
</div>
</div>
</header>
<!-- ─────────── HOW IT WORKS ─────────── -->
<section class="section" id="how">
<div class="wrap">
<div class="section-tag reveal">How Solace works</div>
<h2 class="section-h reveal" style="--rd:.05s">Three quiet moments, <em>woven together.</em></h2>
<p class="section-lede reveal" style="--rd:.1s">A loop of attention — hear, understand, respond — that feels less like software and more like being met.</p>
<div class="how-cards">
<article class="how-card reveal" style="--rd:.0s">
<span class="how-num">01</span>
<div class="how-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="3" width="6" height="12" rx="3"></rect>
<path d="M5 11a7 7 0 0 0 14 0"></path>
<line x1="12" y1="18" x2="12" y2="22"></line>
</svg>
</div>
<h3 class="how-title"><em>Listen</em></h3>
<p class="how-desc">Speak naturally into your device. Solace captures your voice through the Reachy Mini robot's microphone and transcribes it using 0G Whisper AI — no cloud account, no tracking.</p>
</article>
<article class="how-card reveal" style="--rd:.12s">
<span class="how-num">02</span>
<div class="how-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3a4 4 0 0 0-4 4v1a4 4 0 0 0-2 7 4 4 0 0 0 6 4 4 4 0 0 0 6-4 4 4 0 0 0-2-7V7a4 4 0 0 0-4-4z"></path>
<path d="M12 8v13"></path>
</svg>
</div>
<h3 class="how-title"><em>Understand</em></h3>
<p class="how-desc">Your words flow to a powerful language model on 0G decentralized compute. It reads your emotional tone — not just the words — and crafts a warm, therapist-style response grounded in active listening.</p>
</article>
<article class="how-card reveal" style="--rd:.24s">
<span class="how-num">03</span>
<div class="how-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="5" y="8" width="14" height="11" rx="3"></rect>
<path d="M12 4v4"></path>
<circle cx="12" cy="3" r="1.2"></circle>
<circle cx="9.5" cy="13" r="1"></circle>
<circle cx="14.5" cy="13" r="1"></circle>
<path d="M9 17h6"></path>
</svg>
</div>
<h3 class="how-title"><em>Respond</em></h3>
<p class="how-desc">Reachy Mini moves. Its head tilts, its antennas shift, its synthetic voice speaks. Each reaction is choreographed to your specific emotion — a nod when you're heard, a gentle droop when you're sad, a lifted gaze when you show courage.</p>
</article>
</div>
</div>
</section>
<!-- ─────────── WHY IT MATTERS ─────────── -->
<section class="why" id="why">
<div class="wrap">
<div class="section-tag reveal">Why this matters</div>
<blockquote class="why-quote reveal" style="--rd:.05s">
<b>1 in 4 people</b> will face a mental health challenge this year. Most never speak to anyone about it.
</blockquote>
<div class="why-grid">
<div class="why-text reveal" style="--rd:.0s">
<p>There's a gap between needing support and reaching it — cost, stigma, availability, the simple weight of asking. For most people, on most days, that gap stays open.</p>
<p>Solace isn't therapy. It won't diagnose, prescribe, or replace a clinician. But it is a quiet place to be heard, any hour, for the price of a few cents of compute. Sometimes that's the difference between sitting with a feeling and being crushed by it.</p>
</div>
<div class="why-stats">
<div class="stat-chip reveal" style="--rd:.05s">
<div class="stat-num" data-count="50" data-suffix="%"><em>0%</em></div>
<div class="stat-label">of people with a mental illness receive no treatment in any given year.</div>
</div>
<div class="stat-chip reveal" style="--rd:.15s">
<div class="stat-num" data-count="4" data-suffix=" min"><em>0 min</em></div>
<div class="stat-label">average time before someone feels unheard in a difficult conversation.</div>
</div>
<div class="stat-chip reveal" style="--rd:.25s">
<div class="stat-num"><em></em></div>
<div class="stat-label">sessions available, no waitlist, no judgment, no one watching the clock.</div>
</div>
</div>
</div>
</div>
</section>
<!-- ─────────── FIRST SESSION ─────────── -->
<section class="section" id="start">
<div class="wrap">
<div class="section-tag reveal">Your first session</div>
<h2 class="section-h reveal" style="--rd:.05s">Four steps. <em>About five minutes.</em></h2>
<p class="section-lede reveal" style="--rd:.1s">No installs, no signups, no waiting for a confirmation email. Bring a key, bring yourself.</p>
<div class="steps">
<article class="step reveal" style="--rd:.0s">
<div class="step-num"><em>1</em></div>
<div class="step-body">
<h3>Get your 0G key</h3>
<p>Visit <code>pc.0g.ai</code>, fund a provider wallet, and generate your <code>app-sk-…</code> API key. Takes about three minutes.</p>
</div>
</article>
<article class="step reveal" style="--rd:.05s">
<div class="step-num"><em>2</em></div>
<div class="step-body">
<h3>Open Solace</h3>
<p>Open the app link in any browser. Paste your key into the setup card. Choose Simulator or Live Robot — both work, the simulator is plenty for a first try.</p>
</div>
</article>
<article class="step reveal" style="--rd:.1s">
<div class="step-num"><em>3</em></div>
<div class="step-body">
<h3>Speak</h3>
<p>Tap the mic button and talk. About your day, your worries, your wins — anything. Solace won't judge, and it won't rush you to the point.</p>
</div>
</article>
<article class="step reveal" style="--rd:.15s">
<div class="step-num"><em>4</em></div>
<div class="step-body">
<h3>Feel heard</h3>
<p>Watch Reachy Mini respond — moving its body to match your emotion, speaking back with warmth and one gentle question to help you go a little deeper.</p>
</div>
</article>
</div>
</div>
</section>
<!-- ─────────── POWERED BY ─────────── -->
<section class="dark" id="stack">
<div class="wrap">
<div class="section-tag reveal">Built on 0G</div>
<h2 class="section-h reveal" style="--rd:.05s">Decentralized AI, <em>privately.</em></h2>
<div class="dark-grid">
<div class="reveal" style="--rd:.1s">
<p>Solace runs entirely on 0G Compute — a decentralized network of AI providers. Your words are never stored on a central server. Your key funds only the compute you actually use, second by second, and nothing more.</p>
<p style="margin-top:18px">No subscription. No data lake. No model fine-tuning on what you said last Tuesday at 2 a.m.</p>
<div class="dark-footnote">
Reachy Mini SDK<span class="dot"></span>WebRTC<span class="dot"></span>Web Speech API<span class="dot"></span>Pure HTML
</div>
</div>
<div class="tech-pills">
<div class="tech-pill reveal" style="--rd:.05s">
<span class="name">0G Whisper</span>
<span class="role">speech recognition</span>
</div>
<div class="tech-pill reveal" style="--rd:.15s">
<span class="name">0G LLM</span>
<span class="role">emotion + dialogue</span>
</div>
</div>
</div>
</div>
</section>
<!-- ─────────── FOOTER ─────────── -->
<footer>
<div class="wrap">
<div class="foot-top">
<div>
<a class="brand" href="#top">
<span class="brand-mark"></span>
<span class="brand-word">Solace</span>
</a>
<div class="foot-tag">A companion that listens.</div>
</div>
<div class="foot-links">
<div class="foot-links-title">Links</div>
<a href="index.html">Open App <span class="ext"></span></a>
<a href="index.html">GitHub <span class="ext"></span></a>
<a href="index.html">0G Compute <span class="ext"></span></a>
<a href="index.html">Reachy Mini <span class="ext"></span></a>
</div>
</div>
<div class="foot-bottom">
<p class="foot-disclaimer">
<b>Solace is not a licensed therapy service.</b>
If you are in crisis, please contact <b>988</b> (US) or <b>116 123</b> (UK), or your local emergency number.
</p>
<div class="foot-copy">© 2026 Solace · Built for the Reachy Mini × 0G Hackathon</div>
</div>
</div>
</footer>
<script>
// ── Sticky navbar frosted state ──
(function () {
const nav = document.getElementById('nav');
let lastScrolled = false;
function onScroll() {
const scrolled = window.scrollY > 60;
if (scrolled !== lastScrolled) {
nav.classList.toggle('scrolled', scrolled);
lastScrolled = scrolled;
}
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})();
// ── Reveal on scroll ──
(function () {
const els = document.querySelectorAll('.reveal');
if (!('IntersectionObserver' in window)) {
els.forEach(el => el.classList.add('visible'));
return;
}
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('visible');
io.unobserve(e.target);
}
});
}, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 });
els.forEach(el => io.observe(el));
})();
// ── Count-up for stat numbers when in view ──
(function () {
const nums = document.querySelectorAll('.stat-num[data-count]');
if (!nums.length) return;
function countUp(el) {
const target = parseFloat(el.dataset.count);
const suffix = el.dataset.suffix || '';
const duration = 1200;
const start = performance.now();
function tick(now) {
const t = Math.min(1, (now - start) / duration);
const eased = 1 - Math.pow(1 - t, 3); // ease-out cubic
const val = Math.round(target * eased);
el.innerHTML = `<em>${val}${suffix}</em>`;
if (t < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
if (!('IntersectionObserver' in window)) {
nums.forEach(countUp);
return;
}
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
countUp(e.target);
io.unobserve(e.target);
}
});
}, { threshold: 0.5 });
nums.forEach(n => io.observe(n));
})();
</script>
</body>
</html>