);
}
function Services() {
const [open, setOpen] = React.useState("shaving");
// Open the matching menu when arriving via a #service- deep link
// (from the hamburger menu), then scroll it into view.
React.useEffect(() => {
var pendingId = null;
var finalizeTimer = null;
var safetyTimer = null;
var fixedTimers = [];
var ro = null;
function snap(id) {
var el = document.getElementById("service-" + id);
if (!el) return;
el.scrollIntoView({ block: "start" });
}
function finalize() {
if (!pendingId) return;
snap(pendingId); // one last correction before we stop watching
pendingId = null;
document.documentElement.style.scrollBehavior = ""; // restore smooth
if (ro) { ro.disconnect(); ro = null; }
detachUserWatch();
}
// The moment the user scrolls/touches, stop correcting: continuing to
// snap would yank them back and feel jerky while they scroll down.
function onUserIntent() {
if (!pendingId) return;
pendingId = null;
clearTimeout(finalizeTimer);
clearTimeout(safetyTimer);
fixedTimers.forEach(clearTimeout);
fixedTimers = [];
document.documentElement.style.scrollBehavior = "";
if (ro) { ro.disconnect(); ro = null; }
detachUserWatch();
}
function attachUserWatch() {
window.addEventListener("wheel", onUserIntent, { passive: true });
window.addEventListener("touchstart", onUserIntent, { passive: true });
window.addEventListener("touchmove", onUserIntent, { passive: true });
window.addEventListener("keydown", onUserIntent, { passive: true });
}
function detachUserWatch() {
window.removeEventListener("wheel", onUserIntent);
window.removeEventListener("touchstart", onUserIntent);
window.removeEventListener("touchmove", onUserIntent);
window.removeEventListener("keydown", onUserIntent);
}
function bump() {
if (!pendingId) return;
snap(pendingId);
clearTimeout(finalizeTimer);
finalizeTimer = setTimeout(finalize, 260);
}
// Layout can settle via a CSS transition ending, a non-transition size
// change (ResizeObserver), or — in case neither fires reliably — a
// handful of fixed-delay checks. Any one of these is enough; they're
// all idempotent (snapping to an already-correct position is a no-op).
function onTransitionEnd(e) {
if (e.propertyName !== "grid-template-rows") return;
bump();
}
function openFromHash() {
const m = (window.location.hash || "").match(/^#service-(.+)$/);
if (!m) return;
const id = decodeURIComponent(m[1]);
if (!SERVICE_MENU.some((s) => s.id === id)) return;
pendingId = id;
// Clicking a hamburger-drawer link both navigates AND closes the
// drawer; the drawer's own body scroll-lock (overflow:hidden) is only
// released once React re-renders, which can lag a tick behind this
// handler. While locked, scrollIntoView is a no-op — clear it directly
// here so scrolling is never blocked.
document.body.style.overflow = "";
// Disable global smooth-scroll for the whole open sequence so the
// browser's native hash jump doesn't animate toward the panel's
// pre-collapse position and fight our snaps. Restored once settled.
document.documentElement.style.scrollBehavior = "auto";
setOpen(id);
fixedTimers.forEach(clearTimeout);
fixedTimers = [0, 60, 150, 300, 500, 750, 1050].map(function (ms) {
return setTimeout(function () { snap(id); }, ms);
});
requestAnimationFrame(function () { snap(id); });
clearTimeout(finalizeTimer);
finalizeTimer = setTimeout(finalize, 1200);
if (ro) ro.disconnect();
ro = new ResizeObserver(bump);
ro.observe(document.body);
ro.observe(document.documentElement);
clearTimeout(safetyTimer);
safetyTimer = setTimeout(finalize, 1800);
// Hand control back to the user as soon as they touch the page.
detachUserWatch();
attachUserWatch();
}
var menu = document.querySelector(".svc-menu");
if (menu) menu.addEventListener("transitionend", onTransitionEnd);
openFromHash();
window.addEventListener("hashchange", openFromHash);
return () => {
window.removeEventListener("hashchange", openFromHash);
if (menu) menu.removeEventListener("transitionend", onTransitionEnd);
clearTimeout(finalizeTimer);
clearTimeout(safetyTimer);
fixedTimers.forEach(clearTimeout);
if (ro) ro.disconnect();
detachUserWatch();
};
}, []);
return (
04