Accessibility Map
Whole Romania
${location.ratings.overallScore.toFixed(1)}
`;
return L.divIcon({
html,
className: “”,
iconSize: [36, 36],
iconAnchor: [18, 36],
popupAnchor: [0, -36],
});
}
/** Add markers for the currently-filtered locations and reframe the map. */
function renderMarkers() {
// Remove existing markers
markersById.forEach((m) => m.remove());
markersById.clear();
const visible = LOCATIONS.filter(
(loc) => activeCity === “all” || loc.city === activeCity
);
visible.forEach((loc) => {
const marker = L.marker(
[loc.coordinates.lat, loc.coordinates.lng],
{ icon: buildIcon(loc), title: loc.title }
);
marker.on(“click”, () => openLocationCard(loc));
marker.addTo(map);
markersById.set(loc.id, marker);
});
fitMapToVisible(visible);
}
/** Reframe the map to fit the visible markers. */
function fitMapToVisible(visible) {
if (visible.length === 0) {
map.setView(CONFIG.initialView.center, CONFIG.initialView.zoom);
return;
}
if (visible.length === 1) {
const only = visible[0];
map.setView([only.coordinates.lat, only.coordinates.lng], 15);
return;
}
const bounds = L.latLngBounds(
visible.map((loc) => [loc.coordinates.lat, loc.coordinates.lng])
);
map.fitBounds(bounds, { padding: CONFIG.fitPadding });
}
/* ============================================================================
6) FILTERING
============================================================================ */
function setActiveCity(city) {
activeCity = city;
// Toggle .is-active on the matching drawer filter
dom.filterButtons.forEach((btn) => {
const isMatch = btn.dataset.city === city;
btn.classList.toggle(“is-active”, isMatch);
});
// Update the brand pill so the user can always see the current filter
const label = (() => {
const btn = Array.from(dom.filterButtons).find((b) => b.dataset.city === city);
return btn ? btn.querySelector(“.drawer__filter-label”).textContent : “All”;
})();
dom.brandPillCity.textContent = label;
renderMarkers();
closeLocationCard(); // stale details would be confusing
closeDrawer(); // give the user immediate feedback on the map
}
/* ============================================================================
7) DRAWER
============================================================================ */
function openDrawer() {
dom.drawer.classList.add(“is-open”);
dom.drawer.setAttribute(“aria-hidden”, “false”);
dom.hamburgerBtn.classList.add(“is-open”);
dom.hamburgerBtn.setAttribute(“aria-expanded”, “true”);
dom.hamburgerBtn.setAttribute(“aria-label”, “Close menu”);
dom.backdrop.classList.add(“is-open”);
}
function closeDrawer() {
dom.drawer.classList.remove(“is-open”);
dom.drawer.setAttribute(“aria-hidden”, “true”);
dom.hamburgerBtn.classList.remove(“is-open”);
dom.hamburgerBtn.setAttribute(“aria-expanded”, “false”);
dom.hamburgerBtn.setAttribute(“aria-label”, “Open menu”);
// Only hide the backdrop if the side panel isn’t also using it
if (!dom.sidePanel.classList.contains(“is-open”)) {
dom.backdrop.classList.remove(“is-open”);
}
}
function toggleDrawer() {
if (dom.drawer.classList.contains(“is-open”)) closeDrawer();
else openDrawer();
}
/* ============================================================================
8) SIDE PANEL (location card)
============================================================================ */
function renderStars(el, score) {
const filled = Math.max(0, Math.min(5, Math.round(score)));
const empty = 5 – filled;
el.textContent = “★”.repeat(filled) + “☆”.repeat(empty);
if (score >= 4) el.style.color = “var(–color-good)”;
else if (score >= 2.5) el.style.color = “var(–color-ok)”;
else el.style.color = “var(–color-poor)”;
}
function colorOverallRing(circleEl, score) {
// Sets the inset ring color of the circular score badge.
let ring;
if (score >= 4) ring = “var(–color-good)”;
else if (score >= 2.5) ring = “var(–color-ok)”;
else ring = “var(–color-poor)”;
circleEl.style.boxShadow =
`inset 0 0 0 4px ${ring}, 0 4px 12px rgba(15, 23, 42, 0.07)`;
}
function openLocationCard(loc) {
// 1) Hero image + city badge
dom.cardImage.src = loc.imageUrl;
dom.cardImage.alt = loc.title;
dom.cardCityBadge.textContent = loc.city;
// 2) Title + description
dom.cardTitle.textContent = loc.title;
dom.cardDescription.textContent = loc.description;
// 3) Overall score
dom.cardOverallScore.textContent = loc.ratings.overallScore.toFixed(1);
colorOverallRing(dom.cardOverallCircle, loc.ratings.overallScore);
// 4) Physical accessibility (stars + notes)
renderStars(dom.cardPhysicalStars, loc.ratings.physicalAccessibility);
dom.cardPhysicalNotes.textContent = loc.ratings.physicalNotes;
// 5) Coordinates footer
dom.cardCoords.textContent =
`Coordinates: ${loc.coordinates.lat.toFixed(5)}, ${loc.coordinates.lng.toFixed(5)}`;
// 6) Slide panel + backdrop in
dom.sidePanel.classList.add(“is-open”);
dom.sidePanel.setAttribute(“aria-hidden”, “false”);
dom.backdrop.classList.add(“is-open”);
// 7) Pan the map slightly so the marker isn’t hidden behind the panel
if (window.innerWidth > 768) {
map.panTo([loc.coordinates.lat, loc.coordinates.lng], { animate: true });
}
}
function closeLocationCard() {
dom.sidePanel.classList.remove(“is-open”);
dom.sidePanel.setAttribute(“aria-hidden”, “true”);
// Only hide the backdrop if the drawer isn’t also using it
if (!dom.drawer.classList.contains(“is-open”)) {
dom.backdrop.classList.remove(“is-open”);
}
}
/* ============================================================================
9) BOOTSTRAP
============================================================================ */
function cacheDom() {
dom.hamburgerBtn = document.getElementById(“hamburgerBtn”);
dom.drawer = document.getElementById(“drawer”);
dom.drawerClose = document.getElementById(“drawerClose”);
dom.brandPillCity = document.getElementById(“brandPillCity”);
dom.backdrop = document.getElementById(“backdrop”);
dom.sidePanel = document.getElementById(“sidePanel”);
dom.sidePanelClose = document.getElementById(“sidePanelClose”);
dom.cardImage = document.getElementById(“cardImage”);
dom.cardCityBadge = document.getElementById(“cardCityBadge”);
dom.cardTitle = document.getElementById(“cardTitle”);
dom.cardOverallCircle = document.getElementById(“cardOverallCircle”);
dom.cardOverallScore = document.getElementById(“cardOverallScore”);
dom.cardDescription = document.getElementById(“cardDescription”);
dom.cardPhysicalStars = document.getElementById(“cardPhysicalStars”);
dom.cardPhysicalNotes = document.getElementById(“cardPhysicalNotes”);
dom.cardCoords = document.getElementById(“cardCoords”);
dom.filterButtons = document.querySelectorAll(“.drawer__filter”);
}
function bindEvents() {
// Hamburger toggles the drawer
dom.hamburgerBtn.addEventListener(“click”, toggleDrawer);
dom.drawerClose.addEventListener(“click”, closeDrawer);
// Drawer filter buttons
dom.filterButtons.forEach((btn) => {
btn.addEventListener(“click”, () => setActiveCity(btn.dataset.city));
});
// Side panel close
dom.sidePanelClose.addEventListener(“click”, closeLocationCard);
// Backdrop click closes whichever overlay is open
dom.backdrop.addEventListener(“click”, () => {
closeDrawer();
closeLocationCard();
});
// Escape closes everything
document.addEventListener(“keydown”, (e) => {
if (e.key === “Escape”) {
closeDrawer();
closeLocationCard();
}
});
}
document.addEventListener(“DOMContentLoaded”, () => {
cacheDom();
initMap();
renderMarkers();
bindEvents();
});
/* ============================================================================
ACCESSIBILITY MAP — styles.css
============================================================================
Layout philosophy:
• The map fills the entire viewport.
• Every UI element floats on top as a glass-morphism panel.
• Soft, layered shadows + subtle borders give a premium feel.
Sections:
1) :root — design tokens (colors, fonts, spacing, etc.)
2) Base / reset
3) Hamburger button — animated 3-bars → X
4) Brand pill — top-center floating title
5) Drawer — left slide-in menu
6) Map + legend
7) Side panel (location card)
8) Backdrop (shared)
9) Custom Leaflet markers
10) Responsive overrides
11) Reduced motion
============================================================================ */
/* ============================================================================
1) DESIGN TOKENS
—————————————————————————-
>>> CHANGE PRIMARY COLORS / FONTS HERE <<<
============================================================================ */
:root {
/* --- Brand / accent --- */
--color-primary: #6366f1; /* indigo-500 — main accent */
--color-primary-dark: #4f46e5; /* indigo-600 — hover/pressed */
--color-primary-soft: #eef2ff; /* indigo-50 — subtle backgrounds */
--color-primary-tint: rgba(99, 102, 241, 0.12); /* translucent fills */
/* --- Score / status colors --- */
--color-good: #10b981; /* emerald-500 */
--color-ok: #f59e0b; /* amber-500 */
--color-poor: #ef4444; /* red-500 */
/* --- Neutrals (warm-cool blend) --- */
--color-bg: #f5f7fb;
--color-surface: #ffffff;
--color-surface-2: #f8fafc;
--color-border: #e5e7eb;
--color-border-soft: rgba(15, 23, 42, 0.06);
--color-text: #0f172a;
--color-text-soft: #475569;
--color-text-mute: #94a3b8;
/* Glass surface — semi-transparent white used for floating panels.
Combined with backdrop-filter: blur(...) for the frosted look. */
--glass-bg: rgba(255, 255, 255, 0.78);
--glass-bg-solid: rgba(255, 255, 255, 0.95);
--glass-border: rgba(255, 255, 255, 0.6);
/* --- Typography --- */
--font-display: "Plus Jakarta Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-size-base: 16px;
/* --- Spacing --- */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 48px;
/* --- Radii --- */
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 20px;
--radius-xl: 28px;
--radius-pill: 999px;
/* --- Shadows (soft, layered) --- */
--shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.06);
--shadow-sm: 0 4px 12px rgba(15, 23, 42, 0.07);
--shadow-md: 0 10px 30px rgba(15, 23, 42, 0.10);
--shadow-lg: 0 24px 60px rgba(15, 23, 42, 0.18);
--shadow-glow: 0 12px 30px rgba(99, 102, 241, 0.30);
/* --- Layout sizes --- */
--drawer-width: 320px;
--side-panel-width: 440px;
/* --- Motion --- */
--ease: cubic-bezier(0.4, 0, 0.2, 1);
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--duration: 300ms;
--duration-fast: 200ms;
}
/* ============================================================================
2) BASE / RESET
============================================================================ */
*,
*::before,
*::after { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
height: 100%;
}
body {
font-family: var(--font-body);
font-size: var(--font-size-base);
color: var(--color-text);
background-color: var(--color-bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow: hidden; /* the map itself handles scrolling/panning */
}
button {
font-family: inherit;
cursor: pointer;
border: none;
background: none;
color: inherit;
}
img { display: block; max-width: 100%; }
/* Reusable glass-panel surface */
.glass {
background-color: var(--glass-bg);
-webkit-backdrop-filter: saturate(180%) blur(18px);
backdrop-filter: saturate(180%) blur(18px);
border: 1px solid var(--glass-border);
}
/* ============================================================================
3) HAMBURGER BUTTON (top-left)
============================================================================ */
.hamburger {
position: fixed;
top: var(--space-4);
left: var(--space-4);
z-index: 1200;
width: 52px;
height: 52px;
border-radius: var(--radius-md);
background-color: var(--glass-bg);
-webkit-backdrop-filter: saturate(180%) blur(18px);
backdrop-filter: saturate(180%) blur(18px);
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-md);
display: flex;
align-items: center;
justify-content: center;
transition:
transform var(--duration-fast) var(--ease),
background-color var(--duration-fast) var(--ease),
box-shadow var(--duration-fast) var(--ease);
}
.hamburger:hover {
background-color: var(--glass-bg-solid);
transform: translateY(-1px);
box-shadow: var(--shadow-lg);
}
.hamburger:active {
transform: translateY(0);
}
/* The 3 bars container */
.hamburger__bars {
position: relative;
width: 22px;
height: 16px;
display: block;
}
.hamburger__bars span {
position: absolute;
left: 0;
width: 100%;
height: 2px;
border-radius: 2px;
background-color: var(--color-text);
transition:
transform var(--duration-fast) var(--ease),
opacity var(--duration-fast) var(--ease),
top var(--duration-fast) var(--ease);
}
.hamburger__bars span:nth-child(1) { top: 0; }
.hamburger__bars span:nth-child(2) { top: 7px; }
.hamburger__bars span:nth-child(3) { top: 14px; }
/* Animate to X when drawer is open (.is-open is toggled by JS) */
.hamburger.is-open .hamburger__bars span:nth-child(1) {
top: 7px;
transform: rotate(45deg);
}
.hamburger.is-open .hamburger__bars span:nth-child(2) {
opacity: 0;
}
.hamburger.is-open .hamburger__bars span:nth-child(3) {
top: 7px;
transform: rotate(-45deg);
}
/* ============================================================================
4) BRAND PILL (top-center)
============================================================================ */
.brand-pill {
position: fixed;
top: var(--space-4);
left: 50%;
transform: translateX(-50%);
z-index: 1100;
display: flex;
align-items: center;
gap: var(--space-3);
padding: 10px 18px 10px 14px;
border-radius: var(--radius-pill);
background-color: var(--glass-bg);
-webkit-backdrop-filter: saturate(180%) blur(18px);
backdrop-filter: saturate(180%) blur(18px);
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-md);
pointer-events: none; /* purely informational, don't intercept clicks */
user-select: none;
max-width: calc(100vw - 140px);
}
.brand-pill__icon {
width: 22px;
height: 22px;
fill: var(--color-primary);
flex-shrink: 0;
}
.brand-pill__text {
display: flex;
flex-direction: column;
line-height: 1.15;
min-width: 0;
}
.brand-pill__title {
font-family: var(--font-display);
font-weight: 700;
font-size: 0.92rem;
letter-spacing: -0.01em;
color: var(--color-text);
}
.brand-pill__city {
font-size: 0.74rem;
font-weight: 500;
color: var(--color-primary-dark);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ============================================================================
5) DRAWER (slides in from the left)
============================================================================ */
.drawer {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: var(--drawer-width);
max-width: 90vw;
background-color: var(--color-surface);
box-shadow: var(--shadow-lg);
z-index: 1300;
/* Hidden state — pushed off the left edge */
transform: translateX(-100%);
transition: transform var(--duration) var(--ease-out);
display: flex;
flex-direction: column;
overflow: hidden;
}
.drawer.is-open {
transform: translateX(0);
}
/* Subtle gradient stripe at the top of the drawer for visual interest */
.drawer::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0;
height: 4px;
background: linear-gradient(90deg,
var(--color-primary) 0%,
#8b5cf6 50%,
#06b6d4 100%);
z-index: 1;
}
.drawer__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-6) var(--space-5) var(--space-4);
}
.drawer__brand {
display: flex;
align-items: center;
gap: var(--space-3);
}
.drawer__logo {
width: 32px;
height: 32px;
fill: var(--color-primary);
}
.drawer__brand-text {
display: flex;
flex-direction: column;
line-height: 1.1;
}
.drawer__title {
font-family: var(--font-display);
font-weight: 800;
font-size: 1.05rem;
letter-spacing: -0.01em;
}
.drawer__subtitle {
font-size: 0.75rem;
font-weight: 500;
color: var(--color-text-mute);
margin-top: 2px;
}
.drawer__close {
width: 36px;
height: 36px;
border-radius: 50%;
font-size: 1.5rem;
line-height: 1;
color: var(--color-text-soft);
background-color: var(--color-surface-2);
display: flex;
align-items: center;
justify-content: center;
transition: background-color var(--duration-fast) var(--ease);
}
.drawer__close:hover {
background-color: var(--color-border);
color: var(--color-text);
}
.drawer__section-title {
margin: 0;
padding: var(--space-2) var(--space-5) var(--space-3);
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-mute);
}
/* Filter list */
.drawer__filters {
display: flex;
flex-direction: column;
gap: var(--space-1);
padding: 0 var(--space-3);
flex: 1;
overflow-y: auto;
}
.drawer__filter {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 14px 16px;
border-radius: var(--radius-md);
font-size: 0.95rem;
font-weight: 500;
color: var(--color-text);
text-align: left;
transition:
background-color var(--duration-fast) var(--ease),
color var(--duration-fast) var(--ease),
transform var(--duration-fast) var(--ease);
}
.drawer__filter:hover {
background-color: var(--color-primary-soft);
color: var(--color-primary-dark);
transform: translateX(2px);
}
.drawer__filter-arrow {
color: var(--color-text-mute);
font-size: 1.2rem;
transition: transform var(--duration-fast) var(--ease);
}
.drawer__filter:hover .drawer__filter-arrow {
color: var(--color-primary);
transform: translateX(2px);
}
/* Active filter (toggled by JS) */
.drawer__filter.is-active {
background-color: var(--color-primary);
color: #fff;
font-weight: 600;
box-shadow: var(--shadow-glow);
}
.drawer__filter.is-active .drawer__filter-arrow {
color: rgba(255, 255, 255, 0.9);
}
.drawer__footer {
padding: var(--space-5);
font-size: 0.78rem;
color: var(--color-text-mute);
border-top: 1px solid var(--color-border);
line-height: 1.5;
}
/* ============================================================================
6) MAP + LEGEND
============================================================================ */
.map-wrapper {
position: fixed;
inset: 0; /* fills the entire viewport */
z-index: 1;
}
#map {
width: 100%;
height: 100%;
background-color: #e8eef5;
}
/* Legend — bottom-left floating glass panel */
.legend {
position: fixed;
left: var(--space-4);
bottom: var(--space-4);
z-index: 600;
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-md);
background-color: var(--glass-bg);
-webkit-backdrop-filter: saturate(180%) blur(18px);
backdrop-filter: saturate(180%) blur(18px);
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-md);
font-size: 0.82rem;
color: var(--color-text-soft);
user-select: none;
}
.legend__title {
font-family: var(--font-display);
font-weight: 700;
color: var(--color-text);
margin-bottom: var(--space-2);
font-size: 0.85rem;
}
.legend__row {
display: flex;
align-items: center;
gap: var(--space-2);
padding: 2px 0;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8);
}
.dot--good { background-color: var(--color-good); }
.dot--ok { background-color: var(--color-ok); }
.dot--poor { background-color: var(--color-poor); }
/* Slim down Leaflet's default attribution box so it blends in */
.leaflet-control-attribution {
background-color: rgba(255, 255, 255, 0.7) !important;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
font-size: 0.7rem !important;
border-radius: 6px 0 0 0;
}
/* Reposition Leaflet's zoom buttons to keep them clear of the hamburger */
.leaflet-top.leaflet-left {
top: 80px;
left: var(--space-4);
}
.leaflet-control-zoom {
border: none !important;
box-shadow: var(--shadow-md) !important;
border-radius: var(--radius-md) !important;
overflow: hidden;
}
.leaflet-control-zoom a {
background-color: var(--glass-bg) !important;
-webkit-backdrop-filter: saturate(180%) blur(18px);
backdrop-filter: saturate(180%) blur(18px);
color: var(--color-text) !important;
border-bottom: 1px solid var(--color-border-soft) !important;
}
.leaflet-control-zoom a:hover {
background-color: var(--glass-bg-solid) !important;
}
/* ============================================================================
7) SIDE PANEL (location card)
============================================================================ */
.side-panel {
position: fixed;
top: 0;
right: 0;
height: 100vh;
width: var(--side-panel-width);
max-width: 100%;
background-color: var(--color-surface);
box-shadow: var(--shadow-lg);
transform: translateX(100%);
transition: transform var(--duration) var(--ease-out);
z-index: 1250;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.side-panel.is-open {
transform: translateX(0);
}
.side-panel__close {
position: absolute;
top: var(--space-3);
right: var(--space-3);
width: 38px;
height: 38px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.95);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
font-size: 1.5rem;
line-height: 1;
color: var(--color-text);
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
box-shadow: var(--shadow-sm);
transition: transform var(--duration-fast) var(--ease);
}
.side-panel__close:hover {
transform: rotate(90deg);
}
/* Hero image */
.card__image-wrap {
position: relative;
width: 100%;
height: 240px;
background-color: var(--color-surface-2);
flex-shrink: 0;
overflow: hidden;
}
.card__image {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Soft gradient overlay so the city badge is always readable */
.card__image-overlay {
position: absolute;
inset: 0;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 50%,
rgba(0, 0, 0, 0.55) 100%
);
}
.card__city-badge {
position: absolute;
left: var(--space-4);
bottom: var(--space-4);
padding: 6px 14px;
border-radius: var(--radius-pill);
background-color: rgba(255, 255, 255, 0.95);
color: var(--color-primary-dark);
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.02em;
box-shadow: var(--shadow-sm);
}
/* Card body */
.card__body {
padding: var(--space-5);
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.card__title {
margin: 0;
font-family: var(--font-display);
font-size: 1.55rem;
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1.2;
}
/* Overall score block — circular badge + meta text */
.card__overall {
display: flex;
align-items: center;
gap: var(--space-4);
padding: var(--space-4);
border-radius: var(--radius-lg);
background: linear-gradient(135deg,
var(--color-surface-2) 0%,
#ffffff 100%);
border: 1px solid var(--color-border);
}
.card__overall-circle {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
/* The ring color is set inline by JS based on the score (good/ok/poor) */
box-shadow:
inset 0 0 0 4px var(--color-primary),
var(--shadow-sm);
}
.card__overall-score {
font-family: var(--font-display);
font-size: 1.6rem;
font-weight: 800;
line-height: 1;
letter-spacing: -0.02em;
color: var(--color-text);
}
.card__overall-out {
font-size: 0.7rem;
color: var(--color-text-mute);
font-weight: 600;
margin-top: 2px;
}
.card__overall-meta {
display: flex;
flex-direction: column;
gap: 2px;
}
.card__overall-label {
font-family: var(--font-display);
font-size: 1rem;
font-weight: 700;
color: var(--color-text);
}
.card__overall-sub {
font-size: 0.82rem;
color: var(--color-text-soft);
}
.card__description {
margin: 0;
color: var(--color-text-soft);
line-height: 1.6;
font-size: 0.95rem;
}
/* Ratings */
.card__ratings {
display: flex;
flex-direction: column;
gap: var(--space-3);
padding-top: var(--space-4);
border-top: 1px solid var(--color-border);
}
.rating-row {
display: flex;
flex-direction: column;
gap: 6px;
}
.rating-row__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-3);
}
.rating-row__label {
font-family: var(--font-display);
font-weight: 700;
font-size: 0.95rem;
}
.rating-row__stars {
font-size: 1.05rem;
letter-spacing: 3px;
color: var(--color-ok);
white-space: nowrap;
}
.rating-row__notes {
margin: 0;
font-size: 0.88rem;
color: var(--color-text-soft);
line-height: 1.5;
}
.card__coords {
margin-top: var(--space-2);
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-sm);
background-color: var(--color-surface-2);
font-size: 0.75rem;
color: var(--color-text-mute);
font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
}
/* ============================================================================
8) BACKDROP
============================================================================ */
.backdrop {
position: fixed;
inset: 0;
background-color: rgba(15, 23, 42, 0.45);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
opacity: 0;
pointer-events: none;
transition: opacity var(--duration) var(--ease);
z-index: 1150;
}
.backdrop.is-open {
opacity: 1;
pointer-events: auto;
}
/* ============================================================================
9) CUSTOM LEAFLET MARKERS
----------------------------------------------------------------------------
Built with L.divIcon() in JS. The variant class (is-good / is-ok / is-poor)
is set by JS based on the location's overallScore.
============================================================================ */
.access-marker {
width: 36px;
height: 36px;
border-radius: 50% 50% 50% 0;
transform: rotate(-45deg);
border: 3px solid #ffffff;
box-shadow:
0 4px 14px rgba(15, 23, 42, 0.25),
0 0 0 1px rgba(15, 23, 42, 0.04);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition:
transform var(--duration-fast) var(--ease),
box-shadow var(--duration-fast) var(--ease);
}
.access-marker:hover {
transform: rotate(-45deg) scale(1.18) translate(-2px, -2px);
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.35);
z-index: 1000;
}
/* The score number inside the pin (rotated upright) */
.access-marker__inner {
transform: rotate(45deg);
color: #ffffff;
font-weight: 700;
font-size: 0.78rem;
font-family: var(--font-display);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.access-marker.is-good { background-color: var(--color-good); }
.access-marker.is-ok { background-color: var(--color-ok); }
.access-marker.is-poor { background-color: var(--color-poor); }
/* ============================================================================
10) RESPONSIVE OVERRIDES
============================================================================ */
@media (max-width: 768px) {
/* Hide the brand pill text on small screens — keeps the chrome minimal */
.brand-pill {
padding: 8px 14px 8px 12px;
}
.brand-pill__title { font-size: 0.85rem; }
.brand-pill__city { font-size: 0.7rem; }
/* Side panel becomes full width on phones (modal-like) */
.side-panel {
width: 100%;
}
/* Pin Leaflet zoom controls below the hamburger more tightly */
.leaflet-top.leaflet-left {
top: 80px;
}
}
@media (max-width: 480px) {
.brand-pill__city { display: none; }
.card__title { font-size: 1.3rem; }
.card__overall-circle { width: 68px; height: 68px; }
.card__overall-score { font-size: 1.35rem; }
.legend {
font-size: 0.75rem;
padding: var(--space-2) var(--space-3);
}
}
/* ============================================================================
11) REDUCED MOTION
----------------------------------------------------------------------------
Honors the user's OS-level preference to minimize animations.
============================================================================ */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}