Map supporting pan, zoom and selectable markers.
<div class="imap">
<div class="imap__viewport">
<div class="imap__layer" style="transform:scale(100%);">
<details class="imap__marker" style="left:30%;top:38%;">
<summary class="imap__pin" style="background:#241430;" aria-label="Marker: Studio HQ"></summary>
<div class="imap__popover">Studio HQ</div>
</details>
<details class="imap__marker" style="left:64%;top:56%;">
<summary class="imap__pin" style="background:#241430;" aria-label="Marker: Riverside Cafe"></summary>
<div class="imap__popover">Riverside Cafe</div>
</details>
</div>
</div>
</div>
<style>
.imap { max-width: 360px; font: 12px/1.4 system-ui, sans-serif; color: #241430; }
.imap__viewport { position: relative; aspect-ratio: 4 / 3; overflow: hidden; border-radius: 12px; border: 1px solid #24143022; background: linear-gradient(#D9C8F0, #BFD9F2); cursor: grab; }
.imap__layer { position: absolute; inset: 0; transform-origin: center; background-image: repeating-linear-gradient(0deg, #24143014 0 1px, transparent 1px 40px), repeating-linear-gradient(90deg, #24143014 0 1px, transparent 1px 40px); }
.imap__marker { position: absolute; list-style: none; }
.imap__pin { display: block; width: 18px; height: 18px; border-radius: 50% 50% 50% 0; transform: translate(-50%, -100%) rotate(-45deg); cursor: pointer; border: 2px solid #FAF7F2; list-style: none; }
.imap__pin::marker { content: ""; }
.imap__pin::-webkit-details-marker { display: none; }
.imap__pin:focus-visible { outline: 2px solid #241430; outline-offset: 2px; }
.imap__popover { position: absolute; left: 0; bottom: calc(100% + 6px); padding: 4px 8px; border-radius: 6px; background: #241430; color: #FAF7F2; font-size: 11px; white-space: nowrap; }
.imap__perm-label { position: absolute; top: 2px; left: 22px; font-size: 10px; color: #241430cc; white-space: nowrap; }
@media (prefers-reduced-motion: no-preference) {
.imap__layer { transition: transform .2s ease; }
}
</style><div class="imap-tw max-w-[360px] font-sans text-xs text-[#241430]">
<div class="imap-tw__viewport relative overflow-hidden rounded-xl border border-[#24143022] cursor-grab" style="aspect-ratio:4/3;background:linear-gradient(#D9C8F0,#BFD9F2);">
<div class="imap-tw__layer absolute inset-0" style="transform:scale(100%);transform-origin:center;background-image:repeating-linear-gradient(0deg,#24143014 0 1px,transparent 1px 40px),repeating-linear-gradient(90deg,#24143014 0 1px,transparent 1px 40px);">
<details class="imap-tw__marker absolute list-none" style="left:30%;top:38%;">
<summary class="imap-tw__pin block w-[18px] h-[18px] cursor-pointer border-2 border-[#FAF7F2]" style="background:#241430;border-radius:50% 50% 50% 0;transform:translate(-50%,-100%) rotate(-45deg);" aria-label="Marker: Studio HQ"></summary>
<div class="absolute left-0 px-2 py-1 rounded-md bg-[#241430] text-[#FAF7F2] text-[11px] whitespace-nowrap" style="bottom:calc(100% + 6px);">Studio HQ</div>
</details>
<details class="imap-tw__marker absolute list-none" style="left:64%;top:56%;">
<summary class="imap-tw__pin block w-[18px] h-[18px] cursor-pointer border-2 border-[#FAF7F2]" style="background:#241430;border-radius:50% 50% 50% 0;transform:translate(-50%,-100%) rotate(-45deg);" aria-label="Marker: Riverside Cafe"></summary>
<div class="absolute left-0 px-2 py-1 rounded-md bg-[#241430] text-[#FAF7F2] text-[11px] whitespace-nowrap" style="bottom:calc(100% + 6px);">Riverside Cafe</div>
</details>
</div>
</div>
</div>
<style>
.imap-tw__pin::-webkit-details-marker { display: none; }
.imap-tw__pin::marker { content: ""; }
.imap-tw__pin:focus-visible { outline: 2px solid #241430; outline-offset: 2px; }
</style>export function InteractiveMap({
zoom = "100%",
markerLabel = "Studio HQ",
accent = "#241430",
showLabels = false,
}) {
const markers = [
{ left: "30%", top: "38%", label: markerLabel },
{ left: "64%", top: "56%", label: "Riverside Cafe" },
];
return (
<div style={{ maxWidth: 360, font: "12px/1.4 system-ui, sans-serif", color: "#241430" }}>
<div style={{ position: "relative", aspectRatio: "4 / 3", overflow: "hidden", borderRadius: 12,
border: "1px solid #24143022", background: "linear-gradient(#D9C8F0, #BFD9F2)", cursor: "grab" }}>
<div className="map-content" style={{ position: "absolute", inset: 0, transformOrigin: "center",
transform: `scale(${zoom})`,
backgroundImage: "repeating-linear-gradient(0deg, #24143014 0 1px, transparent 1px 40px), repeating-linear-gradient(90deg, #24143014 0 1px, transparent 1px 40px)" }}>
{markers.map((m) => (
<details key={m.label} style={{ position: "absolute", left: m.left, top: m.top, listStyle: "none" }}>
<summary
style={{ display: "block", width: 18, height: 18, borderRadius: "50% 50% 50% 0",
transform: "translate(-50%, -100%) rotate(-45deg)", cursor: "pointer", border: "2px solid #FAF7F2",
background: accent, listStyle: "none" }}
aria-label={`Marker: ${m.label}`}
/>
<div style={{ position: "absolute", left: 0, bottom: "calc(100% + 6px)", padding: "4px 8px",
borderRadius: 6, background: "#241430", color: "#FAF7F2", fontSize: 11, whiteSpace: "nowrap" }}>
{m.label}
</div>
{showLabels && (
<span style={{ position: "absolute", top: 2, left: 22, fontSize: 10, color: "#241430cc", whiteSpace: "nowrap" }}>
{m.label}
</span>
)}
</details>
))}
</div>
</div>
<style>{`
@media (prefers-reduced-motion: no-preference) {
.map-content { transition: transform .2s ease; }
}
`}</style>
</div>
);
}