Dental — Smile Gallery
A trust-first before/after smile gallery for dental clinics: filterable case cards each with a draggable comparison slider that wipes between the before and after photos, a treatment tag, tooth-shade and visit-count meta, and a keyboard-accessible reveal handle. Filter chips narrow cases by treatment — whitening, veneers, aligners, implants — with a live result count, empty state, and soft clinical styling built for reassurance.
MCP
Code
:root {
--blue: #2563eb;
--blue-d: #1d4ed8;
--blue-50: #eff5ff;
--mint: #34d399;
--mint-50: #e8fbf3;
--ink: #0f2740;
--ink-2: #3a5169;
--muted: #6b7c90;
--bg: #f3f8ff;
--white: #fff;
--line: rgba(15, 39, 64, 0.10);
--line-2: rgba(15, 39, 64, 0.18);
--ok: #22b07d;
--warn: #d98a2b;
--danger: #e05252;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--shadow-sm: 0 2px 8px rgba(15, 39, 64, 0.06);
--shadow-md: 0 12px 30px rgba(15, 39, 64, 0.10);
--shadow-lg: 0 22px 55px rgba(15, 39, 64, 0.14);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(1200px 600px at 15% -10%, #e8f1ff 0%, transparent 60%),
radial-gradient(1000px 500px at 100% 0%, var(--mint-50) 0%, transparent 55%),
var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
.wrap {
max-width: 1120px;
margin: 0 auto;
padding: 28px 22px 56px;
}
/* ---------- Masthead ---------- */
.masthead {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand__mark {
width: 44px;
height: 44px;
display: grid;
place-items: center;
color: var(--white);
background: linear-gradient(150deg, var(--blue), var(--blue-d));
border-radius: 13px;
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.30);
}
.brand__name {
margin: 0;
font-weight: 800;
font-size: 1.02rem;
letter-spacing: -0.01em;
}
.brand__sub {
margin: 0;
font-size: 0.78rem;
color: var(--muted);
font-weight: 500;
}
.pill {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 0.76rem;
font-weight: 600;
padding: 7px 13px;
border-radius: 999px;
background: var(--white);
border: 1px solid var(--line);
box-shadow: var(--shadow-sm);
color: var(--ink-2);
}
.pill--ok { color: #17845c; }
.dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--ok);
box-shadow: 0 0 0 4px rgba(34, 176, 125, 0.16);
}
/* ---------- Intro ---------- */
.intro { margin: 30px 0 20px; }
.intro h1 {
margin: 0 0 6px;
font-size: clamp(1.55rem, 4vw, 2.15rem);
font-weight: 800;
letter-spacing: -0.025em;
}
.intro p {
margin: 0;
color: var(--ink-2);
max-width: 52ch;
font-size: 0.98rem;
}
/* ---------- Toolbar / chips ---------- */
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
margin-bottom: 22px;
}
.chips {
display: flex;
gap: 9px;
flex-wrap: wrap;
}
.chip {
font: inherit;
font-size: 0.86rem;
font-weight: 600;
color: var(--ink-2);
background: var(--white);
border: 1px solid var(--line-2);
padding: 9px 15px;
border-radius: 999px;
cursor: pointer;
transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease,
border-color 0.15s ease, box-shadow 0.15s ease;
}
.chip:hover {
border-color: var(--blue);
color: var(--blue-d);
transform: translateY(-1px);
}
.chip.is-active {
background: linear-gradient(150deg, var(--blue), var(--blue-d));
border-color: transparent;
color: var(--white);
box-shadow: 0 8px 18px rgba(37, 99, 235, 0.28);
}
.chip:focus-visible {
outline: 3px solid rgba(37, 99, 235, 0.45);
outline-offset: 2px;
}
.count {
margin: 0;
font-size: 0.82rem;
font-weight: 600;
color: var(--muted);
white-space: nowrap;
}
/* ---------- Grid ---------- */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 22px;
}
.card {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--shadow-sm);
transition: transform 0.22s ease, box-shadow 0.22s ease;
display: flex;
flex-direction: column;
animation: rise 0.4s ease both;
}
.card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
@keyframes rise {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
/* ---------- Compare viewer ---------- */
.compare {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
touch-action: none;
user-select: none;
cursor: ew-resize;
background: #dfeaf7;
}
.compare__img {
position: absolute;
inset: 0;
display: grid;
place-items: end center;
padding-bottom: 16px;
background-size: cover;
background-position: center;
}
.compare__after {
/* revealed layer sits underneath, clipped by the before layer */
}
.compare__before {
clip-path: inset(0 calc(100% - var(--pos, 50%)) 0 0);
}
.tag {
position: absolute;
top: 12px;
left: 12px;
z-index: 4;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.01em;
padding: 6px 11px;
border-radius: 999px;
color: var(--ink);
background: rgba(255, 255, 255, 0.86);
backdrop-filter: blur(6px);
border: 1px solid rgba(255, 255, 255, 0.7);
box-shadow: var(--shadow-sm);
}
.tag__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--blue);
}
.label {
position: absolute;
bottom: 12px;
z-index: 3;
font-size: 0.68rem;
font-weight: 800;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: var(--r-sm);
color: var(--white);
background: rgba(15, 39, 64, 0.55);
backdrop-filter: blur(4px);
}
.label--before { left: 12px; }
.label--after { right: 12px; }
/* handle */
.handle {
position: absolute;
top: 0;
bottom: 0;
left: var(--pos, 50%);
width: 3px;
transform: translateX(-50%);
background: var(--white);
z-index: 5;
box-shadow: 0 0 0 1px rgba(15, 39, 64, 0.12);
}
.handle__grip {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--white);
border: 0;
cursor: ew-resize;
display: grid;
place-items: center;
color: var(--blue-d);
box-shadow: var(--shadow-md);
transition: transform 0.15s ease;
}
.handle__grip:hover { transform: translate(-50%, -50%) scale(1.08); }
.handle__grip:focus-visible {
outline: 3px solid rgba(37, 99, 235, 0.5);
outline-offset: 3px;
}
.handle__grip svg { width: 20px; height: 20px; }
/* ---------- Card body ---------- */
.card__body {
padding: 15px 17px 17px;
display: flex;
flex-direction: column;
gap: 12px;
flex: 1;
}
.card__top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
}
.card__name {
margin: 0;
font-size: 1.02rem;
font-weight: 700;
letter-spacing: -0.01em;
}
.card__where {
margin: 2px 0 0;
font-size: 0.78rem;
color: var(--muted);
font-weight: 500;
}
.rating {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 0.8rem;
font-weight: 700;
color: var(--warn);
white-space: nowrap;
}
.meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.74rem;
font-weight: 600;
padding: 5px 10px;
border-radius: 999px;
background: var(--blue-50);
color: var(--blue-d);
border: 1px solid rgba(37, 99, 235, 0.14);
}
.badge--mint {
background: var(--mint-50);
color: #17845c;
border-color: rgba(34, 176, 125, 0.18);
}
.shade {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 0.74rem;
font-weight: 600;
color: var(--ink-2);
padding: 5px 10px 5px 6px;
border-radius: 999px;
background: var(--white);
border: 1px solid var(--line-2);
}
.swatch {
width: 16px;
height: 16px;
border-radius: 5px;
border: 1px solid rgba(15, 39, 64, 0.12);
}
.shade__arrow { color: var(--muted); font-weight: 700; }
.quote {
margin: 0;
font-size: 0.85rem;
color: var(--ink-2);
line-height: 1.55;
padding-left: 11px;
border-left: 3px solid var(--mint);
}
/* ---------- Empty state ---------- */
.empty {
text-align: center;
padding: 56px 20px;
background: var(--white);
border: 1px dashed var(--line-2);
border-radius: var(--r-lg);
}
.empty__icon { font-size: 2rem; }
.empty__title {
margin: 12px 0 4px;
font-weight: 700;
font-size: 1.05rem;
}
.empty__sub {
margin: 0 0 18px;
color: var(--muted);
font-size: 0.9rem;
}
.btn {
font: inherit;
font-weight: 600;
font-size: 0.9rem;
color: var(--white);
background: linear-gradient(150deg, var(--blue), var(--blue-d));
border: 0;
padding: 11px 20px;
border-radius: 999px;
cursor: pointer;
box-shadow: 0 8px 18px rgba(37, 99, 235, 0.28);
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:hover { transform: translateY(-1px); box-shadow: 0 12px 24px rgba(37, 99, 235, 0.32); }
.btn:focus-visible { outline: 3px solid rgba(37, 99, 235, 0.5); outline-offset: 2px; }
/* ---------- Footer ---------- */
.foot {
margin-top: 34px;
text-align: center;
}
.foot p {
margin: 0;
font-size: 0.78rem;
color: var(--muted);
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 26px);
background: var(--ink);
color: var(--white);
font-size: 0.85rem;
font-weight: 500;
padding: 11px 18px;
border-radius: 999px;
box-shadow: var(--shadow-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 40;
}
.toast.is-show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ---------- Responsive ---------- */
@media (max-width: 520px) {
.wrap { padding: 20px 15px 44px; }
.intro { margin: 22px 0 16px; }
.grid { grid-template-columns: 1fr; gap: 18px; }
.toolbar { align-items: flex-start; }
.count { width: 100%; }
.chips { gap: 7px; }
.chip { font-size: 0.8rem; padding: 8px 13px; }
.brand__sub { display: none; }
}
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}(function () {
"use strict";
/* ---------- Data (fictional but realistic) ---------- */
var CASES = [
{
id: 1,
name: "Maya R.",
where: "Composite veneers · 2 visits",
treatment: "veneers",
tlabel: "Porcelain veneers",
visits: 2,
rating: "5.0",
shadeFrom: "#cbbf9a",
shadeTo: "#f3ece0",
quote: "I finally stopped hiding my smile in photos — the shape looks completely natural.",
before: "linear-gradient(160deg,#b9a888,#8f7f63)",
after: "linear-gradient(160deg,#f6f0e6,#e2d9c8)"
},
{
id: 2,
name: "Dev P.",
where: "In-office whitening · 1 visit",
treatment: "whitening",
tlabel: "Whitening",
visits: 1,
rating: "4.9",
shadeFrom: "#d8c79f",
shadeTo: "#f7f2ea",
quote: "One appointment and my teeth were several shades brighter. Zero sensitivity.",
before: "linear-gradient(160deg,#cbb98d,#a99a70)",
after: "linear-gradient(160deg,#faf6ee,#eae2d2)"
},
{
id: 3,
name: "Aisha K.",
where: "Clear aligners · 9 months",
treatment: "aligners",
tlabel: "Clear aligners",
visits: 7,
rating: "5.0",
shadeFrom: "#e6ddc9",
shadeTo: "#f2ebdd",
quote: "The crowding on my lower teeth is gone. Nobody even noticed I was wearing them.",
before: "linear-gradient(160deg,#d9cdb2,#c0b391)",
after: "linear-gradient(160deg,#f4eedf,#e6ddc7)"
},
{
id: 4,
name: "Liam O.",
where: "Edge bonding · 1 visit",
treatment: "bonding",
tlabel: "Composite bonding",
visits: 1,
rating: "4.8",
shadeFrom: "#e2d6bd",
shadeTo: "#f4efe4",
quote: "They filled the little chip on my front tooth in an hour — you can't tell at all.",
before: "linear-gradient(160deg,#ddceac,#c4b48d)",
after: "linear-gradient(160deg,#f5f0e6,#e7ded0)"
},
{
id: 5,
name: "Sofia M.",
where: "Single implant + crown · 3 visits",
treatment: "implants",
tlabel: "Dental implant",
visits: 3,
rating: "5.0",
shadeFrom: "#d3c4a2",
shadeTo: "#f1eadd",
quote: "The gap from my missing molar is filled and it feels just like a real tooth.",
before: "linear-gradient(160deg,#cebf9a,#b0a179)",
after: "linear-gradient(160deg,#f2ece0,#e3dac8)"
},
{
id: 6,
name: "Noah T.",
where: "Whitening + bonding · 2 visits",
treatment: "whitening",
tlabel: "Whitening",
visits: 2,
rating: "4.9",
shadeFrom: "#d6c69c",
shadeTo: "#f6f1e8",
quote: "Coffee had really dulled my smile. This brought back the brightness instantly.",
before: "linear-gradient(160deg,#c9b787,#a7976d)",
after: "linear-gradient(160deg,#f9f4ec,#e9e0d0)"
}
];
var TREATMENT_LABELS = {
all: "all cases",
whitening: "whitening",
veneers: "veneers",
aligners: "clear aligners",
bonding: "bonding",
implants: "implants"
};
var grid = document.getElementById("grid");
var chipsWrap = document.getElementById("chips");
var countEl = document.getElementById("count");
var emptyEl = document.getElementById("empty");
var resetBtn = document.getElementById("resetBtn");
var toastEl = document.getElementById("toast");
var current = "all";
var toastTimer;
/* ---------- Toast helper ---------- */
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2200);
}
function esc(s) {
return String(s).replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
/* ---------- Card template ---------- */
function cardMarkup(c) {
return (
'<article class="card" data-treatment="' + c.treatment + '">' +
'<div class="compare" style="--pos:50%">' +
'<div class="compare__img compare__after" style="background:' + c.after + '"></div>' +
'<div class="compare__before" data-before style="background:' + c.before + '"></div>' +
'<span class="tag"><span class="tag__dot"></span>' + esc(c.tlabel) + "</span>" +
'<span class="label label--before">Before</span>' +
'<span class="label label--after">After</span>' +
'<div class="handle" data-handle>' +
'<button class="handle__grip" type="button" role="slider" ' +
'aria-label="Reveal ' + esc(c.name) + ' after photo" ' +
'aria-valuemin="0" aria-valuemax="100" aria-valuenow="50" tabindex="0">' +
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 6 3 12l6 6M15 6l6 6-6 6"/></svg>' +
"</button>" +
"</div>" +
"</div>" +
'<div class="card__body">' +
'<div class="card__top">' +
"<div>" +
'<h3 class="card__name">' + esc(c.name) + "</h3>" +
'<p class="card__where">' + esc(c.where) + "</p>" +
"</div>" +
'<span class="rating">★ ' + esc(c.rating) + "</span>" +
"</div>" +
'<div class="meta">' +
'<span class="badge badge--mint">' + c.visits + " visit" + (c.visits > 1 ? "s" : "") + "</span>" +
'<span class="shade">' +
'<span class="swatch" style="background:' + c.shadeFrom + '"></span>' +
'<span class="shade__arrow">→</span>' +
'<span class="swatch" style="background:' + c.shadeTo + '"></span>' +
"Shade" +
"</span>" +
"</div>" +
'<p class="quote">' + esc(c.quote) + "</p>" +
"</div>" +
"</article>"
);
}
/* ---------- Render ---------- */
function render(list) {
grid.innerHTML = list.map(cardMarkup).join("");
if (list.length === 0) {
grid.hidden = true;
emptyEl.hidden = false;
} else {
grid.hidden = false;
emptyEl.hidden = true;
wireSliders();
}
countEl.textContent = "Showing " + list.length + " of " + CASES.length + " cases";
}
function filterBy(treatment) {
current = treatment;
var list = treatment === "all"
? CASES.slice()
: CASES.filter(function (c) { return c.treatment === treatment; });
render(list);
Array.prototype.forEach.call(chipsWrap.querySelectorAll(".chip"), function (chip) {
var active = chip.getAttribute("data-treatment") === treatment;
chip.classList.toggle("is-active", active);
chip.setAttribute("aria-pressed", active ? "true" : "false");
});
if (list.length === 0) {
toast("No " + TREATMENT_LABELS[treatment] + " cases yet");
} else {
toast("Showing " + list.length + " " + TREATMENT_LABELS[treatment] + " case" + (list.length > 1 ? "s" : ""));
}
}
/* ---------- Slider wiring ---------- */
function setPos(compare, pct) {
pct = Math.max(0, Math.min(100, pct));
compare.style.setProperty("--pos", pct + "%");
var grip = compare.querySelector(".handle__grip");
if (grip) grip.setAttribute("aria-valuenow", Math.round(pct));
}
function wireSliders() {
Array.prototype.forEach.call(grid.querySelectorAll(".compare"), function (compare) {
var dragging = false;
function pctFromEvent(e) {
var rect = compare.getBoundingClientRect();
var x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;
return (x / rect.width) * 100;
}
function onMove(e) {
if (!dragging) return;
if (e.cancelable) e.preventDefault();
setPos(compare, pctFromEvent(e));
}
function start(e) {
dragging = true;
setPos(compare, pctFromEvent(e));
}
function end() { dragging = false; }
compare.addEventListener("pointerdown", function (e) {
start(e);
compare.setPointerCapture && compare.setPointerCapture(e.pointerId);
});
compare.addEventListener("pointermove", onMove);
compare.addEventListener("pointerup", end);
compare.addEventListener("pointercancel", end);
/* keyboard on the grip */
var grip = compare.querySelector(".handle__grip");
grip.addEventListener("keydown", function (e) {
var cur = parseFloat(compare.style.getPropertyValue("--pos")) || 50;
var step = e.shiftKey ? 10 : 4;
if (e.key === "ArrowLeft" || e.key === "ArrowDown") { setPos(compare, cur - step); e.preventDefault(); }
else if (e.key === "ArrowRight" || e.key === "ArrowUp") { setPos(compare, cur + step); e.preventDefault(); }
else if (e.key === "Home") { setPos(compare, 0); e.preventDefault(); }
else if (e.key === "End") { setPos(compare, 100); e.preventDefault(); }
});
/* prevent the button click from also moving the slider awkwardly */
grip.addEventListener("pointerdown", function (e) { e.stopPropagation(); dragging = true; });
});
}
/* ---------- Events ---------- */
chipsWrap.addEventListener("click", function (e) {
var chip = e.target.closest(".chip");
if (!chip) return;
var t = chip.getAttribute("data-treatment");
if (t !== current) filterBy(t);
});
resetBtn.addEventListener("click", function () { filterBy("all"); });
/* ---------- Init ---------- */
render(CASES.slice());
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bright Harbor Dental — Smile Gallery</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&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="wrap">
<header class="masthead">
<div class="brand">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 5.5C10 3.5 6.5 3.2 5 5.2 3.4 7.3 4 11 5.4 14.3c.6 1.4 1.1 3 1.5 4.4.3 1.1 1.8 1.2 2.1.1l.7-2.6c.3-1 1.3-1 1.6 0l.7 2.6c.3 1.1 1.8 1 2.1-.1.4-1.4.9-3 1.5-4.4C18 11 18.6 7.3 17 5.2c-1.5-2-5-1.7-7 .3Z"/>
</svg>
</span>
<div>
<p class="brand__name">Bright Harbor Dental</p>
<p class="brand__sub">Smile transformations</p>
</div>
</div>
<div class="masthead__meta">
<span class="pill pill--ok"><span class="dot" aria-hidden="true"></span> Real patient outcomes</span>
</div>
</header>
<section class="intro">
<h1>Before & after smile gallery</h1>
<p>Drag the slider on any case to reveal the result, or filter by the treatment you're curious about.</p>
</section>
<div class="toolbar" role="group" aria-label="Filter cases by treatment">
<div class="chips" id="chips">
<button class="chip is-active" type="button" data-treatment="all" aria-pressed="true">All cases</button>
<button class="chip" type="button" data-treatment="whitening" aria-pressed="false">Whitening</button>
<button class="chip" type="button" data-treatment="veneers" aria-pressed="false">Veneers</button>
<button class="chip" type="button" data-treatment="aligners" aria-pressed="false">Clear aligners</button>
<button class="chip" type="button" data-treatment="bonding" aria-pressed="false">Bonding</button>
<button class="chip" type="button" data-treatment="implants" aria-pressed="false">Implants</button>
</div>
<p class="count" id="count" aria-live="polite">Showing 6 of 6 cases</p>
</div>
<section class="grid" id="grid" aria-label="Smile gallery cases"></section>
<div class="empty" id="empty" hidden>
<span class="empty__icon" aria-hidden="true">🔍</span>
<p class="empty__title">No cases in this category yet</p>
<p class="empty__sub">Try another treatment — we add new smiles every month.</p>
<button class="btn" type="button" id="resetBtn">Show all cases</button>
</div>
<footer class="foot">
<p>Results vary by patient. Images are illustrative composites for demonstration.</p>
</footer>
</main>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>A clean, clinical before/after smile gallery designed for a dental practice website. Each case is a rounded card with a split-image comparison viewer: drag the center handle (or use the arrow keys) to wipe between the before and after smile. A frosted treatment badge, patient nickname, tooth-shade progression chip, and visit count give every case a real-feeling story, while a subtle gradient stands in for photography so the component stays fully self-contained.
Above the grid, a row of filter chips lets visitors focus on a single treatment — whitening, veneers, clear aligners, bonding, or implants — updating a live “showing N of M” count. Chips are real buttons with visible focus rings and aria-pressed state; selecting one that matches nothing swaps the grid for a friendly empty state. A toast confirms filter changes for screen-reader-free feedback, and the whole layout reflows to a single column with a compact header below 520px.
Interactions are pure vanilla JS: pointer, touch, and keyboard all drive the slider, hover lifts the cards, and the reveal handle animates smoothly with reduced-motion respected. Everything is keyboard-usable and AA-contrast.
Illustrative UI only — not intended for real medical use.