Dental — Landing Pediatric
A cheerful pediatric dentistry landing page with a reassuring hero, animated tooth mascot, and playful blue-and-mint accents. Parents get a three-step first-visit guide, filterable age-group care cards, glowing trust stats, real-feeling testimonials, an expandable parent FAQ, and a sticky book-a-visit bar. Every control is keyboard friendly with visible focus, toasts confirm actions, and the layout stays calm and legible down to small phones.
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;
--sun: #fbbf24;
--pink: #f472b6;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--shadow-sm: 0 2px 8px rgba(15, 39, 64, 0.06);
--shadow-md: 0 10px 30px rgba(15, 39, 64, 0.10);
--shadow-lg: 0 24px 60px rgba(37, 99, 235, 0.16);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: var(--ink);
background: var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-bottom: 76px;
}
h1, h2, h3 { font-family: "Baloo 2", "Inter", system-ui, sans-serif; line-height: 1.15; margin: 0; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
.wrap { width: min(1120px, 100% - 40px); margin-inline: auto; }
.skip-link {
position: absolute;
left: -9999px;
top: 8px;
background: var(--blue);
color: #fff;
padding: 10px 16px;
border-radius: var(--r-sm);
z-index: 100;
}
.skip-link:focus { left: 12px; }
/* ---------- Buttons ---------- */
.btn {
--_bg: var(--blue);
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font-family: inherit;
font-weight: 700;
font-size: 15px;
border: 0;
border-radius: 999px;
padding: 11px 20px;
cursor: pointer;
transition: transform .15s ease, box-shadow .2s ease, background .2s ease;
text-align: center;
}
.btn:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.btn-primary { background: var(--blue); color: #fff; box-shadow: 0 8px 20px rgba(37, 99, 235, 0.28); }
.btn-primary:hover { background: var(--blue-d); transform: translateY(-2px); box-shadow: 0 12px 26px rgba(37, 99, 235, 0.34); }
.btn-primary:active { transform: translateY(0); }
.btn-ghost { background: var(--white); color: var(--blue-d); border: 1.5px solid var(--line-2); box-shadow: var(--shadow-sm); }
.btn-ghost:hover { border-color: var(--blue); transform: translateY(-2px); }
.btn-sm { padding: 8px 15px; font-size: 14px; }
.btn-lg { padding: 14px 26px; font-size: 16px; }
.btn-block { width: 100%; }
/* ---------- Pills / badges ---------- */
.pill {
display: inline-block;
font-weight: 700;
font-size: 12.5px;
letter-spacing: .02em;
padding: 5px 13px;
border-radius: 999px;
}
.pill-mint { background: var(--mint-50); color: var(--ok); }
.pill-blue { background: var(--blue-50); color: var(--blue-d); }
.badge {
display: inline-block;
font-size: 12px;
font-weight: 700;
padding: 4px 11px;
border-radius: 999px;
}
.badge-mint { background: var(--mint-50); color: var(--ok); }
.badge-blue { background: var(--blue-50); color: var(--blue-d); }
/* ---------- Header ---------- */
.site-header {
position: sticky;
top: 0;
z-index: 40;
background: rgba(243, 248, 255, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--line);
}
.header-inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 68px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 9px;
font-family: "Baloo 2", sans-serif;
font-weight: 800;
font-size: 21px;
color: var(--ink);
}
.brand-mark {
display: grid;
place-items: center;
width: 38px;
height: 38px;
border-radius: 12px;
background: linear-gradient(135deg, var(--blue), var(--mint));
color: #fff;
}
.nav { display: flex; align-items: center; gap: 22px; }
.nav a { font-weight: 600; font-size: 15px; color: var(--ink-2); transition: color .15s ease; }
.nav a:hover { color: var(--blue); }
.nav a.btn { color: #fff; }
.nav a.btn:hover { color: #fff; }
/* ---------- Hero ---------- */
.hero {
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 40px;
align-items: center;
padding: 64px 0 40px;
}
.hero-copy .pill { margin-bottom: 18px; }
.hero h1 { font-size: clamp(38px, 6vw, 62px); font-weight: 800; letter-spacing: -0.01em; }
.hero h1 .accent { color: var(--blue); }
.lede { margin: 20px 0 26px; font-size: 18px; color: var(--ink-2); max-width: 46ch; }
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.chips { list-style: none; margin: 28px 0 0; padding: 0; display: flex; gap: 10px; flex-wrap: wrap; }
.chip {
background: var(--white);
border: 1px solid var(--line);
border-radius: 999px;
padding: 8px 14px;
font-size: 13.5px;
font-weight: 600;
color: var(--ink-2);
box-shadow: var(--shadow-sm);
}
/* Hero art / mascot */
.hero-art { position: relative; min-height: 340px; display: grid; place-items: center; }
.blob { position: absolute; border-radius: 50%; filter: blur(2px); opacity: .55; }
.blob-a { width: 300px; height: 300px; background: radial-gradient(circle at 30% 30%, #bcd7ff, transparent 70%); top: 0; right: 10%; }
.blob-b { width: 240px; height: 240px; background: radial-gradient(circle at 60% 60%, #b8f5df, transparent 70%); bottom: 0; left: 8%; }
.tooth-mascot { position: relative; animation: float 4s ease-in-out infinite; cursor: pointer; }
.tooth-mascot:focus-visible { outline: 3px solid var(--blue); outline-offset: 8px; border-radius: 40px; }
.tooth-mascot.wiggle { animation: wiggle .6s ease; }
.tooth-body {
width: 168px;
height: 190px;
background: linear-gradient(180deg, #ffffff, #eaf3ff);
border: 3px solid #d6e6ff;
border-radius: 46% 46% 40% 40% / 40% 40% 60% 60%;
box-shadow: var(--shadow-lg), inset 0 -10px 20px rgba(37, 99, 235, 0.06);
position: relative;
display: grid;
place-items: center;
}
.tooth-body::before, .tooth-body::after {
content: "";
position: absolute;
bottom: -2px;
width: 34px;
height: 44px;
background: linear-gradient(180deg, #eaf3ff, #ffffff);
border: 3px solid #d6e6ff;
border-top: 0;
}
.tooth-body::before { left: 30px; border-radius: 0 0 40% 40%; }
.tooth-body::after { right: 30px; border-radius: 0 0 40% 40%; }
.tooth-face { position: relative; width: 96px; height: 60px; }
.eye {
position: absolute;
top: 8px;
width: 15px;
height: 15px;
background: var(--ink);
border-radius: 50%;
}
.eye::after {
content: "";
position: absolute;
top: 2px; left: 3px;
width: 5px; height: 5px;
background: #fff;
border-radius: 50%;
}
.eye-l { left: 12px; }
.eye-r { right: 12px; }
.cheek { position: absolute; top: 24px; width: 16px; height: 10px; background: var(--pink); opacity: .55; border-radius: 50%; }
.cheek-l { left: 4px; }
.cheek-r { right: 4px; }
.smile {
position: absolute;
bottom: 4px;
left: 50%;
transform: translateX(-50%);
width: 42px;
height: 22px;
border: 4px solid var(--ink);
border-top: 0;
border-radius: 0 0 42px 42px;
}
.sparkle { position: absolute; color: var(--sun); font-size: 22px; animation: twinkle 2.4s ease-in-out infinite; }
.s1 { top: 6px; left: 4px; }
.s2 { top: 40px; right: -6px; animation-delay: .6s; color: var(--mint); }
.s3 { bottom: 18px; left: -8px; animation-delay: 1.2s; color: var(--blue); }
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes twinkle { 0%,100% { opacity: .3; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.15); } }
@keyframes wiggle { 0%,100% { transform: rotate(0); } 25% { transform: rotate(-7deg); } 75% { transform: rotate(7deg); } }
/* ---------- Stats ---------- */
.stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 26px;
box-shadow: var(--shadow-md);
margin-top: 10px;
}
.stat { text-align: center; padding: 6px; }
.stat-num { font-family: "Baloo 2", sans-serif; font-size: 34px; font-weight: 800; color: var(--blue); }
.stat-suffix { font-family: "Baloo 2", sans-serif; font-size: 24px; font-weight: 800; color: var(--mint); }
.stat-label { display: block; margin-top: 4px; font-size: 13.5px; color: var(--muted); font-weight: 500; }
/* ---------- Sections ---------- */
.section { padding: 62px 0; }
.section-head { max-width: 620px; margin-bottom: 34px; }
.section-head .pill { margin-bottom: 14px; }
.section-head h2 { font-size: clamp(28px, 4vw, 40px); font-weight: 800; }
.section-head p { margin-top: 12px; font-size: 17px; color: var(--ink-2); }
/* Steps */
.steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; counter-reset: step; }
.step-card {
position: relative;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 30px 24px 24px;
box-shadow: var(--shadow-sm);
transition: transform .18s ease, box-shadow .2s ease, border-color .2s ease;
}
.step-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--line-2); }
.step-num {
display: grid;
place-items: center;
width: 44px;
height: 44px;
border-radius: 14px;
background: linear-gradient(135deg, var(--blue), var(--mint));
color: #fff;
font-family: "Baloo 2", sans-serif;
font-weight: 800;
font-size: 20px;
margin-bottom: 16px;
}
.step-card h3 { font-size: 20px; }
.step-card p { margin-top: 8px; color: var(--ink-2); font-size: 15px; }
.step-time { display: inline-block; margin-top: 14px; font-size: 12.5px; font-weight: 700; color: var(--muted); background: var(--blue-50); padding: 4px 11px; border-radius: 999px; }
/* Tabs + care grid */
.tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 26px; }
.tab {
font-family: inherit;
font-weight: 700;
font-size: 14.5px;
color: var(--ink-2);
background: var(--white);
border: 1.5px solid var(--line);
border-radius: 999px;
padding: 9px 18px;
cursor: pointer;
transition: all .15s ease;
}
.tab:hover { border-color: var(--blue); color: var(--blue); }
.tab:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.tab.is-active { background: var(--blue); border-color: var(--blue); color: #fff; box-shadow: 0 6px 16px rgba(37, 99, 235, 0.28); }
.care-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.care-card {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 24px;
box-shadow: var(--shadow-sm);
transition: transform .18s ease, box-shadow .2s ease, border-color .2s ease;
animation: fadeUp .4s ease both;
}
.care-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--line-2); }
.care-card.is-hidden { display: none; }
.care-emoji {
display: grid;
place-items: center;
width: 54px;
height: 54px;
border-radius: 16px;
background: var(--mint-50);
font-size: 28px;
margin-bottom: 14px;
}
.care-card h3 { font-size: 19px; }
.care-card p { margin: 8px 0 14px; color: var(--ink-2); font-size: 14.5px; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
/* Testimonials */
.testi-section { text-align: center; }
.testi-section .section-head { margin-inline: auto; }
.testi-card {
max-width: 680px;
margin-inline: auto;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 40px 34px 30px;
box-shadow: var(--shadow-md);
}
.stars { color: var(--sun); font-size: 22px; letter-spacing: 3px; }
#testiQuote {
margin: 18px 0 22px;
font-family: "Baloo 2", sans-serif;
font-size: 22px;
font-weight: 600;
color: var(--ink);
line-height: 1.4;
min-height: 96px;
}
.testi-meta { display: inline-flex; align-items: center; gap: 12px; text-align: left; }
.avatar {
display: grid;
place-items: center;
width: 46px;
height: 46px;
border-radius: 50%;
background: linear-gradient(135deg, var(--blue), var(--mint));
color: #fff;
font-weight: 800;
font-size: 15px;
}
.testi-meta strong { display: block; font-size: 15px; }
.testi-meta span { font-size: 13px; color: var(--muted); }
.testi-dots { display: flex; gap: 9px; justify-content: center; margin-top: 24px; }
.testi-dots button {
width: 10px; height: 10px; padding: 0;
border-radius: 50%;
border: 0;
background: var(--line-2);
cursor: pointer;
transition: all .2s ease;
}
.testi-dots button:hover { background: var(--muted); }
.testi-dots button.is-active { background: var(--blue); width: 26px; border-radius: 999px; }
.testi-dots button:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
/* FAQ */
.faq { display: grid; gap: 12px; max-width: 780px; }
.faq-item { background: var(--white); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; transition: border-color .2s ease, box-shadow .2s ease; }
.faq-item:hover { border-color: var(--line-2); }
.faq-item h3 { margin: 0; font-family: inherit; }
.faq-q {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
background: none;
border: 0;
padding: 18px 20px;
font-family: "Baloo 2", sans-serif;
font-weight: 600;
font-size: 17px;
color: var(--ink);
text-align: left;
cursor: pointer;
}
.faq-q:focus-visible { outline: 3px solid var(--blue); outline-offset: -3px; }
.faq-icon { position: relative; flex: 0 0 22px; width: 22px; height: 22px; }
.faq-icon::before, .faq-icon::after {
content: "";
position: absolute;
top: 50%; left: 50%;
background: var(--blue);
border-radius: 2px;
transition: transform .25s ease;
}
.faq-icon::before { width: 14px; height: 3px; transform: translate(-50%, -50%); }
.faq-icon::after { width: 3px; height: 14px; transform: translate(-50%, -50%); }
.faq-q[aria-expanded="true"] .faq-icon::after { transform: translate(-50%, -50%) scaleY(0); }
.faq-q[aria-expanded="true"] { color: var(--blue-d); }
.faq-a { padding: 0 20px 18px; color: var(--ink-2); font-size: 15px; }
.faq-a p { max-width: 62ch; }
/* Book */
.book-section { padding-top: 20px; }
.book-card {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
background: linear-gradient(135deg, #eef5ff, #eafcf4);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 40px;
box-shadow: var(--shadow-md);
}
.book-copy h2 { font-size: clamp(26px, 3.4vw, 34px); margin: 14px 0 12px; }
.book-copy p { color: var(--ink-2); font-size: 16px; }
.book-perks { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; }
.book-perks li { font-weight: 600; font-size: 15px; color: var(--ink); }
.book-form { background: var(--white); border-radius: var(--r-lg); padding: 26px; box-shadow: var(--shadow-sm); }
.field { margin-bottom: 16px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.field label { display: block; font-size: 13.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; }
.field input, .field select {
width: 100%;
font-family: inherit;
font-size: 15px;
color: var(--ink);
background: var(--bg);
border: 1.5px solid var(--line-2);
border-radius: var(--r-sm);
padding: 11px 13px;
transition: border-color .15s ease, box-shadow .15s ease;
}
.field input:focus, .field select:focus { outline: 0; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.16); }
.field input.invalid, .field select.invalid { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(224, 82, 82, 0.14); }
.form-note { margin-top: 12px; font-size: 12.5px; color: var(--muted); text-align: center; }
/* Footer */
.site-footer { border-top: 1px solid var(--line); background: var(--white); padding: 34px 0; margin-top: 30px; }
.footer-inner { text-align: center; display: grid; gap: 8px; }
.brand-sm { font-size: 18px; justify-self: center; }
.site-footer p { font-size: 14px; color: var(--ink-2); }
.site-footer .muted { color: var(--muted); font-size: 12.5px; }
/* Sticky bar */
.sticky-bar {
position: fixed;
left: 0; right: 0; bottom: 0;
z-index: 45;
background: rgba(255, 255, 255, 0.92);
backdrop-filter: blur(10px);
border-top: 1px solid var(--line);
box-shadow: 0 -6px 24px rgba(15, 39, 64, 0.08);
transform: translateY(110%);
transition: transform .3s ease;
}
.sticky-bar.show { transform: translateY(0); }
.sticky-inner { display: flex; align-items: center; justify-content: space-between; gap: 14px; height: 64px; }
.sticky-text { font-weight: 600; font-size: 15px; color: var(--ink); }
/* Toast */
.toast-region {
position: fixed;
bottom: 84px;
left: 50%;
transform: translateX(-50%);
z-index: 60;
display: grid;
gap: 10px;
width: min(360px, calc(100% - 32px));
}
.toast {
background: var(--ink);
color: #fff;
padding: 13px 18px;
border-radius: var(--r-md);
font-size: 14.5px;
font-weight: 600;
box-shadow: var(--shadow-md);
display: flex;
align-items: center;
gap: 10px;
animation: toastIn .3s ease;
}
.toast.ok { background: linear-gradient(135deg, var(--blue), var(--ok)); }
.toast.err { background: var(--danger); }
.toast.leaving { animation: toastOut .3s ease forwards; }
@keyframes toastIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes toastOut { to { opacity: 0; transform: translateY(14px); } }
/* ---------- Responsive ---------- */
@media (max-width: 860px) {
.hero { grid-template-columns: 1fr; padding-top: 44px; }
.hero-art { order: -1; min-height: 260px; }
.stats { grid-template-columns: repeat(2, 1fr); }
.steps { grid-template-columns: 1fr; }
.book-card { grid-template-columns: 1fr; padding: 30px; gap: 28px; }
}
@media (max-width: 520px) {
body { padding-bottom: 70px; }
.nav a:not(.btn) { display: none; }
.hero h1 { font-size: 36px; }
.lede { font-size: 16px; }
.hero-cta { flex-direction: column; }
.hero-cta .btn { width: 100%; }
.stats { grid-template-columns: 1fr 1fr; padding: 18px; gap: 10px; }
.stat-num { font-size: 28px; }
.care-grid { grid-template-columns: 1fr; }
.section { padding: 46px 0; }
.field-row { grid-template-columns: 1fr; }
.book-card { padding: 22px; }
.book-form { padding: 20px; }
#testiQuote { font-size: 18px; min-height: 120px; }
.sticky-text { font-size: 13px; }
.sticky-inner { height: 58px; }
.toast-region { bottom: 72px; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var region = document.getElementById("toastRegion");
function toast(msg, kind) {
if (!region) return;
var el = document.createElement("div");
el.className = "toast " + (kind || "");
el.setAttribute("role", "status");
el.textContent = msg;
region.appendChild(el);
setTimeout(function () {
el.classList.add("leaving");
setTimeout(function () { el.remove(); }, 300);
}, 3200);
}
/* ---------- Mascot wiggle on click / keypress ---------- */
var mascot = document.getElementById("mascot");
if (mascot) {
mascot.setAttribute("tabindex", "0");
mascot.setAttribute("role", "button");
mascot.setAttribute("aria-label", "Say hi to Grinny the tooth");
var cheers = ["Hi there! 🦷", "Brush, brush, hooray! ✨", "You've got a great smile!", "High five! 🖐"];
function wiggle() {
mascot.classList.remove("wiggle");
void mascot.offsetWidth;
mascot.classList.add("wiggle");
toast(cheers[Math.floor(Math.random() * cheers.length)], "ok");
}
mascot.addEventListener("click", wiggle);
mascot.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); wiggle(); }
});
}
/* ---------- Count-up stats ---------- */
var stats = document.querySelectorAll(".stat-num");
function animateCount(el) {
var target = parseInt(el.getAttribute("data-count"), 10) || 0;
var dur = 1300, start = null;
function frame(ts) {
if (start === null) start = ts;
var p = Math.min((ts - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
var val = Math.round(target * eased);
el.textContent = val >= 1000 ? val.toLocaleString("en-US") : String(val);
if (p < 1) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
if ("IntersectionObserver" in window) {
var seen = new WeakSet();
var statObs = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting && !seen.has(en.target)) {
seen.add(en.target);
animateCount(en.target);
}
});
}, { threshold: 0.5 });
stats.forEach(function (s) { statObs.observe(s); });
} else {
stats.forEach(animateCount);
}
/* ---------- Care-by-age tabs ---------- */
var tabs = document.querySelectorAll(".tab");
var cards = document.querySelectorAll(".care-card");
function selectGroup(group) {
tabs.forEach(function (t) {
var on = t.getAttribute("data-group") === group;
t.classList.toggle("is-active", on);
t.setAttribute("aria-selected", on ? "true" : "false");
});
cards.forEach(function (c) {
var show = c.getAttribute("data-group") === group;
c.classList.toggle("is-hidden", !show);
if (show) { c.style.animation = "none"; void c.offsetWidth; c.style.animation = ""; }
});
}
tabs.forEach(function (t, i) {
t.addEventListener("click", function () { selectGroup(t.getAttribute("data-group")); });
t.addEventListener("keydown", function (e) {
var idx = null;
if (e.key === "ArrowRight") idx = (i + 1) % tabs.length;
else if (e.key === "ArrowLeft") idx = (i - 1 + tabs.length) % tabs.length;
if (idx !== null) {
e.preventDefault();
tabs[idx].focus();
selectGroup(tabs[idx].getAttribute("data-group"));
}
});
});
/* ---------- FAQ accordion (single-open) ---------- */
var qs = document.querySelectorAll(".faq-q");
qs.forEach(function (btn) {
btn.addEventListener("click", function () {
var expanded = btn.getAttribute("aria-expanded") === "true";
qs.forEach(function (other) {
other.setAttribute("aria-expanded", "false");
var p = document.getElementById(other.getAttribute("aria-controls"));
if (p) p.hidden = true;
});
if (!expanded) {
btn.setAttribute("aria-expanded", "true");
var panel = document.getElementById(btn.getAttribute("aria-controls"));
if (panel) panel.hidden = false;
}
});
});
/* ---------- Testimonials rotator ---------- */
var reviews = [
{ q: "My daughter used to cry at the dentist. Now she counts down the days. The staff are pure magic.", name: "Maya R.", role: "Parent of 2", initials: "MR" },
{ q: "The first-visit walkthrough calmed my nerves more than my son's! We left with a sticker and a plan.", name: "Daniel O.", role: "Dad of a toddler", initials: "DO" },
{ q: "Gentle, patient, and genuinely fun. My twins actually argue over who gets to go first.", name: "Priya S.", role: "Parent of twins", initials: "PS" },
{ q: "They explained everything at my daughter's level. No fear, no fuss — just a happy kiddo.", name: "Leah T.", role: "First-time parent", initials: "LT" }
];
var qEl = document.getElementById("testiQuote");
var nameEl = document.getElementById("testiName");
var roleEl = document.getElementById("testiRole");
var avaEl = document.getElementById("testiAvatar");
var dotsWrap = document.getElementById("testiDots");
var current = 0, timer = null;
function renderReview(i) {
current = i;
var r = reviews[i];
qEl.style.opacity = "0";
setTimeout(function () {
qEl.textContent = '"' + r.q + '"';
nameEl.textContent = r.name;
roleEl.textContent = r.role;
avaEl.textContent = r.initials;
qEl.style.opacity = "1";
}, 180);
if (dotsWrap) {
Array.prototype.forEach.call(dotsWrap.children, function (d, di) {
d.classList.toggle("is-active", di === i);
d.setAttribute("aria-selected", di === i ? "true" : "false");
});
}
}
if (qEl && dotsWrap) {
qEl.style.transition = "opacity .18s ease";
reviews.forEach(function (r, i) {
var b = document.createElement("button");
b.setAttribute("role", "tab");
b.setAttribute("aria-label", "Review from " + r.name);
if (i === 0) b.classList.add("is-active");
b.addEventListener("click", function () { renderReview(i); restart(); });
dotsWrap.appendChild(b);
});
function next() { renderReview((current + 1) % reviews.length); }
function restart() { clearInterval(timer); timer = setInterval(next, 5000); }
restart();
}
/* ---------- Booking form ---------- */
var form = document.getElementById("bookForm");
if (form) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var fields = form.querySelectorAll("input[required], select[required]");
var firstBad = null;
fields.forEach(function (f) {
var bad = !f.value || (f.type === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(f.value));
f.classList.toggle("invalid", bad);
if (bad && !firstBad) firstBad = f;
});
if (firstBad) {
firstBad.focus();
toast("Please fill in the highlighted fields.", "err");
return;
}
var name = form.querySelector("#parent").value.trim().split(" ")[0] || "there";
form.reset();
toast("Thanks, " + name + "! We'll confirm your visit within 1 business day. 🦷", "ok");
});
form.querySelectorAll("input, select").forEach(function (f) {
f.addEventListener("input", function () { f.classList.remove("invalid"); });
f.addEventListener("change", function () { f.classList.remove("invalid"); });
});
}
/* ---------- Sticky book bar (show after hero) ---------- */
var bar = document.getElementById("stickyBar");
var hero = document.getElementById("hero");
if (bar && hero && "IntersectionObserver" in window) {
var barObs = new IntersectionObserver(function (entries) {
bar.classList.toggle("show", !entries[0].isIntersecting);
}, { threshold: 0 });
barObs.observe(hero);
} else if (bar) {
window.addEventListener("scroll", function () {
bar.classList.toggle("show", window.scrollY > 480);
}, { passive: true });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Little Grins — Pediatric Dentistry</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=Baloo+2:wght@500;600;700;800&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#book">Skip to booking</a>
<header class="site-header">
<div class="wrap header-inner">
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 32 32" width="26" height="26"><path d="M16 4c-4 0-6 2-9 2S2 4 2 9c0 6 2 8 4 14 1.4 4.2 2.6 5 3.6 5 1.4 0 1.6-2 2.4-5 .6-2.2 1-3 4-3s3.4.8 4 3c.8 3 1 5 2.4 5 1 0 2.2-.8 3.6-5 2-6 4-8 4-14 0-5-2-5-5-3s-5-2-9-2Z" fill="currentColor"/></svg>
</span>
Little Grins
</a>
<nav class="nav" aria-label="Primary">
<a href="#visit">First visit</a>
<a href="#care">Care by age</a>
<a href="#faq">Parent FAQ</a>
<a href="#book" class="btn btn-primary btn-sm">Book a visit</a>
</nav>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero wrap" id="hero">
<div class="hero-copy">
<span class="pill pill-mint">Now welcoming new little patients</span>
<h1>Happy teeth,<br /><span class="accent">happy kiddos.</span></h1>
<p class="lede">Gentle, playful dental care built around your child — from first tooth to first big-kid checkup. No scary chairs, just high-fives and sticker prizes.</p>
<div class="hero-cta">
<a href="#book" class="btn btn-primary btn-lg">Book a first visit</a>
<a href="#visit" class="btn btn-ghost btn-lg">See what to expect</a>
</div>
<ul class="chips" aria-label="Why families choose us">
<li class="chip">🦷 Kid-first exam rooms</li>
<li class="chip">🎈 Sticker & prize wall</li>
<li class="chip">😌 Calm, no-rush visits</li>
</ul>
</div>
<div class="hero-art" aria-hidden="true">
<div class="blob blob-a"></div>
<div class="blob blob-b"></div>
<div class="tooth-mascot" id="mascot">
<div class="tooth-body">
<div class="tooth-face">
<span class="eye eye-l"></span>
<span class="eye eye-r"></span>
<span class="cheek cheek-l"></span>
<span class="cheek cheek-r"></span>
<span class="smile"></span>
</div>
</div>
<div class="sparkle s1">✦</div>
<div class="sparkle s2">✦</div>
<div class="sparkle s3">✦</div>
</div>
</div>
</section>
<!-- TRUST STATS -->
<section class="stats wrap" aria-label="Practice highlights">
<div class="stat">
<span class="stat-num" data-count="12000">0</span><span class="stat-suffix">+</span>
<span class="stat-label">Little smiles seen</span>
</div>
<div class="stat">
<span class="stat-num" data-count="98">0</span><span class="stat-suffix">%</span>
<span class="stat-label">Parents would recommend</span>
</div>
<div class="stat">
<span class="stat-num" data-count="15">0</span><span class="stat-suffix">min</span>
<span class="stat-label">Avg. wait time</span>
</div>
<div class="stat">
<span class="stat-num" data-count="6">0</span>
<span class="stat-label">Kid-friendly dentists</span>
</div>
</section>
<!-- FIRST VISIT GUIDE -->
<section class="section wrap" id="visit">
<div class="section-head">
<span class="pill pill-blue">The first visit</span>
<h2>Three easy steps, zero nerves</h2>
<p>We keep it short, gentle, and fun. Here's exactly how your child's first appointment goes.</p>
</div>
<ol class="steps">
<li class="step-card">
<span class="step-num">1</span>
<h3>Meet & explore</h3>
<p>A friendly hello, a tour of the room, and a ride in the "moon chair." Your child touches every tool before it's used.</p>
<span class="step-time">~5 min</span>
</li>
<li class="step-card">
<span class="step-num">2</span>
<h3>Count the teeth</h3>
<p>A gentle, tickle-free checkup and cleaning with our sugar-bug detector. We narrate every step so nothing feels surprising.</p>
<span class="step-time">~15 min</span>
</li>
<li class="step-card">
<span class="step-num">3</span>
<h3>Prizes & plan</h3>
<p>A sticker, a new toothbrush, and a simple at-home plan for you. High-fives all around before you go.</p>
<span class="step-time">~5 min</span>
</li>
</ol>
</section>
<!-- CARE BY AGE -->
<section class="section wrap" id="care">
<div class="section-head">
<span class="pill pill-mint">Care by age</span>
<h2>The right care for every stage</h2>
<p>Pick your child's stage to see how we tailor the visit.</p>
</div>
<div class="tabs" role="tablist" aria-label="Care by age group">
<button class="tab is-active" role="tab" aria-selected="true" data-group="babies" id="tab-babies">Babies</button>
<button class="tab" role="tab" aria-selected="false" data-group="toddlers" id="tab-toddlers">Toddlers</button>
<button class="tab" role="tab" aria-selected="false" data-group="kids" id="tab-kids">Big Kids</button>
<button class="tab" role="tab" aria-selected="false" data-group="teens" id="tab-teens">Teens</button>
</div>
<div class="care-grid" id="careGrid">
<!-- babies -->
<article class="care-card" data-group="babies">
<span class="care-emoji" aria-hidden="true">👶</span>
<h3>First tooth check</h3>
<p>Ages 0–2. Gum care coaching, teething relief, and spotting sugar-bugs early.</p>
<span class="badge badge-mint">Gentle</span>
</article>
<article class="care-card" data-group="babies">
<span class="care-emoji" aria-hidden="true">🍼</span>
<h3>Bottle & feeding tips</h3>
<p>Simple habits to protect brand-new teeth from bottle cavities.</p>
<span class="badge badge-blue">Coaching</span>
</article>
<!-- toddlers -->
<article class="care-card is-hidden" data-group="toddlers">
<span class="care-emoji" aria-hidden="true">🧸</span>
<h3>Tickle-free cleanings</h3>
<p>Ages 2–5. Short, playful cleanings with the "sugar-bug counter" game.</p>
<span class="badge badge-mint">Playful</span>
</article>
<article class="care-card is-hidden" data-group="toddlers">
<span class="care-emoji" aria-hidden="true">🪥</span>
<h3>Brushing bootcamp</h3>
<p>We turn brushing into a two-minute song your toddler will beg to do.</p>
<span class="badge badge-blue">Habit-building</span>
</article>
<!-- kids -->
<article class="care-card is-hidden" data-group="kids">
<span class="care-emoji" aria-hidden="true">🦷</span>
<h3>Sealants & checkups</h3>
<p>Ages 6–11. Protective sealants and easy cavity prevention as big teeth arrive.</p>
<span class="badge badge-mint">Preventive</span>
</article>
<article class="care-card is-hidden" data-group="kids">
<span class="care-emoji" aria-hidden="true">⚽</span>
<h3>Sport mouthguards</h3>
<p>Custom-fit guards in fun colors to keep active grins safe on the field.</p>
<span class="badge badge-blue">Protective</span>
</article>
<!-- teens -->
<article class="care-card is-hidden" data-group="teens">
<span class="care-emoji" aria-hidden="true">😁</span>
<h3>Braces-ready checks</h3>
<p>Ages 12+. Alignment reviews and referrals when it's time for straightening.</p>
<span class="badge badge-mint">Guidance</span>
</article>
<article class="care-card is-hidden" data-group="teens">
<span class="care-emoji" aria-hidden="true">✨</span>
<h3>Confidence cleanings</h3>
<p>Fresh, bright smiles and honest advice teens actually listen to.</p>
<span class="badge badge-blue">Whitening-safe</span>
</article>
</div>
</section>
<!-- TESTIMONIALS -->
<section class="section wrap testi-section" aria-label="Parent reviews">
<div class="section-head">
<span class="pill pill-blue">Loved by parents</span>
<h2>Grown-ups approve, too</h2>
</div>
<div class="testi-card">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote id="testiQuote">"My daughter used to cry at the dentist. Now she counts down the days. The staff are pure magic."</blockquote>
<div class="testi-meta">
<span class="avatar" id="testiAvatar" aria-hidden="true">MR</span>
<div>
<strong id="testiName">Maya R.</strong>
<span id="testiRole">Parent of 2</span>
</div>
</div>
<div class="testi-dots" id="testiDots" role="tablist" aria-label="Choose a review"></div>
</div>
</section>
<!-- FAQ -->
<section class="section wrap" id="faq">
<div class="section-head">
<span class="pill pill-mint">Parent FAQ</span>
<h2>Questions, answered</h2>
</div>
<div class="faq" id="faq-list">
<div class="faq-item">
<h3>
<button class="faq-q" aria-expanded="false" aria-controls="a1" id="q1">
When should my child first see a dentist?
<span class="faq-icon" aria-hidden="true"></span>
</button>
</h3>
<div class="faq-a" id="a1" role="region" aria-labelledby="q1" hidden>
<p>By their first birthday, or within six months of the first tooth appearing. Early visits keep things easy and build lifelong comfort.</p>
</div>
</div>
<div class="faq-item">
<h3>
<button class="faq-q" aria-expanded="false" aria-controls="a2" id="q2">
Will the visit hurt or scare them?
<span class="faq-icon" aria-hidden="true"></span>
</button>
</h3>
<div class="faq-a" id="a2" role="region" aria-labelledby="q2" hidden>
<p>Nope. First visits are all about meeting us and exploring. We move at your child's pace and never rush a nervous kiddo.</p>
</div>
</div>
<div class="faq-item">
<h3>
<button class="faq-q" aria-expanded="false" aria-controls="a3" id="q3">
Can I stay in the room with my child?
<span class="faq-icon" aria-hidden="true"></span>
</button>
</h3>
<div class="faq-a" id="a3" role="region" aria-labelledby="q3" hidden>
<p>Always. Parents are welcome beside the chair for every appointment — you're part of the team.</p>
</div>
</div>
<div class="faq-item">
<h3>
<button class="faq-q" aria-expanded="false" aria-controls="a4" id="q4">
Do you take insurance and payment plans?
<span class="faq-icon" aria-hidden="true"></span>
</button>
</h3>
<div class="faq-a" id="a4" role="region" aria-labelledby="q4" hidden>
<p>We accept most major plans and offer simple, no-surprise payment options. Our front desk will sort the details before you arrive.</p>
</div>
</div>
</div>
</section>
<!-- BOOK -->
<section class="section wrap book-section" id="book">
<div class="book-card">
<div class="book-copy">
<span class="pill pill-blue">Book a visit</span>
<h2>Let's get that first smile scheduled</h2>
<p>Tell us a little about your child and we'll reach out within one business day to confirm a time that works.</p>
<ul class="book-perks">
<li>✔ Free first-visit consult</li>
<li>✔ Evening & Saturday slots</li>
<li>✔ Sticker prize guaranteed</li>
</ul>
</div>
<form class="book-form" id="bookForm" novalidate>
<div class="field">
<label for="parent">Parent name</label>
<input id="parent" name="parent" type="text" autocomplete="name" required placeholder="Alex Morgan" />
</div>
<div class="field">
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required placeholder="[email protected]" />
</div>
<div class="field-row">
<div class="field">
<label for="childage">Child's age</label>
<select id="childage" name="childage" required>
<option value="" disabled selected>Select</option>
<option>Under 2</option>
<option>2–5</option>
<option>6–11</option>
<option>12+</option>
</select>
</div>
<div class="field">
<label for="visit-type">Visit type</label>
<select id="visit-type" name="visit-type" required>
<option value="" disabled selected>Select</option>
<option>First visit</option>
<option>Checkup & cleaning</option>
<option>Something's bothering us</option>
</select>
</div>
</div>
<button type="submit" class="btn btn-primary btn-lg btn-block">Request my visit</button>
<p class="form-note">We'll never share your info. Reply within 1 business day.</p>
</form>
</div>
</section>
</main>
<footer class="site-footer">
<div class="wrap footer-inner">
<span class="brand brand-sm">Little Grins</span>
<p>Illustrative UI only — not intended for real medical use.</p>
<p class="muted">© 2026 Little Grins Pediatric Dentistry (fictional).</p>
</div>
</footer>
<!-- STICKY BOOK BAR -->
<div class="sticky-bar" id="stickyBar">
<div class="wrap sticky-inner">
<span class="sticky-text">🦷 Ready when you are — new patients welcome</span>
<a href="#book" class="btn btn-primary btn-sm">Book a visit</a>
</div>
</div>
<div class="toast-region" id="toastRegion" aria-live="polite" aria-atomic="true"></div>
<script src="script.js"></script>
</body>
</html>A warm, trust-first landing page for a fictional pediatric dental practice, Little Grins. The hero pairs kid-friendly copy with a floating tooth mascot, quick reassurance chips, and dual calls to action, while a soft blue-and-mint palette keeps the whole page feeling clinical yet playful. Below the fold, a three-step first-visit guide walks nervous parents through what to expect, and a set of age-group care cards can be filtered by tab (Babies, Toddlers, Big Kids, Teens) with a smooth cross-fade.
The page is fully interactive with vanilla JavaScript only. Filter tabs update the visible care cards, the parent FAQ is an accessible accordion (aria-expanded, single-open, keyboard operable), and the book-a-visit form validates inline and fires a friendly toast() confirmation. A sticky bottom bar keeps the primary CTA in reach, trust stats count up when scrolled into view, and testimonials rotate through real-feeling parent quotes. Hover, active, and focus states are defined everywhere, and a @media (max-width:520px) block reflows the grid, stacks the hero, and shrinks the sticky bar for phones down to about 360px.
Illustrative UI only — not intended for real medical use.