Dating — Landing Serious
A warm, relationship-first dating landing page built around long-term compatibility. Leads with a soft gradient hero and an animated match-count ticker, then a compatibility-quiz teaser, a three-step how-it-works flow, real couple success stories with wedding dates, rotating member testimonials, transparent pricing, and an inline email signup that validates and confirms with a toast. Designed to feel earnest and human rather than swipe-happy.
MCP
Code
:root {
--bg: #fff5f6;
--surface: #ffffff;
--ink: #2a1a2e;
--ink-2: #5a4a55;
--muted: #8a7a85;
--coral: #ff5e6c;
--coral-d: #e63950;
--violet: #8b5cf6;
--violet-d: #7c3aed;
--pink: #ff8fb1;
--grad: linear-gradient(135deg, #ff5e6c, #8b5cf6);
--line: rgba(42, 26, 46, 0.10);
--white: #fff;
--r-sm: 12px;
--r-md: 20px;
--r-lg: 28px;
--shadow: 0 18px 44px -22px rgba(124, 58, 237, 0.45);
--shadow-soft: 0 10px 30px -18px rgba(42, 26, 46, 0.35);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1, h2, h3 {
margin: 0;
line-height: 1.12;
letter-spacing: -0.01em;
}
p {
margin: 0;
}
a {
color: inherit;
text-decoration: none;
}
img {
max-width: 100%;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.skip-link {
position: absolute;
left: -999px;
top: 8px;
background: var(--ink);
color: #fff;
padding: 10px 16px;
border-radius: 999px;
z-index: 100;
}
.skip-link:focus {
left: 12px;
}
:focus-visible {
outline: 3px solid var(--violet);
outline-offset: 2px;
border-radius: 6px;
}
/* ---- buttons ---- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font: inherit;
font-weight: 700;
border: 0;
cursor: pointer;
padding: 13px 24px;
border-radius: 999px;
transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
white-space: nowrap;
}
.btn-primary {
background: var(--grad);
color: #fff;
box-shadow: var(--shadow);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 22px 48px -20px rgba(124, 58, 237, 0.6);
}
.btn-primary:active {
transform: translateY(0);
}
.btn-ghost {
background: var(--white);
color: var(--ink);
border: 1.5px solid var(--line);
}
.btn-ghost:hover {
border-color: var(--coral);
color: var(--coral-d);
transform: translateY(-2px);
}
.eyebrow {
display: inline-block;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--violet-d);
background: rgba(139, 92, 246, 0.1);
padding: 6px 12px;
border-radius: 999px;
}
/* ---- header ---- */
.site-header {
position: sticky;
top: 0;
z-index: 40;
background: rgba(255, 245, 246, 0.82);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--line);
}
.nav {
max-width: 1120px;
margin: 0 auto;
padding: 14px 22px;
display: flex;
align-items: center;
gap: 24px;
}
.brand {
display: flex;
align-items: center;
gap: 8px;
font-family: "Fraunces", serif;
font-weight: 600;
font-size: 1.32rem;
}
.brand-mark {
color: var(--coral);
font-size: 1.1rem;
}
.nav-links {
display: flex;
gap: 22px;
list-style: none;
margin: 0 auto 0 12px;
padding: 0;
font-weight: 500;
}
.nav-links a {
color: var(--ink-2);
transition: color 0.15s;
}
.nav-links a:hover {
color: var(--coral-d);
}
.nav-cta {
padding: 9px 18px;
}
/* ---- hero ---- */
.hero {
max-width: 1120px;
margin: 0 auto;
padding: 64px 22px 40px;
}
.hero-inner {
display: grid;
grid-template-columns: 1.15fr 0.85fr;
gap: 48px;
align-items: center;
}
h1 {
font-family: "Fraunces", serif;
font-weight: 600;
font-size: clamp(2.3rem, 5vw, 3.6rem);
}
h1 em {
font-style: italic;
background: var(--grad);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.lede {
margin-top: 20px;
font-size: 1.12rem;
color: var(--ink-2);
max-width: 46ch;
}
.join-form {
margin-top: 28px;
}
.field {
display: flex;
gap: 10px;
background: var(--white);
padding: 8px;
border-radius: 999px;
border: 1.5px solid var(--line);
box-shadow: var(--shadow-soft);
max-width: 460px;
transition: border-color 0.16s, box-shadow 0.16s;
}
.field:focus-within {
border-color: var(--violet);
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15);
}
.field input {
flex: 1;
border: 0;
background: transparent;
font: inherit;
padding: 6px 16px;
color: var(--ink);
min-width: 0;
}
.field input:focus {
outline: none;
}
.field.invalid {
border-color: var(--coral-d);
box-shadow: 0 0 0 4px rgba(230, 57, 80, 0.14);
}
.hint {
margin-top: 10px;
font-size: 0.9rem;
color: var(--muted);
}
.hint.error {
color: var(--coral-d);
font-weight: 600;
}
.trust-row {
margin-top: 26px;
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.trust-chip {
font-size: 0.9rem;
color: var(--ink-2);
background: var(--white);
border: 1px solid var(--line);
padding: 8px 14px;
border-radius: 999px;
}
.trust-chip b {
color: var(--coral-d);
}
/* hero stat */
.hero-stat {
position: relative;
}
.stat-card {
background: var(--grad);
color: #fff;
border-radius: var(--r-lg);
padding: 32px 28px;
box-shadow: var(--shadow);
position: relative;
overflow: hidden;
}
.stat-card::after {
content: "";
position: absolute;
inset: auto -30px -60px auto;
width: 180px;
height: 180px;
background: rgba(255, 255, 255, 0.16);
border-radius: 50%;
}
.stat-eyebrow {
font-size: 0.82rem;
font-weight: 600;
opacity: 0.92;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.stat-number {
display: block;
font-family: "Fraunces", serif;
font-weight: 600;
font-size: clamp(2.4rem, 6vw, 3.2rem);
margin: 8px 0 2px;
font-variant-numeric: tabular-nums;
}
.stat-sub {
font-size: 0.98rem;
opacity: 0.9;
}
.avatar-stack {
display: flex;
align-items: center;
margin-top: 22px;
}
.av {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2.5px solid rgba(255, 255, 255, 0.85);
margin-left: -10px;
}
.av:first-child {
margin-left: 0;
}
.av-1 { background: linear-gradient(135deg, #ffd1dc, #ff8fb1); }
.av-2 { background: linear-gradient(135deg, #c4b5fd, #8b5cf6); }
.av-3 { background: linear-gradient(135deg, #ffe0b2, #ffab73); }
.av-4 { background: linear-gradient(135deg, #b9f6ca, #69f0ae); }
.av-more {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.72rem;
font-weight: 700;
background: rgba(255, 255, 255, 0.22);
color: #fff;
}
.stat-note {
margin-top: 14px;
font-size: 0.9rem;
opacity: 0.9;
}
/* ---- compat ---- */
.compat {
max-width: 1120px;
margin: 40px auto;
padding: 0 22px;
}
.compat-inner {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 40px;
display: grid;
grid-template-columns: 1fr 0.9fr;
gap: 40px;
align-items: center;
box-shadow: var(--shadow-soft);
}
.compat-copy h2 {
margin: 14px 0 12px;
font-family: "Fraunces", serif;
font-weight: 600;
font-size: clamp(1.6rem, 3.4vw, 2.2rem);
}
.compat-copy p {
color: var(--ink-2);
max-width: 42ch;
}
.dim-list {
margin: 20px 0 0;
padding: 0;
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.dim-list li {
font-size: 0.88rem;
font-weight: 500;
color: var(--violet-d);
background: rgba(139, 92, 246, 0.09);
padding: 7px 13px;
border-radius: 999px;
}
.compat-widget {
background: var(--bg);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 30px;
text-align: center;
}
.gauge {
width: 168px;
height: 168px;
margin: 0 auto 22px;
border-radius: 50%;
display: flex;
align-items: baseline;
justify-content: center;
gap: 2px;
position: relative;
background:
radial-gradient(circle at center, var(--white) 60%, transparent 61%),
conic-gradient(var(--coral) 0turn, var(--violet) var(--gauge-turn, 0.72turn), rgba(42, 26, 46, 0.08) 0);
box-shadow: var(--shadow-soft);
transition: --gauge-turn 0.4s ease;
}
.gauge-num {
font-family: "Fraunces", serif;
font-weight: 600;
font-size: 3rem;
color: var(--ink);
align-self: center;
font-variant-numeric: tabular-nums;
}
.gauge-pct {
font-weight: 700;
color: var(--violet-d);
align-self: center;
font-size: 1.2rem;
}
.gauge-label {
position: absolute;
bottom: 34px;
left: 0;
right: 0;
font-size: 0.74rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
align-self: unset;
}
.slider-block {
text-align: left;
}
.slider-block label {
display: block;
font-weight: 600;
font-size: 0.92rem;
margin-bottom: 10px;
}
input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
background: linear-gradient(90deg, var(--coral), var(--violet));
outline-offset: 4px;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 26px;
height: 26px;
border-radius: 50%;
background: var(--white);
border: 3px solid var(--violet);
box-shadow: var(--shadow-soft);
cursor: pointer;
transition: transform 0.14s;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.12);
}
input[type="range"]::-moz-range-thumb {
width: 26px;
height: 26px;
border-radius: 50%;
background: var(--white);
border: 3px solid var(--violet);
cursor: pointer;
}
.slider-scale {
display: flex;
justify-content: space-between;
margin-top: 6px;
font-size: 0.74rem;
color: var(--muted);
}
.widget-tag {
margin-top: 18px;
font-weight: 600;
color: var(--coral-d);
}
/* ---- sections shared ---- */
.section-head {
text-align: center;
max-width: 640px;
margin: 0 auto 34px;
}
.section-head h2 {
margin-top: 14px;
font-family: "Fraunces", serif;
font-weight: 600;
font-size: clamp(1.7rem, 3.6vw, 2.4rem);
}
/* ---- how ---- */
.how {
max-width: 1120px;
margin: 72px auto;
padding: 0 22px;
}
.steps {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 22px;
counter-reset: none;
}
.step {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 30px 26px;
transition: transform 0.18s, box-shadow 0.18s;
}
.step:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-soft);
}
.step-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border-radius: 50%;
background: var(--grad);
color: #fff;
font-weight: 800;
font-size: 1.1rem;
margin-bottom: 16px;
}
.step h3 {
font-size: 1.2rem;
margin-bottom: 8px;
}
.step p {
color: var(--ink-2);
}
/* ---- stories ---- */
.stories {
max-width: 1120px;
margin: 72px auto;
padding: 0 22px;
}
.story-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.story-card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--shadow-soft);
transition: transform 0.18s, box-shadow 0.18s;
}
.story-card:hover {
transform: translateY(-5px);
box-shadow: var(--shadow);
}
.story-photo {
height: 180px;
position: relative;
}
.photo-a { background: linear-gradient(135deg, #ff8fb1, #ff5e6c); }
.photo-b { background: linear-gradient(135deg, #c4b5fd, #8b5cf6); }
.photo-c { background: linear-gradient(135deg, #ffd1a1, #ff5e6c 90%); }
.story-photo::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.35), transparent 55%);
}
.story-body {
padding: 22px 24px 26px;
}
.badge {
display: inline-block;
font-size: 0.74rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--violet-d);
background: rgba(139, 92, 246, 0.12);
padding: 5px 11px;
border-radius: 999px;
margin-bottom: 12px;
}
.story-body h3 {
font-size: 1.24rem;
}
.story-quote {
margin: 10px 0 14px;
color: var(--ink-2);
font-style: italic;
}
.story-meta {
font-size: 0.86rem;
color: var(--muted);
font-weight: 500;
}
/* ---- testimonial ---- */
.testi {
max-width: 760px;
margin: 72px auto;
padding: 0 22px;
}
.testi-card {
background: var(--grad);
color: #fff;
border-radius: var(--r-lg);
padding: 44px 40px;
text-align: center;
box-shadow: var(--shadow);
}
.testi-card blockquote {
margin: 0;
font-family: "Fraunces", serif;
font-weight: 500;
font-size: clamp(1.2rem, 2.6vw, 1.55rem);
line-height: 1.4;
transition: opacity 0.3s;
}
.testi-who {
margin-top: 20px;
display: flex;
flex-direction: column;
gap: 2px;
}
.testi-name {
font-weight: 700;
}
.testi-role {
font-size: 0.9rem;
opacity: 0.9;
}
.testi-dots {
display: flex;
justify-content: center;
gap: 9px;
margin-top: 22px;
}
.testi-dots button {
width: 10px;
height: 10px;
padding: 0;
border-radius: 50%;
border: 0;
background: rgba(255, 255, 255, 0.42);
cursor: pointer;
transition: transform 0.15s, background 0.15s;
}
.testi-dots button:hover {
transform: scale(1.25);
}
.testi-dots button[aria-selected="true"] {
background: #fff;
transform: scale(1.25);
}
/* ---- pricing ---- */
.pricing {
max-width: 1120px;
margin: 72px auto;
padding: 0 22px;
}
.plans {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 22px;
align-items: stretch;
}
.plan {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 32px 28px;
display: flex;
flex-direction: column;
transition: transform 0.18s, box-shadow 0.18s;
}
.plan:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-soft);
}
.plan-featured {
position: relative;
border: 2px solid var(--violet);
box-shadow: var(--shadow);
}
.plan-flag {
position: absolute;
top: -13px;
left: 50%;
transform: translateX(-50%);
background: var(--grad);
color: #fff;
font-size: 0.74rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
padding: 6px 14px;
border-radius: 999px;
}
.plan h3 {
font-size: 1.3rem;
}
.price {
margin: 12px 0 18px;
color: var(--muted);
font-weight: 500;
}
.price span {
font-family: "Fraunces", serif;
font-weight: 600;
font-size: 2.4rem;
color: var(--ink);
}
.plan-feats {
list-style: none;
margin: 0 0 24px;
padding: 0;
display: grid;
gap: 11px;
flex: 1;
}
.plan-feats li {
position: relative;
padding-left: 26px;
color: var(--ink-2);
}
.plan-feats li::before {
content: "♥";
position: absolute;
left: 0;
color: var(--coral);
font-size: 0.9rem;
}
.plan .btn {
width: 100%;
}
/* ---- final cta ---- */
.final-cta {
max-width: 1120px;
margin: 72px auto;
padding: 0 22px;
}
.cta-card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 54px 40px;
text-align: center;
box-shadow: var(--shadow-soft);
position: relative;
overflow: hidden;
}
.cta-card::before {
content: "";
position: absolute;
inset: -50% 60% 40% -20%;
background: radial-gradient(circle, rgba(255, 94, 108, 0.14), transparent 70%);
}
.cta-card::after {
content: "";
position: absolute;
inset: 40% -20% -50% 60%;
background: radial-gradient(circle, rgba(139, 92, 246, 0.14), transparent 70%);
}
.cta-card > * {
position: relative;
}
.cta-card h2 {
font-family: "Fraunces", serif;
font-weight: 600;
font-size: clamp(1.7rem, 3.6vw, 2.4rem);
}
.cta-card p {
margin-top: 12px;
color: var(--ink-2);
}
.join-form--big {
margin: 26px auto 0;
}
.join-form--big .field {
margin: 0 auto;
}
.fineprint {
margin-top: 16px;
font-size: 0.84rem;
color: var(--muted);
}
/* ---- footer ---- */
.site-footer {
border-top: 1px solid var(--line);
padding: 30px 22px;
text-align: center;
color: var(--muted);
font-size: 0.9rem;
}
/* ---- toast ---- */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 140%);
background: var(--ink);
color: #fff;
padding: 14px 22px;
border-radius: 999px;
font-weight: 600;
box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.4);
z-index: 90;
opacity: 0;
transition: transform 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2), opacity 0.32s;
max-width: calc(100% - 44px);
text-align: center;
}
.toast.show {
transform: translate(-50%, 0);
opacity: 1;
}
/* ---- responsive ---- */
@media (max-width: 900px) {
.hero-inner,
.compat-inner {
grid-template-columns: 1fr;
gap: 32px;
}
.steps,
.story-grid,
.plans {
grid-template-columns: 1fr;
}
.plan-featured {
order: -1;
}
}
@media (max-width: 520px) {
.nav-links {
display: none;
}
.hero {
padding: 40px 18px 24px;
}
.compat-inner,
.cta-card {
padding: 28px 22px;
}
.field {
flex-direction: column;
border-radius: var(--r-md);
padding: 12px;
}
.field input {
padding: 10px 12px;
}
.field .btn {
width: 100%;
}
.testi-card {
padding: 32px 24px;
}
.trust-row {
gap: 8px;
}
}(function () {
"use strict";
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 3200);
}
/* ---------- animated match ticker ---------- */
var ticker = document.getElementById("ticker");
if (ticker) {
var target = parseInt(ticker.getAttribute("data-target"), 10) || 0;
var started = false;
function runTicker() {
if (started) return;
started = true;
var duration = 1800;
var start = null;
function step(ts) {
if (start === null) start = ts;
var p = Math.min((ts - start) / duration, 1);
// easeOutCubic
var eased = 1 - Math.pow(1 - p, 3);
var val = Math.floor(eased * target);
ticker.textContent = val.toLocaleString("en-US");
if (p < 1) requestAnimationFrame(step);
else ticker.textContent = target.toLocaleString("en-US");
}
requestAnimationFrame(step);
}
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) {
runTicker();
io.disconnect();
}
});
},
{ threshold: 0.4 }
);
io.observe(ticker);
} else {
runTicker();
}
}
/* ---------- compatibility slider ---------- */
var slider = document.getElementById("valuesSlider");
var scoreOut = document.getElementById("scoreOut");
var gauge = document.querySelector(".gauge");
var widgetTag = document.getElementById("widgetTag");
var tags = [
"Not quite aligned — friendship, maybe.",
"Some common ground to explore.",
"Worth a conversation.",
"A promising start — worth a first date.",
"Strong potential. Say hello.",
"Exceptional match. Don't overthink it.",
];
function updateScore() {
if (!slider) return;
var v = parseInt(slider.value, 10); // 0..5
// base 40 up to 96
var score = Math.round(40 + (v / 5) * 56);
if (scoreOut) scoreOut.textContent = score;
if (gauge) {
var turn = (score / 100).toFixed(3);
gauge.style.setProperty("--gauge-turn", turn + "turn");
// fallback for browsers without @property animated conic: set background directly
gauge.style.background =
"radial-gradient(circle at center, var(--white) 60%, transparent 61%)," +
"conic-gradient(var(--coral) 0turn, var(--violet) " +
turn +
"turn, rgba(42,26,46,0.08) 0)";
}
if (widgetTag) widgetTag.textContent = tags[v];
}
if (slider) {
slider.addEventListener("input", updateScore);
updateScore();
}
/* ---------- testimonial rotator ---------- */
var testimonials = [
{
q: "I'd deleted every other app. Kindred was the first one that felt like it took me seriously.",
name: "Amara, 31",
role: "joined for something serious",
},
{
q: "The compatibility profile actually surfaced people I'd never have swiped past. I'm dating one of them now.",
name: "Jonah, 34",
role: "matched at 88%",
},
{
q: "No games, no ghosting-by-design. Just a short list of thoughtful people every morning.",
name: "Lena, 29",
role: "Kindred+ member",
},
{
q: "My matchmaker introduced me to someone I'd have overlooked. Six months in and it's the real thing.",
name: "Marcus, 38",
role: "Concierge member",
},
];
var quoteEl = document.getElementById("testiQuote");
var nameEl = document.getElementById("testiName");
var roleEl = document.getElementById("testiRole");
var dotsEl = document.getElementById("testiDots");
var current = 0;
var autoTimer;
function renderTesti(i) {
var t = testimonials[i];
if (!quoteEl) return;
quoteEl.style.opacity = "0";
setTimeout(function () {
quoteEl.textContent = "“" + t.q + "”";
nameEl.textContent = t.name;
roleEl.textContent = t.role;
quoteEl.style.opacity = "1";
}, 180);
Array.prototype.forEach.call(dotsEl.children, function (btn, idx) {
btn.setAttribute("aria-selected", idx === i ? "true" : "false");
});
current = i;
}
function goTesti(i) {
renderTesti((i + testimonials.length) % testimonials.length);
restartAuto();
}
function restartAuto() {
clearInterval(autoTimer);
autoTimer = setInterval(function () {
goTesti(current + 1);
}, 5000);
}
if (dotsEl) {
testimonials.forEach(function (t, i) {
var b = document.createElement("button");
b.type = "button";
b.setAttribute("role", "tab");
b.setAttribute("aria-label", "Show testimonial " + (i + 1));
b.addEventListener("click", function () {
goTesti(i);
});
dotsEl.appendChild(b);
});
renderTesti(0);
restartAuto();
}
/* ---------- email signup forms ---------- */
function isValidEmail(v) {
return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v);
}
function wireForm(formId, successMsg) {
var form = document.getElementById(formId);
if (!form) return;
var input = form.querySelector("input[type='email']");
var field = form.querySelector(".field");
var hint = form.querySelector(".hint");
var defaultHint = hint ? hint.textContent : "";
input.addEventListener("input", function () {
if (field.classList.contains("invalid") && isValidEmail(input.value.trim())) {
field.classList.remove("invalid");
if (hint) {
hint.classList.remove("error");
hint.textContent = defaultHint;
}
}
});
form.addEventListener("submit", function (e) {
e.preventDefault();
var val = input.value.trim();
if (!isValidEmail(val)) {
field.classList.add("invalid");
if (hint) {
hint.classList.add("error");
hint.textContent = "Please enter a valid email address.";
}
input.focus();
return;
}
field.classList.remove("invalid");
if (hint) {
hint.classList.remove("error");
hint.textContent = defaultHint;
}
form.reset();
toast(successMsg);
});
}
wireForm("joinForm", "Welcome to Kindred! Check your inbox to begin. 💜");
wireForm("joinForm2", "You're in! Let's build your profile. 💜");
/* ---------- smooth scroll for in-page nav ---------- */
document.querySelectorAll('a[href^="#"]').forEach(function (a) {
a.addEventListener("click", function (e) {
var id = a.getAttribute("href");
if (id === "#" || id.length < 2) return;
var el = document.querySelector(id);
if (el) {
e.preventDefault();
el.scrollIntoView({ behavior: "smooth", block: "start" });
if (id === "#join") {
var focusInput = el.querySelector("input[type='email']");
if (focusInput) setTimeout(function () { focusInput.focus(); }, 500);
}
}
});
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Kindred — Dating for people who mean it</title>
<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=Inter:wght@400;500;600;700;800&family=Fraunces:opsz,[email protected],500;9..144,600&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header class="site-header">
<nav class="nav" aria-label="Primary">
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">◆</span>
Kindred
</a>
<ul class="nav-links">
<li><a href="#how">How it works</a></li>
<li><a href="#stories">Success stories</a></li>
<li><a href="#pricing">Pricing</a></li>
</ul>
<a class="btn btn-ghost nav-cta" href="#join">Sign in</a>
</nav>
</header>
<main id="main">
<!-- HERO -->
<section class="hero" id="top">
<div class="hero-inner">
<div class="hero-copy">
<span class="eyebrow">Built for lasting relationships</span>
<h1>Find someone who's<br /><em>actually</em> looking for forever.</h1>
<p class="lede">
Kindred pairs you on values, life goals, and everyday habits — not just a
photo. Take the compatibility profile once, and meet people ready for the
real thing.
</p>
<form class="join-form" id="joinForm" novalidate>
<div class="field">
<label class="sr-only" for="email">Email address</label>
<input
type="email"
id="email"
name="email"
inputmode="email"
autocomplete="email"
placeholder="[email protected]"
aria-describedby="joinHint"
/>
<button class="btn btn-primary" type="submit">Start free</button>
</div>
<p class="hint" id="joinHint">Free to join. No swiping games.</p>
</form>
<div class="trust-row" aria-label="Highlights">
<span class="trust-chip"><b>4.8</b> App rating</span>
<span class="trust-chip"><b>73%</b> Meet within 3 months</span>
</div>
</div>
<aside class="hero-stat" aria-label="Members matched">
<div class="stat-card">
<span class="stat-eyebrow">Meaningful matches made</span>
<span class="stat-number" id="ticker" data-target="2841976">0</span>
<span class="stat-sub">and counting, this year alone</span>
<div class="avatar-stack" aria-hidden="true">
<span class="av av-1"></span>
<span class="av av-2"></span>
<span class="av av-3"></span>
<span class="av av-4"></span>
<span class="av av-more">+9k</span>
</div>
<p class="stat-note">New members joined near you today</p>
</div>
</aside>
</div>
</section>
<!-- COMPATIBILITY TEASER -->
<section class="compat" id="compat" aria-labelledby="compatTitle">
<div class="compat-inner">
<div class="compat-copy">
<span class="eyebrow">Compatibility, not chance</span>
<h2 id="compatTitle">See how our matching thinks</h2>
<p>
Every profile is scored across five dimensions. Slide to see how sharing
more core values lifts a match — the same model we run on real profiles.
</p>
<ul class="dim-list">
<li>Values & family goals</li>
<li>Communication style</li>
<li>Daily rhythm & lifestyle</li>
<li>Ambition & growth</li>
<li>Humor & warmth</li>
</ul>
</div>
<div class="compat-widget">
<div class="gauge">
<span class="gauge-num" id="scoreOut">72</span>
<span class="gauge-pct">%</span>
<span class="gauge-label">compatibility</span>
</div>
<div class="slider-block">
<label for="valuesSlider">Shared core values</label>
<input
type="range"
id="valuesSlider"
min="0"
max="5"
value="3"
step="1"
aria-describedby="scoreOut"
/>
<div class="slider-scale" aria-hidden="true">
<span>0</span><span>1</span><span>2</span><span>3</span><span>4</span><span>5</span>
</div>
</div>
<p class="widget-tag" id="widgetTag">A promising start — worth a first date.</p>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section class="how" id="how" aria-labelledby="howTitle">
<div class="section-head">
<span class="eyebrow">Simple & guided</span>
<h2 id="howTitle">Three steps to a real connection</h2>
</div>
<ol class="steps">
<li class="step">
<span class="step-num">1</span>
<h3>Build your profile</h3>
<p>Answer the compatibility profile — 20 thoughtful questions, about six minutes.</p>
</li>
<li class="step">
<span class="step-num">2</span>
<h3>Meet your matches</h3>
<p>Each morning we hand-pick a short list of genuinely compatible people.</p>
</li>
<li class="step">
<span class="step-num">3</span>
<h3>Start something real</h3>
<p>Break the ice with guided prompts, then plan a first date when it feels right.</p>
</li>
</ol>
</section>
<!-- SUCCESS STORIES -->
<section class="stories" id="stories" aria-labelledby="storiesTitle">
<div class="section-head">
<span class="eyebrow">Real couples</span>
<h2 id="storiesTitle">Love that started here</h2>
</div>
<div class="story-grid">
<article class="story-card">
<div class="story-photo photo-a" role="img" aria-label="Maya and Devin"></div>
<div class="story-body">
<span class="badge">Married</span>
<h3>Maya & Devin</h3>
<p class="story-quote">"We matched at 91%. Two years later we're planning our first road trip as a married couple."</p>
<p class="story-meta">Met Mar 2023 · Married Sep 2025</p>
</div>
</article>
<article class="story-card">
<div class="story-photo photo-b" role="img" aria-label="Priya and Tomás"></div>
<div class="story-body">
<span class="badge">Engaged</span>
<h3>Priya & Tomás</h3>
<p class="story-quote">"The prompts made the first message easy. We haven't stopped talking since."</p>
<p class="story-meta">Met Jan 2024 · Engaged Nov 2025</p>
</div>
</article>
<article class="story-card">
<div class="story-photo photo-c" role="img" aria-label="Rosa and Elena"></div>
<div class="story-body">
<span class="badge">Together</span>
<h3>Rosa & Elena</h3>
<p class="story-quote">"Same values, same weird sense of humor. Kindred just got it right."</p>
<p class="story-meta">Met Aug 2024 · Moved in 2025</p>
</div>
</article>
</div>
</section>
<!-- TESTIMONIAL ROTATOR -->
<section class="testi" aria-labelledby="testiTitle">
<h2 id="testiTitle" class="sr-only">Member testimonials</h2>
<div class="testi-card">
<blockquote id="testiQuote">"I'd deleted every other app. Kindred was the first one that felt like it took me seriously."</blockquote>
<div class="testi-who">
<span class="testi-name" id="testiName">Amara, 31</span>
<span class="testi-role" id="testiRole">joined for something serious</span>
</div>
<div class="testi-dots" id="testiDots" role="tablist" aria-label="Choose testimonial"></div>
</div>
</section>
<!-- PRICING -->
<section class="pricing" id="pricing" aria-labelledby="pricingTitle">
<div class="section-head">
<span class="eyebrow">Honest pricing</span>
<h2 id="pricingTitle">Invest in finding the one</h2>
</div>
<div class="plans">
<article class="plan">
<h3>Free</h3>
<p class="price"><span>$0</span>/mo</p>
<ul class="plan-feats">
<li>Compatibility profile</li>
<li>3 daily matches</li>
<li>Guided icebreakers</li>
</ul>
<a class="btn btn-ghost" href="#join">Start free</a>
</article>
<article class="plan plan-featured">
<span class="plan-flag">Most popular</span>
<h3>Kindred+</h3>
<p class="price"><span>$24</span>/mo</p>
<ul class="plan-feats">
<li>Unlimited daily matches</li>
<li>See who likes you</li>
<li>Read receipts & date planner</li>
<li>Advanced compatibility filters</li>
</ul>
<a class="btn btn-primary" href="#join">Choose Kindred+</a>
</article>
<article class="plan">
<h3>Concierge</h3>
<p class="price"><span>$79</span>/mo</p>
<ul class="plan-feats">
<li>Everything in Kindred+</li>
<li>Dedicated matchmaker</li>
<li>Curated introductions</li>
</ul>
<a class="btn btn-ghost" href="#join">Talk to us</a>
</article>
</div>
</section>
<!-- FINAL CTA -->
<section class="final-cta" id="join">
<div class="cta-card">
<h2>Ready to meet someone who means it?</h2>
<p>Join thousands of people looking for a real relationship this year.</p>
<form class="join-form join-form--big" id="joinForm2" novalidate>
<div class="field">
<label class="sr-only" for="email2">Email address</label>
<input
type="email"
id="email2"
name="email"
inputmode="email"
autocomplete="email"
placeholder="[email protected]"
/>
<button class="btn btn-primary" type="submit">Create my profile</button>
</div>
</form>
<p class="fineprint">By joining you agree to our fictional Terms & Privacy Policy.</p>
</div>
</section>
</main>
<footer class="site-footer">
<p>© 2026 Kindred — a fictional dating brand. Made with care.</p>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>A relationship-focused dating landing page with a warmer, more intentional tone than a typical swipe app. The hero pairs a soft coral-to-violet gradient with a live match-count ticker that animates upward on load, and the primary call to action opens an inline email signup that validates the address and confirms with a toast.
Below the fold, a compatibility teaser card lets visitors move a slider to preview how the matching score responds, a three-step “how it works” row explains the guided flow, and a set of success-story cards feature fictional couples with the date they met and the date they married. A testimonial strip rotates through member quotes automatically and on click, and a transparent pricing block highlights the recommended plan.
Everything is vanilla JS: the ticker, slider preview, testimonial rotation, smooth-scrolling nav, and signup validation all run without dependencies, with visible focus states, aria labelling, and a responsive layout that collapses cleanly on narrow phones.