Dental — Office Tour
A trust-first virtual office tour for a dental practice: a labeled photo gallery grouped by area (reception, operatory, sterilization lab, consult room), room-filter chips, a keyboard-navigable lightbox with captions and counters, and a friendly amenities checklist. Clean clinical light styling, rounded cards, soft shadows and lots of calm white space help nervous patients feel at ease before their first visit.
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;
--sh-sm: 0 1px 2px rgba(15, 39, 64, 0.06), 0 2px 8px rgba(15, 39, 64, 0.05);
--sh-md: 0 6px 20px rgba(15, 39, 64, 0.09), 0 2px 6px rgba(15, 39, 64, 0.05);
--sh-lg: 0 24px 60px rgba(15, 39, 64, 0.28);
}
* { 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 85% -10%, var(--blue-50), transparent 60%),
radial-gradient(900px 500px at -5% 10%, var(--mint-50), transparent 55%),
var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
.wrap {
max-width: 1080px;
margin: 0 auto;
padding: clamp(20px, 4vw, 48px) clamp(16px, 4vw, 32px) 64px;
}
/* ---------- Header ---------- */
.tour-head {
display: flex;
gap: 28px;
align-items: flex-end;
justify-content: space-between;
flex-wrap: wrap;
margin-bottom: 28px;
}
.head-copy { max-width: 560px; }
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--blue-d);
background: var(--white);
border: 1px solid var(--line);
padding: 6px 12px;
border-radius: 999px;
box-shadow: var(--sh-sm);
}
.eyebrow .dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--mint);
box-shadow: 0 0 0 4px var(--mint-50);
}
.tour-head h1 {
font-size: clamp(1.7rem, 4vw, 2.4rem);
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1.1;
margin: 16px 0 10px;
color: var(--ink);
}
.lede {
margin: 0 0 20px;
color: var(--ink-2);
font-size: 1.02rem;
}
.head-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.btn {
font: inherit;
font-weight: 600;
font-size: 0.94rem;
border-radius: var(--r-md);
padding: 11px 20px;
border: 1px solid transparent;
cursor: pointer;
transition: transform 0.12s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
background: linear-gradient(180deg, var(--blue), var(--blue-d));
color: #fff;
box-shadow: var(--sh-md);
}
.btn-primary:hover { box-shadow: 0 10px 26px rgba(37, 99, 235, 0.32); transform: translateY(-1px); }
.btn-ghost {
background: var(--white);
color: var(--ink);
border-color: var(--line-2);
box-shadow: var(--sh-sm);
}
.btn-ghost:hover { border-color: var(--blue); color: var(--blue-d); }
.head-stats {
display: flex;
gap: 10px;
margin: 0;
padding: 0;
}
.head-stats > div {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 12px 16px;
min-width: 84px;
text-align: center;
box-shadow: var(--sh-sm);
}
.head-stats dt { font-size: 0.72rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.head-stats dd { margin: 4px 0 0; font-size: 1.3rem; font-weight: 800; color: var(--ink); }
/* ---------- Filters ---------- */
.filters {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 22px;
}
.chip {
font: inherit;
font-weight: 600;
font-size: 0.9rem;
color: var(--ink-2);
background: var(--white);
border: 1px solid var(--line-2);
border-radius: 999px;
padding: 9px 16px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.chip:hover { border-color: var(--blue); color: var(--blue-d); transform: translateY(-1px); }
.chip .count {
font-size: 0.74rem;
font-weight: 700;
color: var(--muted);
background: var(--blue-50);
border-radius: 999px;
padding: 1px 8px;
min-width: 20px;
text-align: center;
}
.chip.is-active {
background: linear-gradient(180deg, var(--blue), var(--blue-d));
color: #fff;
border-color: transparent;
box-shadow: var(--sh-md);
}
.chip.is-active .count { background: rgba(255, 255, 255, 0.22); color: #fff; }
/* ---------- Gallery ---------- */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 18px;
margin-bottom: 48px;
}
.card {
position: relative;
border: 1px solid var(--line);
border-radius: var(--r-lg);
background: var(--white);
overflow: hidden;
cursor: pointer;
text-align: left;
font: inherit;
padding: 0;
color: inherit;
box-shadow: var(--sh-sm);
transition: transform 0.16s ease, box-shadow 0.24s ease, border-color 0.2s ease;
animation: rise 0.4s ease both;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--sh-md); border-color: var(--line-2); }
.card:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.card-media {
height: 168px;
position: relative;
overflow: hidden;
}
.card-media .ph {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
transition: transform 0.5s ease;
}
.card:hover .card-media .ph { transform: scale(1.07); }
.card-media::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg, transparent 45%, rgba(15, 39, 64, 0.45));
}
.badge {
position: relative;
z-index: 1;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.02em;
color: var(--blue-d);
background: rgba(255, 255, 255, 0.94);
border-radius: 999px;
padding: 5px 11px;
box-shadow: var(--sh-sm);
}
.card-media .badge { position: absolute; top: 12px; left: 12px; }
.card-zoom {
position: absolute;
bottom: 12px;
right: 12px;
z-index: 1;
width: 34px;
height: 34px;
display: grid;
place-items: center;
border-radius: 50%;
background: rgba(255, 255, 255, 0.92);
color: var(--blue-d);
font-size: 1rem;
box-shadow: var(--sh-sm);
opacity: 0;
transform: scale(0.8);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.card:hover .card-zoom { opacity: 1; transform: scale(1); }
.card-body { padding: 14px 16px 16px; }
.card-body h3 { margin: 0 0 4px; font-size: 1.02rem; font-weight: 700; color: var(--ink); }
.card-body p { margin: 0; font-size: 0.86rem; color: var(--muted); }
/* ---------- Amenities ---------- */
.amenities {
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: clamp(20px, 3vw, 30px);
box-shadow: var(--sh-sm);
}
.am-head h2 { margin: 0 0 4px; font-size: 1.35rem; font-weight: 800; letter-spacing: -0.01em; }
.am-head p { margin: 0 0 20px; color: var(--muted); }
.am-grid {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 14px;
}
.am-item {
display: flex;
gap: 13px;
align-items: flex-start;
padding: 14px;
border-radius: var(--r-md);
border: 1px solid var(--line);
background: var(--blue-50);
transition: border-color 0.2s ease, background 0.2s ease, transform 0.14s ease;
}
.am-item:hover { border-color: var(--blue); background: var(--white); transform: translateY(-2px); }
.am-icon {
flex: 0 0 auto;
width: 38px;
height: 38px;
border-radius: 11px;
display: grid;
place-items: center;
font-size: 1.1rem;
background: var(--white);
color: var(--blue-d);
box-shadow: var(--sh-sm);
}
.am-item.mint .am-icon { color: var(--ok); background: var(--mint-50); }
.am-text strong { display: block; font-size: 0.94rem; color: var(--ink); }
.am-text span { font-size: 0.82rem; color: var(--ink-2); }
/* ---------- Lightbox ---------- */
.lightbox {
position: fixed;
inset: 0;
z-index: 60;
display: grid;
place-items: center;
padding: 20px;
}
.lightbox[hidden] { display: none; }
.lb-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 39, 64, 0.62);
backdrop-filter: blur(4px);
animation: fade 0.25s ease both;
}
.lb-panel {
position: relative;
z-index: 1;
width: min(760px, 100%);
background: var(--white);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--sh-lg);
animation: pop 0.28s cubic-bezier(0.2, 0.8, 0.3, 1.1) both;
}
.lb-image {
height: min(52vh, 440px);
background-size: cover;
background-position: center;
background-color: var(--blue-50);
}
.lb-caption { padding: 18px 22px 22px; }
.lb-cap-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.lb-counter { font-size: 0.82rem; font-weight: 700; color: var(--muted); }
.lb-caption h3 { margin: 0 0 6px; font-size: 1.3rem; font-weight: 800; letter-spacing: -0.01em; }
.lb-caption p { margin: 0; color: var(--ink-2); font-size: 0.95rem; }
.lb-close {
position: absolute;
top: 12px;
right: 12px;
z-index: 2;
width: 38px;
height: 38px;
border-radius: 50%;
border: none;
cursor: pointer;
font-size: 1rem;
color: var(--ink);
background: rgba(255, 255, 255, 0.92);
box-shadow: var(--sh-sm);
transition: background 0.18s ease, transform 0.12s ease;
}
.lb-close:hover { background: #fff; transform: rotate(90deg); }
.lb-nav {
position: absolute;
top: calc(min(52vh, 440px) / 2);
transform: translateY(-50%);
z-index: 2;
width: 46px;
height: 46px;
border-radius: 50%;
border: none;
cursor: pointer;
font-size: 1.6rem;
line-height: 1;
color: var(--blue-d);
background: rgba(255, 255, 255, 0.94);
box-shadow: var(--sh-md);
transition: background 0.18s ease, transform 0.14s ease;
}
.lb-nav:hover { background: #fff; }
.lb-prev { left: 14px; }
.lb-next { right: 14px; }
.lb-prev:hover { transform: translateY(-50%) translateX(-2px); }
.lb-next:hover { transform: translateY(-50%) translateX(2px); }
.lb-close:focus-visible,
.lb-nav:focus-visible,
.btn:focus-visible,
.chip:focus-visible {
outline: 3px solid var(--blue);
outline-offset: 2px;
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 20px);
z-index: 80;
background: var(--ink);
color: #fff;
font-size: 0.9rem;
font-weight: 500;
padding: 12px 20px;
border-radius: 999px;
box-shadow: var(--sh-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Animations ---------- */
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; transform: scale(0.94) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
/* ---------- Responsive ---------- */
@media (max-width: 520px) {
.tour-head { align-items: flex-start; }
.head-stats { width: 100%; }
.head-stats > div { flex: 1; min-width: 0; padding: 10px 8px; }
.head-actions { width: 100%; }
.head-actions .btn { flex: 1; text-align: center; }
.gallery { grid-template-columns: 1fr; }
.card-media { height: 190px; }
.lb-panel { width: 100%; }
.lb-image { height: 40vh; }
.lb-nav { width: 40px; height: 40px; font-size: 1.4rem; }
.lb-caption h3 { font-size: 1.12rem; }
}(function () {
"use strict";
// Fictional but realistic tour data. Unsplash placeholder imagery.
var ROOMS = [
{
area: "reception",
label: "Reception",
title: "Welcome Lounge",
desc: "Step in to a bright, plant-filled lounge with warm lighting, a coffee bar, and comfy seating. Check-in takes under a minute.",
img: "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=1200&q=70",
},
{
area: "reception",
label: "Reception",
title: "Family Waiting Area",
desc: "A quiet corner with a kids' play nook, ceiling-mounted screens, and free Wi-Fi so the whole family stays relaxed.",
img: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=1200&q=70",
},
{
area: "operatory",
label: "Operatory",
title: "Operatory 1 — Comfort Suite",
desc: "Reclining chair with memory foam, an overhead TV, noise-cancelling headphones, and a warm blanket on request.",
img: "https://images.unsplash.com/photo-1629909613654-28e377c37b09?auto=format&fit=crop&w=1200&q=70",
},
{
area: "operatory",
label: "Operatory",
title: "Operatory 2 — Digital Bay",
desc: "Fitted with intraoral scanners and a chairside monitor so you can see exactly what we see, in real time.",
img: "https://images.unsplash.com/photo-1588776814546-1ffcf47267a5?auto=format&fit=crop&w=1200&q=70",
},
{
area: "operatory",
label: "Operatory",
title: "Hygiene Room",
desc: "A calm space dedicated to cleanings and check-ups, with a garden-facing window and gentle ultrasonic tools.",
img: "https://images.unsplash.com/photo-1606811841689-23dfddce3e95?auto=format&fit=crop&w=1200&q=70",
},
{
area: "lab",
label: "Sterilization Lab",
title: "Sterilization Center",
desc: "Glass-walled and fully visible — every instrument is autoclaved and pouch-sealed on-site so you can watch our standards at work.",
img: "https://images.unsplash.com/photo-1583912267550-d6c2ac3196c0?auto=format&fit=crop&w=1200&q=70",
},
{
area: "lab",
label: "Sterilization Lab",
title: "Imaging & X-Ray Suite",
desc: "Low-dose digital radiography and 3D cone-beam imaging, shielded and calibrated for the clearest, safest scans.",
img: "https://images.unsplash.com/photo-1571772996211-2f02c9727629?auto=format&fit=crop&w=1200&q=70",
},
{
area: "consult",
label: "Consult",
title: "Consultation Room",
desc: "A private, screen-side room where we walk through your treatment plan, answer questions, and talk options — no pressure.",
img: "https://images.unsplash.com/photo-1631217868264-e5b90bb7e133?auto=format&fit=crop&w=1200&q=70",
},
];
var AMENITIES = [
{ icon: "😌", mint: true, title: "Sedation options", note: "Nitrous & oral sedation for anxious visits." },
{ icon: "📺", mint: false, title: "Ceiling TVs", note: "Netflix & headphones in every operatory." },
{ icon: "🛋️", mint: false, title: "Warm blankets", note: "Cozy up during longer appointments." },
{ icon: "🧼", mint: true, title: "Open sterilization", note: "Glass-walled lab you can see into." },
{ icon: "♿", mint: false, title: "Step-free access", note: "Ramp entry & wide, accessible rooms." },
{ icon: "☕", mint: true, title: "Coffee & Wi-Fi", note: "Complimentary bar in the lounge." },
];
var gallery = document.getElementById("gallery");
var amWrap = document.getElementById("amenities");
var toastEl = document.getElementById("toast");
var toastTimer = null;
var lb = document.getElementById("lightbox");
var lbImage = document.getElementById("lbImage");
var lbBadge = document.getElementById("lbBadge");
var lbTitle = document.getElementById("lbTitle");
var lbDesc = document.getElementById("lbDesc");
var lbCounter = document.getElementById("lbCounter");
var lbClose = document.getElementById("lbClose");
var lbPrev = document.getElementById("lbPrev");
var lbNext = document.getElementById("lbNext");
var currentFilter = "all";
var visible = []; // indices into ROOMS matching current filter
var lbPos = 0; // position within `visible`
var lastFocused = null;
function decode(html) {
var t = document.createElement("textarea");
t.innerHTML = html;
return t.value;
}
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2400);
}
/* ---------- Render gallery ---------- */
function renderGallery() {
gallery.innerHTML = "";
visible = [];
ROOMS.forEach(function (room, idx) {
if (currentFilter !== "all" && room.area !== currentFilter) return;
visible.push(idx);
var pos = visible.length - 1;
var card = document.createElement("button");
card.type = "button";
card.className = "card";
card.style.animationDelay = (pos * 0.05) + "s";
card.setAttribute("aria-label", "Open " + decode(room.title) + " in tour viewer");
card.innerHTML =
'<div class="card-media">' +
'<div class="ph" style="background-image:url(' + room.img + ')"></div>' +
'<span class="badge">' + room.label + '</span>' +
'<span class="card-zoom" aria-hidden="true">⤢</span>' +
'</div>' +
'<div class="card-body">' +
'<h3>' + room.title + '</h3>' +
'<p>' + room.desc.slice(0, 78) + (decode(room.desc).length > 78 ? '…' : '') + '</p>' +
'</div>';
card.addEventListener("click", function () { openLightbox(pos); });
gallery.appendChild(card);
});
}
/* ---------- Render amenities ---------- */
function renderAmenities() {
AMENITIES.forEach(function (a) {
var li = document.createElement("li");
li.className = "am-item" + (a.mint ? " mint" : "");
li.innerHTML =
'<span class="am-icon" aria-hidden="true">' + a.icon + '</span>' +
'<span class="am-text"><strong>' + a.title + '</strong><span>' + a.note + '</span></span>';
amWrap.appendChild(li);
});
}
/* ---------- Filters ---------- */
function updateCounts() {
var counts = { all: ROOMS.length, reception: 0, operatory: 0, lab: 0, consult: 0 };
ROOMS.forEach(function (r) { counts[r.area]++; });
document.querySelectorAll(".count").forEach(function (el) {
var key = el.getAttribute("data-count");
el.textContent = counts[key];
});
}
document.querySelectorAll(".chip").forEach(function (chip) {
chip.addEventListener("click", function () {
document.querySelectorAll(".chip").forEach(function (c) {
c.classList.remove("is-active");
c.setAttribute("aria-pressed", "false");
});
chip.classList.add("is-active");
chip.setAttribute("aria-pressed", "true");
currentFilter = chip.getAttribute("data-filter");
renderGallery();
});
});
/* ---------- Lightbox ---------- */
function paintLightbox() {
var room = ROOMS[visible[lbPos]];
lbImage.style.backgroundImage = "url(" + room.img + ")";
lbBadge.textContent = room.label;
lbTitle.innerHTML = room.title;
lbDesc.innerHTML = room.desc;
lbCounter.textContent = (lbPos + 1) + " / " + visible.length;
}
function openLightbox(pos) {
if (!visible.length) return;
lbPos = pos;
lastFocused = document.activeElement;
paintLightbox();
lb.hidden = false;
document.body.style.overflow = "hidden";
lbClose.focus();
}
function closeLightbox() {
lb.hidden = true;
document.body.style.overflow = "";
if (lastFocused && typeof lastFocused.focus === "function") lastFocused.focus();
}
function step(delta) {
if (!visible.length) return;
lbPos = (lbPos + delta + visible.length) % visible.length;
paintLightbox();
}
lbClose.addEventListener("click", closeLightbox);
lbPrev.addEventListener("click", function () { step(-1); });
lbNext.addEventListener("click", function () { step(1); });
lb.querySelector(".lb-backdrop").addEventListener("click", closeLightbox);
document.addEventListener("keydown", function (e) {
if (lb.hidden) return;
if (e.key === "Escape") { closeLightbox(); }
else if (e.key === "ArrowLeft") { step(-1); }
else if (e.key === "ArrowRight") { step(1); }
else if (e.key === "Tab") {
// Simple focus trap across the interactive controls.
var focusables = [lbClose, lbPrev, lbNext];
var i = focusables.indexOf(document.activeElement);
if (i === -1) { e.preventDefault(); lbClose.focus(); return; }
e.preventDefault();
var dir = e.shiftKey ? -1 : 1;
focusables[(i + dir + focusables.length) % focusables.length].focus();
}
});
/* ---------- Header actions ---------- */
document.getElementById("shareBtn").addEventListener("click", function () {
var link = "https://brightleaf.dental/tour";
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(link).then(
function () { toast("Tour link copied to clipboard ✓"); },
function () { toast("Tour link: " + link); }
);
} else {
toast("Tour link: " + link);
}
});
document.getElementById("requestBtn").addEventListener("click", function () {
toast("Thanks! Our front desk will reach out to book your visit.");
});
/* ---------- Init ---------- */
updateCounts();
renderGallery();
renderAmenities();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Brightleaf Dental — Office Tour</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="tour-head">
<div class="head-copy">
<span class="eyebrow">
<span class="dot" aria-hidden="true"></span>
Take a look around
</span>
<h1>Brightleaf Dental — Office Tour</h1>
<p class="lede">
A calm, modern practice on Maple Grove. Preview every room before your
first visit — no surprises, just a friendly space built for comfort.
</p>
<div class="head-actions">
<button class="btn btn-primary" id="requestBtn" type="button">Request a visit</button>
<button class="btn btn-ghost" id="shareBtn" type="button">Copy tour link</button>
</div>
</div>
<dl class="head-stats" aria-label="Practice highlights">
<div><dt>Rooms</dt><dd>8</dd></div>
<div><dt>Open since</dt><dd>2014</dd></div>
<div><dt>Rating</dt><dd>4.9★</dd></div>
</dl>
</header>
<nav class="filters" aria-label="Filter rooms">
<button class="chip is-active" type="button" data-filter="all" aria-pressed="true">All areas <span class="count" data-count="all"></span></button>
<button class="chip" type="button" data-filter="reception" aria-pressed="false">Reception <span class="count" data-count="reception"></span></button>
<button class="chip" type="button" data-filter="operatory" aria-pressed="false">Operatory <span class="count" data-count="operatory"></span></button>
<button class="chip" type="button" data-filter="lab" aria-pressed="false">Sterilization Lab <span class="count" data-count="lab"></span></button>
<button class="chip" type="button" data-filter="consult" aria-pressed="false">Consult <span class="count" data-count="consult"></span></button>
</nav>
<section class="gallery" id="gallery" aria-label="Office photo gallery">
<!-- cards injected by script.js -->
</section>
<section class="amenities" aria-labelledby="amTitle">
<div class="am-head">
<h2 id="amTitle">Comfort & amenities</h2>
<p>Little touches that make a big difference.</p>
</div>
<ul class="am-grid" id="amenities">
<!-- amenities injected by script.js -->
</ul>
</section>
</main>
<!-- Lightbox -->
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-labelledby="lbTitle" hidden>
<div class="lb-backdrop" data-close></div>
<div class="lb-panel" role="document">
<button class="lb-close" id="lbClose" type="button" aria-label="Close tour viewer">✕</button>
<button class="lb-nav lb-prev" id="lbPrev" type="button" aria-label="Previous room">‹</button>
<figure class="lb-figure">
<div class="lb-image" id="lbImage"></div>
<figcaption class="lb-caption">
<div class="lb-cap-top">
<span class="badge" id="lbBadge">Reception</span>
<span class="lb-counter" id="lbCounter" aria-live="polite">1 / 8</span>
</div>
<h3 id="lbTitle">Room title</h3>
<p id="lbDesc">Room description.</p>
</figcaption>
</figure>
<button class="lb-nav lb-next" id="lbNext" type="button" aria-label="Next room">›</button>
</div>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>An office-tour block that lets prospective patients preview a dental practice before booking. A row of filter chips (All areas, Reception, Operatory, Lab, Consult) narrows a responsive gallery of labeled cards, each showing an area badge, a short caption, and a hover zoom. Clicking any card opens an accessible lightbox with a large image, its title and description, a live position counter, and previous/next controls.
The lightbox is fully keyboard-driven: arrow keys move between photos, Escape closes it, and focus is trapped and restored so screen-reader and keyboard users are never lost. Filtering re-scopes the lightbox sequence so navigation only walks the currently visible rooms. A small toast confirms actions like copying the tour link or requesting a visit.
Alongside the gallery, an amenities checklist highlights comfort features — sedation options, ceiling TVs, warm blankets, sterilization transparency, and step-free access — each with an icon and one-line note, reinforcing a calm, reassuring first impression.
Illustrative UI only — not intended for real medical use.