// Shared viewport-detection hook used by every page entry. // // The site uses a single `isMobile` flag throughout. Historically this was driven // only by a Tweak (handy in design preview, broken on real phones). Now it's a // hybrid: the Tweak can be 'auto', 'desktop', or 'mobile' — only 'auto' listens // to the real screen. // // Breakpoint: < 768px → mobile (iPhone). iPad portrait and up stay desktop. const DCH_MOBILE_MQ = '(max-width: 767px)'; function useEffectiveViewport(tweakValue) { const getAutoMobile = () => { if (typeof window === 'undefined' || !window.matchMedia) return false; return window.matchMedia(DCH_MOBILE_MQ).matches; }; const [autoMobile, setAutoMobile] = React.useState(getAutoMobile); React.useEffect(() => { if (!window.matchMedia) return; const mql = window.matchMedia(DCH_MOBILE_MQ); const onChange = (e) => setAutoMobile(e.matches); // Safari < 14 uses addListener; modern browsers use addEventListener. if (mql.addEventListener) mql.addEventListener('change', onChange); else mql.addListener(onChange); // Re-sync on mount in case SSR / hydration diverged. setAutoMobile(mql.matches); return () => { if (mql.removeEventListener) mql.removeEventListener('change', onChange); else mql.removeListener(onChange); }; }, []); const isAuto = tweakValue === 'auto' || tweakValue == null; const isMobile = isAuto ? autoMobile : tweakValue === 'mobile'; return { isMobile, isAuto }; } // Shared Tweak control: 3-way segmented switch (Auto / Desktop / Mobile). function ViewportTweak({ value, onChange }) { return ( ); } window.useEffectiveViewport = useEffectiveViewport; window.ViewportTweak = ViewportTweak;