Clinic — Dental Clinic Landing
A smile-forward landing page for a fictional dental studio in a clean mint-and-soft-blue palette, with a sticky blurred nav, a hero whose trust stats count up on view, a six-card services grid, a draggable before-and-after smile comparison slider, a free-consult offer band, a four-dentist team strip, an accordion FAQ beside an opening-hours card, reveal-on-scroll sections, a mobile menu and an accessible booking dialog with a focus trap and toast feedback.
MCP
Код
:root {
/* Dental theme — mint + soft blue, smile-forward */
--mint: #d9f2ec;
--mint-d: #3fb6a0;
--mint-700: #2c8e7c;
--mint-50: #eefbf8;
--blue: #5b8def;
--blue-d: #3a6fd6;
--blue-50: #eaf1fe;
--ink: #0f2c3a;
--ink-2: #355160;
--muted: #6c8794;
--bg: #f3fbf9;
--white: #ffffff;
--line: rgba(15, 44, 58, 0.1);
--line-2: rgba(15, 44, 58, 0.18);
--ok: #2f9e6f;
--warn: #d98a2b;
--danger: #d4503e;
--font: "Inter", system-ui, -apple-system, sans-serif;
--r-sm: 10px;
--r-md: 18px;
--r-lg: 26px;
--r-xl: 34px;
--shadow-1: 0 1px 2px rgba(15, 44, 58, 0.05), 0 6px 18px rgba(15, 44, 58, 0.06);
--shadow-2: 0 18px 44px rgba(58, 111, 214, 0.16);
--shadow-soft: 0 24px 60px rgba(63, 182, 160, 0.18);
--maxw: 1120px;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
scroll-padding-top: 88px;
}
body {
font-family: var(--font);
background: var(--bg);
color: var(--ink);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
line-height: 1.5;
}
a {
color: inherit;
text-decoration: none;
}
:focus-visible {
outline: 3px solid var(--blue);
outline-offset: 2px;
border-radius: 6px;
}
.skip-link {
position: absolute;
left: 12px;
top: -56px;
background: var(--white);
color: var(--ink);
padding: 10px 16px;
border-radius: var(--r-sm);
box-shadow: var(--shadow-1);
z-index: 200;
transition: top 0.2s;
}
.skip-link:focus {
top: 12px;
}
/* ── Buttons ──────────────────────────────────────────────── */
.btn {
font: inherit;
font-weight: 600;
border: 1px solid transparent;
border-radius: 999px;
padding: 10px 20px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
white-space: nowrap;
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.btn:active {
transform: translateY(1px) scale(0.99);
}
.btn-lg {
padding: 14px 26px;
font-size: 1.02rem;
}
.btn-block {
width: 100%;
}
.btn-primary {
background: linear-gradient(135deg, var(--blue), var(--blue-d));
color: var(--white);
box-shadow: 0 8px 20px rgba(58, 111, 214, 0.28);
}
.btn-primary:hover {
box-shadow: 0 12px 26px rgba(58, 111, 214, 0.38);
transform: translateY(-2px);
}
.btn-ghost {
background: var(--white);
color: var(--ink);
border-color: var(--line-2);
}
.btn-ghost:hover {
border-color: var(--blue);
color: var(--blue-d);
transform: translateY(-2px);
}
.btn-light {
background: var(--white);
color: var(--blue-d);
box-shadow: 0 8px 20px rgba(15, 44, 58, 0.12);
}
.btn-light:hover {
transform: translateY(-2px);
box-shadow: 0 12px 28px rgba(15, 44, 58, 0.18);
}
/* ── Nav ──────────────────────────────────────────────────── */
.nav {
position: sticky;
top: 0;
z-index: 100;
background: rgba(243, 251, 249, 0.78);
backdrop-filter: saturate(160%) blur(12px);
-webkit-backdrop-filter: saturate(160%) blur(12px);
border-bottom: 1px solid transparent;
transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
}
.nav.is-scrolled {
border-bottom-color: var(--line);
box-shadow: 0 6px 24px rgba(15, 44, 58, 0.05);
background: rgba(243, 251, 249, 0.92);
}
.nav-inner {
max-width: var(--maxw);
margin: 0 auto;
padding: 14px 24px;
display: flex;
align-items: center;
gap: 22px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
font-weight: 800;
font-size: 1.12rem;
letter-spacing: -0.01em;
}
.brand-mark {
width: 38px;
height: 38px;
border-radius: 12px;
display: grid;
place-items: center;
background: linear-gradient(135deg, var(--mint), var(--blue-50));
color: var(--blue-d);
box-shadow: inset 0 0 0 1px rgba(58, 111, 214, 0.18);
}
.brand-name em {
font-style: normal;
color: var(--mint-700);
}
.nav-links {
display: flex;
gap: 6px;
margin-left: 8px;
}
.nav-links a {
padding: 8px 14px;
border-radius: 999px;
font-weight: 500;
color: var(--ink-2);
transition: background 0.15s, color 0.15s;
}
.nav-links a:hover {
background: var(--mint);
color: var(--ink);
}
.nav-cta {
margin-left: auto;
display: flex;
align-items: center;
gap: 14px;
}
.phone {
font-weight: 600;
font-size: 0.92rem;
color: var(--ink-2);
}
.phone:hover {
color: var(--blue-d);
}
.nav-toggle {
display: none;
flex-direction: column;
gap: 5px;
width: 44px;
height: 44px;
background: var(--white);
border: 1px solid var(--line);
border-radius: 12px;
cursor: pointer;
align-items: center;
justify-content: center;
}
.nav-toggle span {
width: 20px;
height: 2px;
background: var(--ink);
border-radius: 2px;
transition: transform 0.25s, opacity 0.2s;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] span:nth-child(2) {
opacity: 0;
}
.nav-toggle[aria-expanded="true"] span:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
/* ── Hero ─────────────────────────────────────────────────── */
.hero {
max-width: var(--maxw);
margin: 0 auto;
padding: 64px 24px 40px;
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 48px;
align-items: center;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--mint);
color: var(--mint-700);
font-weight: 600;
font-size: 0.85rem;
padding: 6px 14px;
border-radius: 999px;
}
.hero h1 {
margin: 18px 0 14px;
font-size: clamp(2.4rem, 5.2vw, 3.5rem);
line-height: 1.04;
letter-spacing: -0.03em;
font-weight: 800;
}
.lede {
font-size: 1.1rem;
color: var(--ink-2);
max-width: 46ch;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin: 26px 0 30px;
}
.hero-trust {
list-style: none;
display: flex;
gap: 30px;
flex-wrap: wrap;
}
.hero-trust li {
display: flex;
flex-direction: column;
}
.hero-trust strong {
font-size: 1.7rem;
font-weight: 800;
color: var(--blue-d);
letter-spacing: -0.02em;
}
.hero-trust span {
font-size: 0.86rem;
color: var(--muted);
}
.hero-art {
position: relative;
min-height: 360px;
display: grid;
place-items: center;
}
.art-card {
position: relative;
z-index: 2;
background: var(--white);
border-radius: var(--r-xl);
padding: 44px 40px;
box-shadow: var(--shadow-soft);
display: grid;
place-items: center;
gap: 14px;
border: 1px solid rgba(58, 111, 214, 0.1);
}
.tooth-emoji {
font-size: 6rem;
line-height: 1;
filter: drop-shadow(0 12px 18px rgba(58, 111, 214, 0.22));
animation: float 5s ease-in-out infinite;
}
.art-tag {
font-weight: 600;
color: var(--ink-2);
}
.art-chip {
position: absolute;
z-index: 3;
background: var(--white);
border: 1px solid var(--line);
border-radius: 999px;
padding: 9px 16px;
font-size: 0.85rem;
font-weight: 600;
box-shadow: var(--shadow-1);
display: inline-flex;
align-items: center;
gap: 8px;
}
.art-chip-1 {
top: 18px;
left: -8px;
animation: float 6s ease-in-out infinite;
}
.art-chip-2 {
bottom: 26px;
right: -10px;
animation: float 6.5s ease-in-out 0.4s infinite;
}
.dot {
width: 9px;
height: 9px;
border-radius: 50%;
}
.dot.ok {
background: var(--ok);
box-shadow: 0 0 0 4px rgba(47, 158, 111, 0.16);
}
.art-blob {
position: absolute;
border-radius: 50%;
filter: blur(8px);
z-index: 1;
}
.art-blob-1 {
width: 220px;
height: 220px;
background: radial-gradient(circle, rgba(91, 141, 239, 0.32), transparent 70%);
top: -30px;
right: 10px;
}
.art-blob-2 {
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(63, 182, 160, 0.32), transparent 70%);
bottom: -20px;
left: 0;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
/* ── Sections ─────────────────────────────────────────────── */
.section {
max-width: var(--maxw);
margin: 0 auto;
padding: 64px 24px;
}
.section-head {
text-align: center;
max-width: 620px;
margin: 0 auto 40px;
}
.section-head-left {
text-align: left;
margin-left: 0;
}
.kicker {
font-weight: 700;
font-size: 0.82rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--mint-700);
}
.section-head h2 {
font-size: clamp(1.7rem, 3.4vw, 2.3rem);
letter-spacing: -0.02em;
margin: 8px 0 10px;
font-weight: 800;
}
.section-head p {
color: var(--ink-2);
font-size: 1.04rem;
}
/* ── Services grid ────────────────────────────────────────── */
.services-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.service-card {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 28px 26px;
box-shadow: var(--shadow-1);
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
position: relative;
overflow: hidden;
}
.service-card::after {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 4px;
background: linear-gradient(90deg, var(--mint-d), var(--blue));
opacity: 0;
transition: opacity 0.2s;
}
.service-card:hover,
.service-card:focus-visible {
transform: translateY(-6px);
box-shadow: var(--shadow-2);
border-color: rgba(58, 111, 214, 0.28);
}
.service-card:hover::after,
.service-card:focus-visible::after {
opacity: 1;
}
.svc-icon {
display: grid;
place-items: center;
width: 54px;
height: 54px;
border-radius: 16px;
background: var(--mint-50);
font-size: 1.7rem;
margin-bottom: 16px;
}
.service-card h3 {
font-size: 1.12rem;
font-weight: 700;
margin-bottom: 8px;
}
.service-card p {
color: var(--ink-2);
font-size: 0.95rem;
margin-bottom: 18px;
}
.svc-price {
display: inline-block;
font-weight: 700;
font-size: 0.86rem;
color: var(--blue-d);
background: var(--blue-50);
padding: 5px 12px;
border-radius: 999px;
}
.service-card-urgent .svc-icon {
background: #fff0ec;
}
.service-card-urgent .svc-price {
color: var(--danger);
background: #fdecea;
}
/* ── Before / After compare ───────────────────────────────── */
.compare {
position: relative;
max-width: 760px;
margin: 0 auto;
height: 340px;
border-radius: var(--r-xl);
overflow: hidden;
box-shadow: var(--shadow-2);
user-select: none;
border: 1px solid var(--line);
}
.compare-pane {
position: absolute;
inset: 0;
display: grid;
place-items: center;
gap: 12px;
}
.compare-after {
background: linear-gradient(135deg, var(--mint-50), var(--blue-50));
}
.compare-before {
background: linear-gradient(135deg, #e7ecef, #d7e0e6);
width: 50%;
border-right: 3px solid var(--white);
}
.compare-smile {
font-size: 7rem;
line-height: 1;
filter: drop-shadow(0 10px 16px rgba(15, 44, 58, 0.12));
}
.smile-before {
filter: grayscale(0.5) brightness(0.95);
}
.compare-label {
position: absolute;
bottom: 18px;
font-weight: 700;
font-size: 0.82rem;
letter-spacing: 0.06em;
text-transform: uppercase;
background: rgba(255, 255, 255, 0.86);
color: var(--ink);
padding: 5px 14px;
border-radius: 999px;
}
.compare-after .compare-label {
right: 18px;
color: var(--blue-d);
}
.compare-before .compare-label {
left: 18px;
}
.compare-range {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: ew-resize;
z-index: 5;
}
.compare-handle {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 3px;
background: var(--white);
transform: translateX(-50%);
z-index: 4;
pointer-events: none;
}
.compare-handle span {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 46px;
height: 46px;
border-radius: 50%;
background: var(--white);
color: var(--blue-d);
display: grid;
place-items: center;
font-weight: 800;
letter-spacing: 2px;
box-shadow: var(--shadow-1);
}
.compare-range:focus-visible + .compare-handle span {
outline: 3px solid var(--blue);
outline-offset: 2px;
}
/* ── Offers band ──────────────────────────────────────────── */
.offers {
background: linear-gradient(135deg, var(--blue), var(--blue-d));
color: var(--white);
border-radius: var(--r-xl);
max-width: var(--maxw);
margin: 24px auto;
padding: 4px;
}
.offers-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 28px;
padding: 38px 44px;
flex-wrap: wrap;
background: radial-gradient(120% 140% at 100% 0%, rgba(217, 242, 236, 0.18), transparent 60%);
border-radius: calc(var(--r-xl) - 4px);
}
.offers-badge {
display: inline-block;
background: rgba(255, 255, 255, 0.18);
font-weight: 700;
font-size: 0.78rem;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 5px 13px;
border-radius: 999px;
margin-bottom: 12px;
}
.offers-text h2 {
font-size: clamp(1.5rem, 3vw, 2rem);
letter-spacing: -0.02em;
font-weight: 800;
}
.offers-text p {
margin-top: 8px;
color: rgba(255, 255, 255, 0.9);
max-width: 48ch;
}
/* ── Dentists ─────────────────────────────────────────────── */
.team-strip {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.dentist {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 26px 22px;
text-align: center;
box-shadow: var(--shadow-1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.dentist:hover {
transform: translateY(-5px);
box-shadow: var(--shadow-2);
}
.avatar {
width: 66px;
height: 66px;
margin: 0 auto 14px;
border-radius: 50%;
display: grid;
place-items: center;
font-weight: 800;
font-size: 1.2rem;
color: var(--white);
background: var(--a, var(--blue));
box-shadow: 0 8px 18px rgba(15, 44, 58, 0.16);
}
.dentist h3 {
font-size: 1.04rem;
font-weight: 700;
}
.dentist .role {
color: var(--blue-d);
font-weight: 600;
font-size: 0.85rem;
margin: 3px 0 8px;
}
.dentist .bio {
color: var(--muted);
font-size: 0.88rem;
}
/* ── FAQ + Hours ──────────────────────────────────────────── */
.faq-grid {
max-width: var(--maxw);
margin: 0 auto;
display: grid;
grid-template-columns: 1.3fr 0.7fr;
gap: 36px;
align-items: start;
}
.faq-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.faq-item {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
transition: border-color 0.2s, box-shadow 0.2s;
}
.faq-item.is-open {
border-color: rgba(58, 111, 214, 0.3);
box-shadow: var(--shadow-1);
}
.faq-q {
width: 100%;
font: inherit;
font-weight: 600;
text-align: left;
background: none;
border: none;
cursor: pointer;
padding: 18px 20px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
color: var(--ink);
}
.faq-icon {
flex-shrink: 0;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--mint-50);
color: var(--mint-700);
display: grid;
place-items: center;
font-size: 1.2rem;
font-weight: 700;
transition: transform 0.25s, background 0.2s, color 0.2s;
}
.faq-item.is-open .faq-icon {
transform: rotate(45deg);
background: var(--blue);
color: var(--white);
}
.faq-a {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.faq-a p {
padding: 0 20px 18px;
color: var(--ink-2);
font-size: 0.95rem;
}
.hours-card {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 26px;
box-shadow: var(--shadow-1);
}
.hours-card h3 {
font-size: 1.1rem;
font-weight: 700;
margin-bottom: 14px;
}
.hours-list {
list-style: none;
margin-bottom: 22px;
}
.hours-list li {
display: flex;
justify-content: space-between;
padding: 11px 12px;
border-radius: 10px;
font-size: 0.94rem;
}
.hours-list li span {
color: var(--ink-2);
}
.hours-list li strong {
font-weight: 700;
}
.hours-list li.is-today {
background: var(--mint-50);
}
.hours-list li.is-today span::after {
content: " · Today";
color: var(--mint-700);
font-weight: 600;
}
.closed {
color: var(--muted);
}
.hours-foot .addr {
color: var(--muted);
font-size: 0.88rem;
margin-bottom: 14px;
}
/* ── Footer ───────────────────────────────────────────────── */
.footer {
background: var(--ink);
color: #d6e6ec;
margin-top: 40px;
}
.footer-inner {
max-width: var(--maxw);
margin: 0 auto;
padding: 56px 24px 36px;
display: grid;
grid-template-columns: 1.6fr repeat(3, 1fr);
gap: 32px;
}
.footer-brand .brand-name {
color: var(--white);
font-size: 1.2rem;
font-weight: 800;
}
.footer-brand .brand-name em {
color: var(--mint-d);
}
.footer-brand p {
margin-top: 12px;
color: #9fb6bf;
max-width: 34ch;
font-size: 0.92rem;
}
.footer-col h4 {
color: var(--white);
font-size: 0.92rem;
margin-bottom: 14px;
font-weight: 700;
}
.footer-col a,
.footer-col p {
display: block;
color: #9fb6bf;
font-size: 0.9rem;
margin-bottom: 9px;
transition: color 0.15s;
}
.footer-col a:hover {
color: var(--mint-d);
}
.footer-base {
border-top: 1px solid rgba(255, 255, 255, 0.08);
max-width: var(--maxw);
margin: 0 auto;
padding: 20px 24px;
display: flex;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
font-size: 0.84rem;
color: #7d97a1;
}
/* ── Toast ────────────────────────────────────────────────── */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translateX(-50%) translateY(12px);
background: var(--ink);
color: var(--white);
padding: 13px 22px;
border-radius: 999px;
font-weight: 600;
font-size: 0.92rem;
box-shadow: var(--shadow-2);
z-index: 300;
opacity: 0;
transition: opacity 0.25s, transform 0.25s;
max-width: calc(100vw - 32px);
text-align: center;
}
.toast:not([hidden]) {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* ── Modal ────────────────────────────────────────────────── */
.modal {
position: fixed;
inset: 0;
z-index: 400;
display: grid;
place-items: center;
padding: 20px;
}
.modal[hidden] { display: none; }
.modal-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 44, 58, 0.5);
backdrop-filter: blur(3px);
animation: fade 0.2s ease;
}
.modal-card {
position: relative;
background: var(--white);
border-radius: var(--r-xl);
padding: 36px 34px;
width: min(440px, 100%);
box-shadow: var(--shadow-2);
animation: pop 0.24s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.modal-x {
position: absolute;
top: 16px;
right: 16px;
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid var(--line);
background: var(--white);
cursor: pointer;
font-size: 0.9rem;
color: var(--ink-2);
transition: background 0.15s;
}
.modal-x:hover {
background: var(--mint-50);
}
.modal-emoji {
font-size: 2.6rem;
}
.modal-card h2 {
font-size: 1.5rem;
font-weight: 800;
margin: 8px 0 6px;
letter-spacing: -0.02em;
}
.modal-sub {
color: var(--ink-2);
margin-bottom: 22px;
}
.field {
display: block;
margin-bottom: 16px;
}
.field span {
display: block;
font-weight: 600;
font-size: 0.88rem;
margin-bottom: 6px;
color: var(--ink-2);
}
.field input,
.field select {
width: 100%;
font: inherit;
padding: 12px 14px;
border: 1px solid var(--line-2);
border-radius: var(--r-sm);
background: var(--bg);
color: var(--ink);
transition: border-color 0.15s, box-shadow 0.15s;
}
.field input:focus,
.field select:focus {
outline: none;
border-color: var(--blue);
box-shadow: 0 0 0 3px rgba(91, 141, 239, 0.18);
}
.field input:invalid:not(:placeholder-shown) {
border-color: var(--danger);
}
@keyframes fade {
from {
opacity: 0;
}
}
@keyframes pop {
from {
opacity: 0;
transform: translateY(14px) scale(0.96);
}
}
/* ── Reveal on scroll ─────────────────────────────────────── */
.reveal {
opacity: 0;
transform: translateY(22px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-in {
opacity: 1;
transform: none;
}
/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 920px) {
.hero {
grid-template-columns: 1fr;
padding-top: 44px;
}
.hero-art {
order: -1;
min-height: 280px;
}
.services-grid {
grid-template-columns: repeat(2, 1fr);
}
.team-strip {
grid-template-columns: repeat(2, 1fr);
}
.faq-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 520px) {
html {
scroll-padding-top: 72px;
}
.nav-inner {
padding: 12px 16px;
}
.nav-links {
position: fixed;
inset: 64px 12px auto 12px;
flex-direction: column;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 10px;
box-shadow: var(--shadow-2);
gap: 2px;
transform-origin: top;
transform: scaleY(0.6);
opacity: 0;
pointer-events: none;
transition: transform 0.2s ease, opacity 0.2s ease;
}
.nav-links.is-open {
transform: scaleY(1);
opacity: 1;
pointer-events: auto;
}
.nav-links a {
padding: 12px 14px;
}
.phone {
display: none;
}
.nav-toggle {
display: flex;
}
.hero {
padding: 32px 16px 24px;
}
.hero-trust {
gap: 22px;
}
.section {
padding: 44px 16px;
}
.services-grid {
grid-template-columns: 1fr;
}
.team-strip {
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.dentist .bio {
display: none;
}
.compare {
height: 260px;
}
.compare-smile {
font-size: 5rem;
}
.offers-inner {
padding: 28px 22px;
flex-direction: column;
align-items: flex-start;
}
.offers,
.section,
.hero {
margin-left: auto;
margin-right: auto;
}
.footer-inner {
grid-template-columns: 1fr 1fr;
gap: 26px;
}
.footer-brand {
grid-column: 1 / -1;
}
.footer-base {
flex-direction: column;
gap: 4px;
}
.btn-lg {
padding: 13px 22px;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
.reveal {
opacity: 1;
transform: none;
}
}// ── Toast helper ─────────────────────────────────────────────────────────────
const toastEl = document.getElementById("toast");
function toast(msg) {
toastEl.textContent = msg;
toastEl.hidden = false;
clearTimeout(toast._t);
toast._t = setTimeout(() => (toastEl.hidden = true), 2800);
}
// ── Sticky nav shadow on scroll ──────────────────────────────────────────────
const nav = document.getElementById("nav");
const onScroll = () => nav.classList.toggle("is-scrolled", window.scrollY > 8);
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
// ── Mobile menu ──────────────────────────────────────────────────────────────
const navToggle = document.getElementById("navToggle");
const navLinks = document.getElementById("navLinks");
function setMenu(open) {
navLinks.classList.toggle("is-open", open);
navToggle.setAttribute("aria-expanded", String(open));
navToggle.setAttribute("aria-label", open ? "Close menu" : "Open menu");
}
navToggle.addEventListener("click", () =>
setMenu(navToggle.getAttribute("aria-expanded") !== "true")
);
navLinks.querySelectorAll("a").forEach((a) => a.addEventListener("click", () => setMenu(false)));
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") setMenu(false);
});
// ── Animated hero stat counters ──────────────────────────────────────────────
function animateCount(el, target, decimals = 0, suffix = "") {
const dur = 1400;
const start = performance.now();
const step = (now) => {
const p = Math.min((now - start) / dur, 1);
const eased = 1 - Math.pow(1 - p, 3);
const val = (target * eased).toFixed(decimals);
el.textContent = (decimals ? val : Math.round(target * eased).toLocaleString()) + suffix;
if (p < 1) requestAnimationFrame(step);
else el.textContent = (decimals ? target.toFixed(decimals) : target.toLocaleString()) + suffix;
};
requestAnimationFrame(step);
}
let statsDone = false;
function runStats() {
if (statsDone) return;
statsDone = true;
animateCount(document.getElementById("statPatients"), 12400, 0, "+");
animateCount(document.getElementById("statRating"), 4.9, 1);
animateCount(document.getElementById("statYears"), 18, 0);
}
// ── Reveal-on-scroll ─────────────────────────────────────────────────────────
const reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
const io = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-in");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.14, rootMargin: "0px 0px -40px 0px" }
);
reveals.forEach((el) => io.observe(el));
const heroObserver = new IntersectionObserver(
(entries) => {
if (entries.some((e) => e.isIntersecting)) {
runStats();
heroObserver.disconnect();
}
},
{ threshold: 0.4 }
);
heroObserver.observe(document.querySelector(".hero"));
} else {
reveals.forEach((el) => el.classList.add("is-in"));
runStats();
}
// ── Before / After slider ────────────────────────────────────────────────────
const range = document.getElementById("compareRange");
const beforePane = document.getElementById("compareBefore");
const handle = document.getElementById("compareHandle");
function setCompare(v) {
beforePane.style.width = v + "%";
handle.style.left = v + "%";
}
range.addEventListener("input", (e) => setCompare(e.target.value));
setCompare(range.value);
// ── FAQ accordion ────────────────────────────────────────────────────────────
document.querySelectorAll(".faq-item").forEach((item) => {
const q = item.querySelector(".faq-q");
const a = item.querySelector(".faq-a");
q.addEventListener("click", () => {
const open = item.classList.toggle("is-open");
q.setAttribute("aria-expanded", String(open));
a.style.maxHeight = open ? a.scrollHeight + "px" : null;
});
});
// ── Booking modal ────────────────────────────────────────────────────────────
const modal = document.getElementById("bookModal");
const bookForm = document.getElementById("bookForm");
let lastFocus = null;
function openModal(trigger) {
lastFocus = trigger || document.activeElement;
modal.hidden = false;
document.body.style.overflow = "hidden";
const first = modal.querySelector("input, select, button");
if (first) first.focus();
}
function closeModal() {
modal.hidden = true;
document.body.style.overflow = "";
if (lastFocus) lastFocus.focus();
}
["navBook", "heroBook", "offerBook", "hoursBook"].forEach((id) => {
const el = document.getElementById(id);
if (el) el.addEventListener("click", () => openModal(el));
});
modal.querySelectorAll("[data-close]").forEach((el) =>
el.addEventListener("click", closeModal)
);
document.addEventListener("keydown", (e) => {
if (e.key === "Escape" && !modal.hidden) closeModal();
});
// Simple focus trap inside the modal
modal.addEventListener("keydown", (e) => {
if (e.key !== "Tab") return;
const focusables = modal.querySelectorAll(
'a[href], button:not([disabled]), input, select, textarea'
);
if (!focusables.length) return;
const first = focusables[0];
const last = focusables[focusables.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
bookForm.addEventListener("submit", (e) => {
e.preventDefault();
const data = new FormData(bookForm);
const name = (data.get("name") || "").toString().trim();
const phone = (data.get("phone") || "").toString().trim();
if (!name || !phone) {
toast("Please add your name and phone so we can confirm.");
return;
}
const service = data.get("service");
closeModal();
bookForm.reset();
toast(`Thanks, ${name.split(" ")[0]}! We'll text you about your ${service.toLowerCase()} visit.`);
});
// ── Service cards: keyboard activation opens booking ─────────────────────────
document.querySelectorAll(".service-card").forEach((card) => {
const book = () => {
const svc = card.querySelector("h3").textContent;
const select = bookForm.querySelector("select");
const match = Array.from(select.options).find((o) =>
svc.toLowerCase().includes(o.value.toLowerCase().split(" ")[0])
);
if (match) select.value = match.value;
openModal(card);
};
card.addEventListener("click", book);
card.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
book();
}
});
});<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Brighter smiles start here — modern, gentle dental care at Brightline Dental Studio." />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
/>
<link rel="stylesheet" href="style.css" />
<title>Home · Brightline Dental Studio</title>
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<!-- ── Sticky nav ───────────────────────────────────────────── -->
<header class="nav" id="nav">
<div class="nav-inner">
<a class="brand" href="#top" aria-label="Brightline Dental Studio home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none">
<path
d="M12 3c-2.2-1.4-4.6-1.3-6 .2C4.3 5 4.4 8 5.2 11.5c.5 2.2.9 4.5 1.6 6.6.4 1.2 1.6 1.6 2.3.5.6-1 .8-2.5 1.2-3.6.3-.8.6-1.3 1.7-1.3s1.4.5 1.7 1.3c.4 1.1.6 2.6 1.2 3.6.7 1.1 1.9.7 2.3-.5.7-2.1 1.1-4.4 1.6-6.6C19.6 8 19.7 5 18 3.2c-1.4-1.5-3.8-1.6-6-.2Z"
fill="currentColor"
/>
</svg>
</span>
<span class="brand-name">Brightline <em>Dental</em></span>
</a>
<nav class="nav-links" id="navLinks" aria-label="Primary">
<a href="#services">Services</a>
<a href="#results">Results</a>
<a href="#team">Dentists</a>
<a href="#faq">FAQ</a>
</nav>
<div class="nav-cta">
<a class="phone" href="tel:+15550148820" aria-label="Call the clinic">
<span aria-hidden="true">☎</span> (555) 014-8820
</a>
<button class="btn btn-primary" id="navBook" type="button">Book a visit</button>
<button
class="nav-toggle"
id="navToggle"
type="button"
aria-expanded="false"
aria-controls="navLinks"
aria-label="Open menu"
>
<span></span><span></span><span></span>
</button>
</div>
</div>
</header>
<main id="main">
<span id="top"></span>
<!-- ── Hero ───────────────────────────────────────────────── -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero-copy reveal">
<span class="eyebrow">✦ Accepting new patients</span>
<h1 id="hero-title">Brighter smiles<br />start here.</h1>
<p class="lede">
Gentle, modern dentistry for the whole family. From routine cleanings to
invisible aligners, our team at Brightline keeps every visit calm, clear and
comfortable.
</p>
<div class="hero-actions">
<button class="btn btn-primary btn-lg" id="heroBook" type="button">
Book your free consult
</button>
<a class="btn btn-ghost btn-lg" href="#services">Explore care →</a>
</div>
<ul class="hero-trust" aria-label="Why patients choose us">
<li><strong id="statPatients">0</strong><span>Smiles cared for</span></li>
<li><strong id="statRating">0.0</strong><span>Average rating</span></li>
<li><strong id="statYears">0</strong><span>Years of care</span></li>
</ul>
</div>
<div class="hero-art reveal" aria-hidden="true">
<div class="art-card art-card-main">
<div class="tooth-emoji">🦷</div>
<p class="art-tag">Painless check-ups</p>
</div>
<div class="art-chip art-chip-1">
<span class="dot ok"></span> Open today · 8am–6pm
</div>
<div class="art-chip art-chip-2">✨ Same-week appointments</div>
<div class="art-blob art-blob-1"></div>
<div class="art-blob art-blob-2"></div>
</div>
</section>
<!-- ── Services ───────────────────────────────────────────── -->
<section class="section" id="services" aria-labelledby="services-title">
<div class="section-head reveal">
<span class="kicker">Our care</span>
<h2 id="services-title">Everything your smile needs</h2>
<p>Comprehensive dentistry under one calm roof — preventive, cosmetic and urgent.</p>
</div>
<div class="services-grid">
<article class="service-card reveal" tabindex="0">
<span class="svc-icon" aria-hidden="true">🪥</span>
<h3>Cleanings & check-ups</h3>
<p>Thorough hygiene visits with digital scans and a friendly progress report.</p>
<span class="svc-price">From $89</span>
</article>
<article class="service-card reveal" tabindex="0">
<span class="svc-icon" aria-hidden="true">✨</span>
<h3>Teeth whitening</h3>
<p>In-chair and take-home whitening that brightens safely, several shades.</p>
<span class="svc-price">From $199</span>
</article>
<article class="service-card reveal" tabindex="0">
<span class="svc-icon" aria-hidden="true">😁</span>
<h3>Orthodontics</h3>
<p>Clear aligners and braces with a mapped-out plan and 3D preview.</p>
<span class="svc-price">From $2,400</span>
</article>
<article class="service-card reveal" tabindex="0">
<span class="svc-icon" aria-hidden="true">🦷</span>
<h3>Dental implants</h3>
<p>Natural-looking, lasting tooth replacement placed by our specialists.</p>
<span class="svc-price">From $1,950</span>
</article>
<article class="service-card reveal service-card-urgent" tabindex="0">
<span class="svc-icon" aria-hidden="true">🚑</span>
<h3>Emergency care</h3>
<p>Sudden pain or a broken tooth? Same-day slots are held open daily.</p>
<span class="svc-price">Same-day</span>
</article>
<article class="service-card reveal" tabindex="0">
<span class="svc-icon" aria-hidden="true">🧒</span>
<h3>Kids' dentistry</h3>
<p>Patient, playful visits that help children feel at home in the chair.</p>
<span class="svc-price">From $69</span>
</article>
</div>
</section>
<!-- ── Before / After ─────────────────────────────────────── -->
<section class="section" id="results" aria-labelledby="results-title">
<div class="section-head reveal">
<span class="kicker">Real results</span>
<h2 id="results-title">See the difference</h2>
<p>Drag the handle to compare a whitening & alignment journey.</p>
</div>
<div class="compare reveal" id="compare">
<div class="compare-pane compare-after" aria-hidden="true">
<div class="compare-smile smile-after">😁</div>
<span class="compare-label">After</span>
</div>
<div class="compare-pane compare-before" id="compareBefore" aria-hidden="true">
<div class="compare-smile smile-before">😬</div>
<span class="compare-label">Before</span>
</div>
<input
class="compare-range"
id="compareRange"
type="range"
min="0"
max="100"
value="50"
aria-label="Reveal before and after"
/>
<div class="compare-handle" id="compareHandle" aria-hidden="true">
<span>‹ ›</span>
</div>
</div>
</section>
<!-- ── Offers band ────────────────────────────────────────── -->
<section class="offers reveal" aria-label="Current offer">
<div class="offers-inner">
<div class="offers-text">
<span class="offers-badge">Limited offer</span>
<h2>Your first consult is on us.</h2>
<p>New patients get a complimentary exam, X-ray and whitening assessment — no obligation.</p>
</div>
<button class="btn btn-light btn-lg" id="offerBook" type="button">Claim free consult</button>
</div>
</section>
<!-- ── Dentists strip ─────────────────────────────────────── -->
<section class="section" id="team" aria-labelledby="team-title">
<div class="section-head reveal">
<span class="kicker">Meet the team</span>
<h2 id="team-title">Dentists you'll feel calm with</h2>
</div>
<div class="team-strip">
<article class="dentist reveal">
<div class="avatar" style="--a:#5b8def" aria-hidden="true">LO</div>
<h3>Dr. Lena Okafor</h3>
<p class="role">Lead Dentist · Cosmetic</p>
<p class="bio">Gentle smile makeovers with a steady, reassuring hand.</p>
</article>
<article class="dentist reveal">
<div class="avatar" style="--a:#3fb6a0" aria-hidden="true">MR</div>
<h3>Dr. Mateo Rivera</h3>
<p class="role">Orthodontist</p>
<p class="bio">Clear-aligner specialist who loves a well-mapped plan.</p>
</article>
<article class="dentist reveal">
<div class="avatar" style="--a:#7a6cf0" aria-hidden="true">SN</div>
<h3>Dr. Sana Nair</h3>
<p class="role">Implant Surgeon</p>
<p class="bio">Precise, lasting implants and a calm chair-side manner.</p>
</article>
<article class="dentist reveal">
<div class="avatar" style="--a:#f0a35b" aria-hidden="true">EC</div>
<h3>Eli Chen, RDH</h3>
<p class="role">Lead Hygienist</p>
<p class="bio">Makes cleanings genuinely relaxing — kids ask for him.</p>
</article>
</div>
</section>
<!-- ── FAQ + Hours ────────────────────────────────────────── -->
<section class="section faq-section" id="faq" aria-labelledby="faq-title">
<div class="faq-grid">
<div class="faq-col">
<div class="section-head section-head-left reveal">
<span class="kicker">Good to know</span>
<h2 id="faq-title">Frequently asked</h2>
</div>
<div class="faq-list reveal" id="faqList">
<div class="faq-item">
<button class="faq-q" type="button" aria-expanded="false">
Do you take my insurance?
<span class="faq-icon" aria-hidden="true">+</span>
</button>
<div class="faq-a"><p>We accept most major plans and offer transparent self-pay quotes. We'll check your coverage before any treatment so there are no surprises.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" type="button" aria-expanded="false">
Does whitening hurt?
<span class="faq-icon" aria-hidden="true">+</span>
</button>
<div class="faq-a"><p>Most patients feel nothing more than mild, temporary sensitivity. We use a gentle gel and a desensitising rinse to keep you comfortable.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" type="button" aria-expanded="false">
How soon can I be seen?
<span class="faq-icon" aria-hidden="true">+</span>
</button>
<div class="faq-a"><p>New-patient exams are usually available the same week, and we always hold emergency slots open for same-day dental pain.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" type="button" aria-expanded="false">
Are kids welcome?
<span class="faq-icon" aria-hidden="true">+</span>
</button>
<div class="faq-a"><p>Absolutely. Our team specialises in calm, playful first visits to help children build a lifelong, fear-free relationship with the dentist.</p></div>
</div>
</div>
</div>
<aside class="hours-card reveal" aria-label="Opening hours">
<h3>Opening hours</h3>
<ul class="hours-list">
<li><span>Mon – Thu</span><strong>8:00 – 18:00</strong></li>
<li class="is-today"><span>Friday</span><strong>8:00 – 18:00</strong></li>
<li><span>Saturday</span><strong>9:00 – 14:00</strong></li>
<li><span>Sunday</span><strong class="closed">Closed</strong></li>
</ul>
<div class="hours-foot">
<p class="addr">128 Maple Row, Brightline Square</p>
<button class="btn btn-primary btn-block" id="hoursBook" type="button">Book a visit</button>
</div>
</aside>
</div>
</section>
</main>
<!-- ── Footer ───────────────────────────────────────────────── -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-brand">
<span class="brand-name">Brightline <em>Dental</em></span>
<p>Brighter smiles, gently done. Modern dentistry for every member of your family.</p>
</div>
<nav class="footer-col" aria-label="Care">
<h4>Care</h4>
<a href="#services">Cleanings</a>
<a href="#services">Whitening</a>
<a href="#services">Orthodontics</a>
<a href="#services">Implants</a>
</nav>
<nav class="footer-col" aria-label="Clinic">
<h4>Clinic</h4>
<a href="#team">Our dentists</a>
<a href="#faq">FAQ</a>
<a href="#results">Results</a>
<a href="tel:+15550148820">(555) 014-8820</a>
</nav>
<div class="footer-col">
<h4>Visit us</h4>
<p>128 Maple Row<br />Brightline Square, 02140</p>
<p>[email protected]</p>
</div>
</div>
<div class="footer-base">
<p>© 2026 Brightline Dental Studio · A fictional clinic.</p>
<p>Illustrative UI only — not for real medical use.</p>
</div>
</footer>
<div id="toast" class="toast" role="status" aria-live="polite" hidden></div>
<!-- ── Booking dialog ───────────────────────────────────────── -->
<div class="modal" id="bookModal" hidden>
<div class="modal-backdrop" data-close></div>
<div class="modal-card" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
<button class="modal-x" type="button" data-close aria-label="Close">✕</button>
<span class="modal-emoji" aria-hidden="true">🦷</span>
<h2 id="modalTitle">Book your visit</h2>
<p class="modal-sub">Tell us a little and we'll confirm by text within the hour.</p>
<form id="bookForm" novalidate>
<label class="field">
<span>Your name</span>
<input type="text" name="name" required placeholder="Jordan Avery" autocomplete="name" />
</label>
<label class="field">
<span>Phone</span>
<input type="tel" name="phone" required placeholder="(555) 000-0000" autocomplete="tel" />
</label>
<label class="field">
<span>What do you need?</span>
<select name="service">
<option>Cleaning & check-up</option>
<option>Teeth whitening</option>
<option>Orthodontics consult</option>
<option>Dental implants</option>
<option>Emergency / dental pain</option>
<option>Kids' dentistry</option>
</select>
</label>
<button class="btn btn-primary btn-block btn-lg" type="submit">Request appointment</button>
</form>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Dental Clinic Landing
A calm, airy marketing page for Brightline Dental Studio, built in a rounded mint-and-soft-blue theme. A sticky, frosted nav gains a subtle shadow as you scroll and collapses into a tidy mobile menu below 520px. The hero pairs a clear Brighter smiles start here headline and a free-consult call to action with a floating tooth motif, status chips and three trust stats that count up the first time the hero scrolls into view.
Below, a six-card services grid covers cleanings, whitening, orthodontics, implants, emergency and kids’ dentistry — each card is keyboard-focusable and pre-selects its own service when it opens the booking dialog. A draggable before-and-after slider reveals a whitening-and-alignment journey, an offers band highlights the complimentary first consult, and a four-dentist strip introduces the team with realistic but clearly fictional names. An accordion FAQ sits beside a today-aware opening hours card.
Every section reveals on scroll, and any Book button opens an accessible modal with a focus trap, Escape-to-close and inline validation; submitting confirms with a friendly toast. All interactions are vanilla JS with no external libraries.
Illustrative UI only — not intended for real medical use.