Dating — Safety Center
A phone-framed dating app Safety Center that pairs swipeable safety-tip cards with a step-by-step report and block walkthrough, a photo-verification call to action, one-tap emergency resources, and an expandable community guidelines accordion — all built with vanilla JS, filter chips, progress tracking, and toast feedback.
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;
--green: #12a67a;
--green-bg: #e7f7f0;
--r-sm: 12px;
--r-md: 20px;
--r-lg: 28px;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
min-height: 100vh;
font-family: Inter, system-ui, sans-serif;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(1000px 500px at 20% -10%, rgba(255, 94, 108, 0.18), transparent 60%),
radial-gradient(900px 500px at 90% 10%, rgba(139, 92, 246, 0.16), transparent 60%),
var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
display: flex;
justify-content: center;
padding: 28px 16px;
}
/* Phone frame */
.phone {
position: relative;
width: 100%;
max-width: 430px;
background: var(--surface);
border-radius: 40px;
box-shadow:
0 2px 0 rgba(255, 255, 255, 0.6) inset,
0 30px 70px -20px rgba(42, 26, 46, 0.35),
0 0 0 8px rgba(42, 26, 46, 0.85),
0 0 0 10px rgba(42, 26, 46, 0.4);
overflow: hidden;
height: min(880px, calc(100vh - 56px));
display: flex;
flex-direction: column;
}
.phone-notch {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
width: 130px;
height: 26px;
background: rgba(42, 26, 46, 0.9);
border-radius: 0 0 16px 16px;
z-index: 6;
}
/* Topbar */
.topbar {
display: flex;
align-items: center;
gap: 10px;
padding: 44px 18px 12px;
background: var(--surface);
border-bottom: 1px solid var(--line);
position: relative;
z-index: 5;
}
.topbar h1 {
margin: 0;
font-size: 18px;
font-weight: 700;
letter-spacing: -0.01em;
flex: 1;
text-align: center;
}
.icon-btn {
width: 38px; height: 38px;
border: 1px solid var(--line);
background: var(--surface);
border-radius: 50%;
display: grid; place-items: center;
cursor: pointer;
color: var(--ink);
transition: background .15s, transform .1s;
}
.icon-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.icon-btn:hover { background: var(--bg); }
.icon-btn:active { transform: scale(.94); }
.shield {
width: 38px; height: 38px;
border-radius: 50%;
display: grid; place-items: center;
background: var(--grad);
color: #fff;
}
.shield svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Scroll area */
.scroll {
flex: 1;
overflow-y: auto;
padding: 16px 18px 8px;
scrollbar-width: thin;
}
.scroll::-webkit-scrollbar { width: 6px; }
.scroll::-webkit-scrollbar-thumb { background: rgba(139, 92, 246, .25); border-radius: 20px; }
/* Hero */
.hero {
position: relative;
border-radius: var(--r-lg);
padding: 22px 20px;
color: #fff;
background: var(--grad);
overflow: hidden;
box-shadow: 0 16px 34px -16px rgba(230, 57, 80, 0.6);
}
.hero-glow {
position: absolute;
width: 220px; height: 220px;
right: -60px; top: -70px;
background: radial-gradient(circle, rgba(255,255,255,.35), transparent 70%);
}
.hero-inner { position: relative; z-index: 1; }
.hero-eyebrow {
margin: 0 0 4px;
font-size: 12px;
font-weight: 600;
letter-spacing: .08em;
text-transform: uppercase;
opacity: .9;
}
.hero h2 {
margin: 0;
font-family: Fraunces, Inter, serif;
font-size: 26px;
font-weight: 700;
letter-spacing: -0.01em;
}
.hero-sub { margin: 6px 0 16px; font-size: 14px; opacity: .95; max-width: 30ch; }
.verify-row {
display: flex;
align-items: center;
gap: 12px;
background: rgba(255, 255, 255, 0.14);
border: 1px solid rgba(255, 255, 255, 0.28);
border-radius: var(--r-md);
padding: 12px 14px;
backdrop-filter: blur(4px);
}
.verify-meta { flex: 1; min-width: 0; }
.verify-badge {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 700;
padding: 3px 9px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.9);
color: var(--coral-d);
}
.verify-badge[data-state="verifying"] { color: var(--violet-d); }
.verify-badge[data-state="verified"] { background: #fff; color: var(--green); }
.verify-badge::before {
content: "";
width: 8px; height: 8px;
border-radius: 50%;
background: currentColor;
}
.verify-note {
display: block;
font-size: 12.5px;
margin-top: 5px;
color: rgba(255, 255, 255, 0.92);
}
.verify-track {
margin-top: 12px;
height: 8px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.25);
overflow: hidden;
}
.verify-track span {
display: block;
height: 100%;
width: 0;
border-radius: 999px;
background: #fff;
transition: width .3s ease;
}
/* Buttons */
.btn {
border: none;
cursor: pointer;
font-family: inherit;
font-weight: 700;
font-size: 14px;
border-radius: 999px;
padding: 11px 18px;
transition: transform .12s, box-shadow .2s, background .2s, color .2s;
white-space: nowrap;
}
.btn:active { transform: scale(.96); }
.btn-glass {
background: #fff;
color: var(--coral-d);
box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.4);
}
.btn-glass:hover { box-shadow: 0 10px 22px -8px rgba(0, 0, 0, 0.5); }
.btn-primary {
background: var(--grad);
color: #fff;
box-shadow: 0 10px 22px -10px rgba(230, 57, 80, 0.7);
}
.btn-primary:hover { filter: brightness(1.04); }
.btn-outline {
background: var(--surface);
color: var(--violet-d);
border: 1.5px solid rgba(139, 92, 246, 0.4);
}
.btn-outline:hover { background: rgba(139, 92, 246, 0.06); }
/* Block sections */
.block { margin-top: 24px; }
.block-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.block-head h3 {
margin: 0;
font-size: 17px;
font-weight: 700;
letter-spacing: -0.01em;
}
.count-pill {
font-size: 12px;
font-weight: 600;
color: var(--violet-d);
background: rgba(139, 92, 246, 0.12);
padding: 4px 10px;
border-radius: 999px;
}
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 16px;
box-shadow: 0 10px 24px -18px rgba(42, 26, 46, 0.4);
}
/* Chips */
.chips {
display: flex;
gap: 8px;
overflow-x: auto;
padding-bottom: 4px;
margin-bottom: 12px;
scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }
.chip {
flex: 0 0 auto;
border: 1.5px solid var(--line);
background: var(--surface);
color: var(--ink-2);
font-family: inherit;
font-size: 13px;
font-weight: 600;
padding: 8px 14px;
border-radius: 999px;
cursor: pointer;
transition: all .15s;
}
.chip:hover { border-color: var(--pink); color: var(--ink); }
.chip.is-active {
background: var(--grad);
color: #fff;
border-color: transparent;
box-shadow: 0 8px 16px -10px rgba(230, 57, 80, 0.7);
}
/* Tips */
.tips { display: flex; flex-direction: column; gap: 10px; }
.tip {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
transition: box-shadow .2s, transform .2s, opacity .25s;
}
.tip.hide { display: none; }
.tip:hover { box-shadow: 0 12px 26px -18px rgba(139, 92, 246, 0.5); }
.tip.open { box-shadow: 0 14px 30px -16px rgba(139, 92, 246, 0.5); }
.tip-head {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
border: none;
background: transparent;
cursor: pointer;
padding: 14px;
text-align: left;
font-family: inherit;
color: var(--ink);
}
.tip-ico {
width: 42px; height: 42px;
flex: 0 0 auto;
border-radius: 14px;
display: grid; place-items: center;
font-size: 20px;
background: linear-gradient(135deg, rgba(255,94,108,.14), rgba(139,92,246,.14));
}
.tip-ico::before { content: attr(data-emoji); }
.tip-title {
flex: 1;
font-size: 15px;
font-weight: 600;
line-height: 1.3;
}
.tip-title em {
display: block;
font-style: normal;
font-size: 12px;
font-weight: 600;
color: var(--muted);
margin-top: 2px;
}
.tip-caret {
width: 22px; height: 22px;
flex: 0 0 auto;
position: relative;
transition: transform .25s;
}
.tip-caret::before, .tip-caret::after {
content: "";
position: absolute;
top: 50%; left: 50%;
width: 10px; height: 2px;
background: var(--muted);
border-radius: 2px;
transform: translate(-50%, -50%);
}
.tip-caret::after { transform: translate(-50%, -50%) rotate(90deg); transition: transform .25s; }
.tip.open .tip-caret::after { transform: translate(-50%, -50%) rotate(0); }
.tip-body {
max-height: 0;
overflow: hidden;
transition: max-height .3s ease;
}
.tip-body p {
margin: 0;
padding: 0 14px 16px 68px;
font-size: 13.5px;
color: var(--ink-2);
}
.empty {
text-align: center;
color: var(--muted);
font-size: 14px;
padding: 20px 0;
}
/* Steps */
.steps ol {
list-style: none;
margin: 0 0 14px;
padding: 0;
display: flex;
flex-direction: column;
gap: 14px;
}
.steps li { display: flex; gap: 12px; }
.step-n {
flex: 0 0 auto;
width: 28px; height: 28px;
border-radius: 50%;
background: var(--grad);
color: #fff;
font-size: 13px;
font-weight: 700;
display: grid; place-items: center;
}
.steps li strong { font-size: 14.5px; }
.steps li p { margin: 2px 0 0; font-size: 13px; color: var(--ink-2); }
.steps-cta { display: flex; gap: 10px; }
.steps-cta .btn { flex: 1; }
/* Emergency */
.emergency {
background: var(--green-bg);
border-color: rgba(18, 166, 122, 0.3);
}
.emg-lead {
margin: 0 0 12px;
font-size: 13.5px;
font-weight: 600;
color: #0c7a58;
}
.emg-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.emg-list li {
display: flex;
align-items: center;
gap: 10px;
background: #fff;
border: 1px solid rgba(18, 166, 122, 0.18);
border-radius: var(--r-sm);
padding: 10px 12px;
}
.emg-info { flex: 1; min-width: 0; }
.emg-info strong { display: block; font-size: 14px; }
.emg-info span { font-size: 12px; color: var(--muted); }
.emg-call {
flex: 0 0 auto;
border: none;
cursor: pointer;
font-family: inherit;
font-weight: 700;
font-size: 13px;
color: #fff;
background: var(--green);
padding: 8px 16px;
border-radius: 999px;
transition: transform .12s, filter .2s;
}
.emg-call:hover { filter: brightness(1.06); }
.emg-call:active { transform: scale(.95); }
/* Accordion */
.accordion { display: flex; flex-direction: column; gap: 8px; }
.acc-item {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-sm);
overflow: hidden;
}
.acc-head {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
border: none;
background: transparent;
cursor: pointer;
padding: 14px;
font-family: inherit;
font-size: 14.5px;
font-weight: 600;
color: var(--ink);
text-align: left;
}
.acc-head:hover { background: var(--bg); }
.acc-icon {
width: 20px; height: 20px;
flex: 0 0 auto;
position: relative;
}
.acc-icon::before, .acc-icon::after {
content: "";
position: absolute;
top: 50%; left: 50%;
background: var(--violet);
border-radius: 2px;
transform: translate(-50%, -50%);
}
.acc-icon::before { width: 12px; height: 2px; }
.acc-icon::after { width: 2px; height: 12px; transition: transform .25s; }
.acc-item.open .acc-icon::after { transform: translate(-50%, -50%) rotate(90deg); }
.acc-panel {
max-height: 0;
overflow: hidden;
transition: max-height .3s ease;
}
.acc-panel p {
margin: 0;
padding: 0 14px 14px;
font-size: 13.5px;
color: var(--ink-2);
}
/* Footer */
.foot {
text-align: center;
font-size: 12px;
color: var(--muted);
padding: 24px 0 20px;
}
/* Focus */
:focus-visible {
outline: 3px solid var(--violet);
outline-offset: 2px;
border-radius: 12px;
}
.hero :focus-visible { outline-color: #fff; }
/* Toast */
.toast {
position: fixed;
left: 50%;
bottom: 32px;
transform: translate(-50%, 20px);
background: var(--ink);
color: #fff;
font-size: 13.5px;
font-weight: 600;
padding: 12px 18px;
border-radius: 999px;
box-shadow: 0 16px 34px -14px rgba(0, 0, 0, 0.5);
opacity: 0;
pointer-events: none;
transition: opacity .25s, transform .25s;
z-index: 40;
max-width: 88vw;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
@media (max-width: 520px) {
body { padding: 0; }
.phone {
max-width: 100%;
height: 100vh;
border-radius: 0;
box-shadow: none;
}
.phone-notch { display: none; }
.topbar { padding-top: 18px; }
.hero h2 { font-size: 23px; }
.verify-row { flex-direction: column; align-items: stretch; }
.btn-glass { width: 100%; }
.steps-cta { flex-direction: column; }
.tip-body p { padding-left: 14px; }
}
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; }
}(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");
}, 2400);
}
/* ---------- Verification CTA ---------- */
var verifyBtn = document.getElementById("verifyBtn");
var verifyBadge = document.getElementById("verifyBadge");
var verifyNote = document.getElementById("verifyNote");
var verifyTrack = document.getElementById("verifyTrack");
var verifyFill = document.getElementById("verifyFill");
var verifying = false;
verifyBtn.addEventListener("click", function () {
if (verifying || verifyBadge.getAttribute("data-state") === "verified") {
if (verifyBadge.getAttribute("data-state") === "verified") {
toast("You're already verified ✨");
}
return;
}
verifying = true;
verifyBtn.disabled = true;
verifyBtn.textContent = "Scanning…";
verifyBadge.setAttribute("data-state", "verifying");
verifyBadge.textContent = "Verifying";
verifyNote.textContent = "Matching your selfie to your photos…";
verifyTrack.hidden = false;
var pct = 0;
var iv = setInterval(function () {
pct = Math.min(100, pct + Math.random() * 22 + 8);
verifyFill.style.width = pct + "%";
if (pct >= 100) {
clearInterval(iv);
verifyBadge.setAttribute("data-state", "verified");
verifyBadge.textContent = "Verified";
verifyNote.textContent = "A blue check now shows on your profile.";
verifyBtn.textContent = "Verified ✓";
toast("Profile verified — nicely done!");
setTimeout(function () { verifyTrack.hidden = true; }, 600);
}
}, 380);
});
/* ---------- Tip filter chips ---------- */
var chips = Array.prototype.slice.call(document.querySelectorAll(".chip"));
var tips = Array.prototype.slice.call(document.querySelectorAll(".tip"));
var tipCount = document.getElementById("tipCount");
var tipEmpty = document.getElementById("tipEmpty");
function applyFilter(filter) {
var shown = 0;
tips.forEach(function (tip) {
var match = filter === "all" || tip.getAttribute("data-cat") === filter;
tip.classList.toggle("hide", !match);
if (match) shown++;
});
tipCount.textContent = shown + (shown === 1 ? " tip" : " tips");
tipEmpty.hidden = shown !== 0;
}
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) {
c.classList.remove("is-active");
c.setAttribute("aria-selected", "false");
});
chip.classList.add("is-active");
chip.setAttribute("aria-selected", "true");
applyFilter(chip.getAttribute("data-filter"));
});
});
/* ---------- Expandable tip cards ---------- */
tips.forEach(function (tip) {
var head = tip.querySelector(".tip-head");
var body = tip.querySelector(".tip-body");
head.addEventListener("click", function () {
var open = tip.classList.toggle("open");
head.setAttribute("aria-expanded", open ? "true" : "false");
body.style.maxHeight = open ? body.scrollHeight + "px" : "0";
});
});
/* ---------- Report & block ---------- */
document.getElementById("reportBtn").addEventListener("click", function () {
toast("Report started — our Trust team reviews within 24h.");
});
document.getElementById("blockBtn").addEventListener("click", function () {
toast("Blocking is instant and silent. Stay safe 💜");
});
/* ---------- Emergency actions ---------- */
Array.prototype.slice.call(document.querySelectorAll(".emg-call")).forEach(function (btn) {
btn.addEventListener("click", function () {
var num = btn.getAttribute("data-number");
var label = btn.textContent.trim().toLowerCase();
if (label === "copy") {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(num).then(function () {
toast("Copied " + num + " to clipboard.");
}, function () {
toast("Number: " + num);
});
} else {
toast("Number: " + num);
}
} else {
toast("Dialing " + num + "…");
}
});
});
/* ---------- Community guidelines accordion (single-open) ---------- */
var accItems = Array.prototype.slice.call(document.querySelectorAll(".acc-item"));
accItems.forEach(function (item) {
var head = item.querySelector(".acc-head");
var panel = item.querySelector(".acc-panel");
head.addEventListener("click", function () {
var willOpen = !item.classList.contains("open");
accItems.forEach(function (other) {
other.classList.remove("open");
other.querySelector(".acc-head").setAttribute("aria-expanded", "false");
other.querySelector(".acc-panel").style.maxHeight = "0";
});
if (willOpen) {
item.classList.add("open");
head.setAttribute("aria-expanded", "true");
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Safety Center — Sparkle</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],600;9..144,700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="phone" role="region" aria-label="Sparkle Safety Center">
<div class="phone-notch" aria-hidden="true"></div>
<header class="topbar">
<button class="icon-btn" aria-label="Go back">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
</button>
<h1>Safety Center</h1>
<span class="shield" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M12 2l8 3v6c0 5-3.4 8.5-8 11-4.6-2.5-8-6-8-11V5z"/><path d="M9 12l2 2 4-4"/></svg>
</span>
</header>
<main class="scroll">
<!-- Hero / verification -->
<section class="hero">
<div class="hero-glow" aria-hidden="true"></div>
<div class="hero-inner">
<p class="hero-eyebrow">Your safety, first</p>
<h2>Date with confidence</h2>
<p class="hero-sub">Get verified, learn the essentials, and keep help one tap away.</p>
<div class="verify-row">
<div class="verify-meta">
<span class="verify-badge" id="verifyBadge" data-state="unverified">Not verified</span>
<span class="verify-note" id="verifyNote">Add a blue check to your profile</span>
</div>
<button class="btn btn-glass" id="verifyBtn">Verify me</button>
</div>
<div class="verify-track" id="verifyTrack" hidden aria-hidden="true"><span id="verifyFill"></span></div>
</div>
</section>
<!-- Safety tips -->
<section class="block">
<div class="block-head">
<h3>Safety tips</h3>
<span class="count-pill" id="tipCount">6 tips</span>
</div>
<div class="chips" role="tablist" aria-label="Filter safety tips">
<button class="chip is-active" role="tab" aria-selected="true" data-filter="all">All</button>
<button class="chip" role="tab" aria-selected="false" data-filter="before">Before you meet</button>
<button class="chip" role="tab" aria-selected="false" data-filter="date">On the date</button>
<button class="chip" role="tab" aria-selected="false" data-filter="online">Online</button>
</div>
<div class="tips" id="tips">
<article class="tip" data-cat="online">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="💬"></span>
<span class="tip-title">Keep chats on the app<em>Online safety</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>Scammers push to move to text or WhatsApp fast. Stay in Sparkle chat until you truly trust someone — our filters flag suspicious links and requests here.</p></div>
</article>
<article class="tip" data-cat="before">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="🔍"></span>
<span class="tip-title">Video call before meeting<em>Before you meet</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>A quick 5-minute video chat confirms your match looks like their photos and helps you read the vibe before committing to an in-person date.</p></div>
</article>
<article class="tip" data-cat="before">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="📍"></span>
<span class="tip-title">Tell a friend your plan<em>Before you meet</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>Share where you're going and who you're meeting. Use Sparkle's live location share so a trusted friend can check in on you.</p></div>
</article>
<article class="tip" data-cat="date">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="☕"></span>
<span class="tip-title">Meet in a public place<em>On the date</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>Pick a busy café, bar, or park for a first date. Skip private homes or remote spots until you've met a few times and feel comfortable.</p></div>
</article>
<article class="tip" data-cat="date">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="🚗"></span>
<span class="tip-title">Own your transport<em>On the date</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>Arrange your own way there and back so you can leave whenever you want. Keep your phone charged and don't leave drinks unattended.</p></div>
</article>
<article class="tip" data-cat="online">
<button class="tip-head" aria-expanded="false">
<span class="tip-ico" data-emoji="🛡️"></span>
<span class="tip-title">Guard personal details<em>Online safety</em></span>
<span class="tip-caret" aria-hidden="true"></span>
</button>
<div class="tip-body"><p>Never share your home address, workplace, or financial info early on. No genuine match will ever ask you to send money or gift cards.</p></div>
</article>
</div>
<p class="empty" id="tipEmpty" hidden>No tips in this filter.</p>
</section>
<!-- Report & block -->
<section class="block">
<div class="block-head"><h3>Report & block</h3></div>
<div class="steps card">
<ol>
<li>
<span class="step-n">1</span>
<div><strong>Open their profile</strong><p>Tap the menu (•••) in the top-right of any profile or chat.</p></div>
</li>
<li>
<span class="step-n">2</span>
<div><strong>Choose Report or Block</strong><p>Pick a reason — harassment, fake profile, or off-platform behaviour.</p></div>
</li>
<li>
<span class="step-n">3</span>
<div><strong>We take it from here</strong><p>Blocking is instant and silent. Our Trust team reviews every report within 24 hours.</p></div>
</li>
</ol>
<div class="steps-cta">
<button class="btn btn-outline" id="reportBtn">Report a profile</button>
<button class="btn btn-primary" id="blockBtn">Block someone</button>
</div>
</div>
</section>
<!-- Emergency -->
<section class="block">
<div class="block-head"><h3>Emergency resources</h3></div>
<div class="emergency card">
<p class="emg-lead">In immediate danger? Contact local authorities right away.</p>
<ul class="emg-list">
<li>
<div class="emg-info"><strong>Emergency services</strong><span>Police · Fire · Medical</span></div>
<button class="emg-call" data-number="911" aria-label="Call emergency services 911">911</button>
</li>
<li>
<div class="emg-info"><strong>Sexual Assault Hotline</strong><span>RAINN · 24/7 confidential</span></div>
<button class="emg-call" data-number="1-800-656-4673" aria-label="Call sexual assault hotline">Call</button>
</li>
<li>
<div class="emg-info"><strong>Crisis Text Line</strong><span>Text HOME to 741741</span></div>
<button class="emg-call" data-number="741741" aria-label="Copy crisis text line number">Copy</button>
</li>
</ul>
</div>
</section>
<!-- Community guidelines -->
<section class="block">
<div class="block-head"><h3>Community guidelines</h3></div>
<div class="accordion" id="accordion">
<div class="acc-item">
<button class="acc-head" aria-expanded="false"><span>Be authentic</span><span class="acc-icon" aria-hidden="true"></span></button>
<div class="acc-panel"><p>Use recent photos of yourself and honest info. Impersonation, catfishing, and fake profiles get removed permanently.</p></div>
</div>
<div class="acc-item">
<button class="acc-head" aria-expanded="false"><span>Be respectful</span><span class="acc-icon" aria-hidden="true"></span></button>
<div class="acc-panel"><p>No harassment, hate speech, or unsolicited explicit content. Treat every match the way you'd want to be treated.</p></div>
</div>
<div class="acc-item">
<button class="acc-head" aria-expanded="false"><span>Keep it safe</span><span class="acc-icon" aria-hidden="true"></span></button>
<div class="acc-panel"><p>No solicitation, scams, or requests for money. Report anyone who pressures you off-platform or asks for financial help.</p></div>
</div>
<div class="acc-item">
<button class="acc-head" aria-expanded="false"><span>18+ only</span><span class="acc-icon" aria-hidden="true"></span></button>
<div class="acc-panel"><p>Sparkle is strictly for adults. Accounts belonging to minors are banned and reported to the appropriate authorities.</p></div>
</div>
</div>
</section>
<footer class="foot">Sparkle Trust & Safety · Here for you 24/7</footer>
</main>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>The Dating Safety Center is a mobile-first screen, wrapped in a ~430px phone frame, that gives members everything they need to date safely in one scrollable place. A gradient hero surfaces a verification prompt, filter chips (All, Before you meet, On the date, Online), let people narrow the safety-tip cards, and each tip expands inline to reveal a fuller explanation. A staged report and block panel walks users through the three-step flow, and a green emergency block pins quick-dial resources front and center.
Interactions are all vanilla JS: tapping a chip filters the tip grid with a smooth fade, the verification CTA runs a fake progress animation and updates a status badge, and the community guidelines render as an accessible accordion where only one panel opens at a time. A small toast helper confirms actions like starting verification or copying a hotline number, and every control is keyboard-operable with visible focus rings.
The layout stays legible down to 360px, respects WCAG AA contrast against the pink-and-violet palette, and uses aria attributes on the accordion, chips, and expandable cards so screen readers can follow along.