{"version":3,"file":"ResizeStabilizer.De-RWRyu.mjs","names":["Fragment"],"sources":["https:/framerusercontent.com/modules/vJqWSQYNrlT0dgtV8SJt/lCOD27U7bElChhzAgQlO/TextWrapPretty.js","https:/framerusercontent.com/modules/i6c3ga64DWvfSetmdXmK/DGmdBSGBC6dQOQoOxEO3/ResizeStabilizer.js"],"sourcesContent":["import{jsx as _jsx}from\"react/jsx-runtime\";import{cloneElement,Fragment,isValidElement,useEffect}from\"react\";/* ════════════════════════════════════════════════════════════\n   TEXT WRAP — wrap styles Framer's text panel doesn't offer.\n   Apply ONE of these overrides to the text layer itself, and\n   choose per layer.\n\n   withKeepLastTwoWords — a paragraph never ends on a single word.\n   The space between each paragraph's last two words becomes a\n   non-breaking space, so the word before a lone last word moves\n   down with it. Every other line wraps exactly as usual. Same in\n   every browser, at every width; it is in the page's HTML, so it\n   holds from the first paint. If the last line already has two or\n   more words, nothing visible changes. Same rule as\n   ScrollRevealText's Last Line › Keep 2 Words (2026-10-14).\n\n   withTextWrapPretty — text-wrap-style: pretty. The browser\n   re-breaks the lines itself, and each engine does it differently:\n     · Chrome / Edge: mainly stops a single word sitting alone on\n       the last line (it reworks only the last four lines).\n     · Safari 26+: evens out the whole paragraph's line lengths,\n       so it often looks like Balance.\n     · Firefox: no effect.\n   Only the wrap STYLE is set (the longhand), never the wrap MODE,\n   so a text layer at fit-content width still won't wrap.\n\n   Neither changes anything else about the layer. Overrides don't\n   run on the canvas; check in preview. Which layers carry which\n   one is set in Framer only — the published HTML shows it as the\n   class `tw-keep2` or `tw-pretty` on each text layer.\n   ════════════════════════════════════════════════════════════ */// ─── Keep last two words ─────────────────────────────────────\nconst NBSP=\"\\xa0\";/** Spaces that make a break opportunity. Framer's text is\n *  `white-space: pre-wrap`, so a newline inside a string is a hard\n *  line break — never glued across, same as a <br>. A non-breaking\n *  space already in the copy is a word character here. */const isSpace=ch=>ch===\" \"||ch===\"\t\";/** Calls `leaf` on every string in document order and swaps in its\n *  result; `br` fires for each <br>. Returns the original node when\n *  nothing changed, so untouched paragraphs keep their identity. */function mapLeaves(node,leaf,br){if(typeof node===\"string\")return leaf(node);if(typeof node===\"number\"){const s=String(node);const r=leaf(s);return r===s?node:r;}if(Array.isArray(node)){let changed=false;const out=node.map(c=>{const r=mapLeaves(c,leaf,br);if(r!==c)changed=true;return r;});return changed?out:node;}if(/*#__PURE__*/isValidElement(node)){if(node.type===\"br\"){br();return node;}const kids=node.props.children;if(kids===undefined||kids===null)return node;const next=mapLeaves(kids,leaf,br);return next===kids?node:/*#__PURE__*/cloneElement(node,{children:next});}return node;}/** One paragraph. Reads its text as one string (a <br> counts as a\n *  newline), finds the space run between the last two words on the\n *  last line, and turns every space in that run into a non-breaking\n *  space. Every space, not just one: a break is allowed after an\n *  ordinary space even when a non-breaking one follows it. Space\n *  count is kept, so nothing shifts under pre-wrap. Works across\n *  styled runs (a last word in a link or bold span). */function keepParagraph(node){let flat=\"\";mapLeaves(node,s=>{flat+=s;return s;},()=>{flat+=\"\\n\";});let i=flat.length-1;while(i>=0&&(isSpace(flat[i])||flat[i]===\"\\n\"))i--// trailing space\n;if(i<0)return node;while(i>=0&&!isSpace(flat[i])&&flat[i]!==\"\\n\"){if(flat[i]===NBSP)return node// already held together in the copy\n;i--// the last word\n;}if(i<0||flat[i]===\"\\n\")return node// one word on the last line\n;const runEnd=i;while(i>=0&&isSpace(flat[i]))i--;if(i<0||flat[i]===\"\\n\")return node// no word before it on that line\n;const runStart=i+1;let pos=0;return mapLeaves(node,s=>{const start=pos;pos+=s.length;if(pos<=runStart||start>runEnd)return s;let out=\"\";for(let k=0;k<s.length;k++){const at=start+k;out+=at>=runStart&&at<=runEnd?NBSP:s[k];}return out;},()=>{pos+=1;});}/** Framer's rich text arrives as a Fragment of block elements — one\n *  per paragraph, with lists as ul/ol › li. Each block is treated as\n *  its own paragraph. */function keepBlocks(node){if(Array.isArray(node)){let changed=false;const out=node.map(c=>{const r=keepBlocks(c);if(r!==c)changed=true;return r;});return changed?out:node;}if(!/*#__PURE__*/isValidElement(node))return node;const t=node.type;if(t===Fragment||t===\"ul\"||t===\"ol\"){const kids=node.props.children;const next=keepBlocks(kids);return next===kids?node:/*#__PURE__*/cloneElement(node,{children:next});}return keepParagraph(node);}// ─── Pretty ──────────────────────────────────────────────────\nconst SHEET_ID=\"gf-text-wrap\";/** The class lands on the text layer's container; Framer renders the\n *  words in .framer-text children, which get the rule directly in case\n *  Framer's own text styles set a wrap value there. !important for the\n *  same reason. */const CSS=[\".tw-pretty, .tw-pretty .framer-text {\",\"    text-wrap-style: pretty !important;\",\"}\"].join(\"\\n\");function ensureSheet(){if(typeof document===\"undefined\")return;let el=document.getElementById(SHEET_ID);if(!el){el=document.createElement(\"style\");el.id=SHEET_ID;document.head.appendChild(el);}if(el.textContent!==CSS)el.textContent=CSS;}function withWrapClass(cls){return function(Component){return function TextWrapped(props){useEffect(()=>{ensureSheet();},[]);const className=[props.className,cls].filter(Boolean).join(\" \");return /*#__PURE__*/_jsx(Component,{...props,className:className});};};}// ─── Exports ─────────────────────────────────────────────────\nexport function withKeepLastTwoWords(Component){return function KeepLastTwoWords(props){const className=[props.className,\"tw-keep2\"].filter(Boolean).join(\" \");// Typed copy arrives as `children`. Text bound to a CMS field\n// or a component property arrives as a plain `text` string,\n// which Framer puts in place of the children's words.\nconst next={...props,className};if(props.children!==undefined)next.children=keepBlocks(props.children);if(typeof props.text===\"string\")next.text=keepParagraph(props.text);return /*#__PURE__*/_jsx(Component,{...next});};}export function withTextWrapPretty(C){return withWrapClass(\"tw-pretty\")(C);}\nexport const __FramerMetadata__ = {\"exports\":{\"withKeepLastTwoWords\":{\"type\":\"reactHoc\",\"name\":\"withKeepLastTwoWords\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withTextWrapPretty\":{\"type\":\"reactHoc\",\"name\":\"withTextWrapPretty\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./TextWrapPretty.map","import{jsx as _jsx}from\"react/jsx-runtime\";import{useEffect}from\"react\";import{RenderTarget}from\"framer\";/* ══════════════════════════════════════════════════════════════════\n * Responsive/ResizeStabilizer.tsx\n *\n * Holds the viewer's place when a width change reflows the page.\n *\n * THE PROBLEM. Crossing a breakpoint swaps layouts — two columns to\n * one, a carousel restacking — and every section above the viewer\n * changes height. The scroll offset does not, so the content slides\n * under them, and the further down the page they are the more of it\n * has accumulated. A few pixels of drag can throw them into the next\n * section.\n *\n * WHY NOT CSS. There is a W3C standard for exactly this — scroll\n * anchoring, `overflow-anchor` — and it cannot be used here for two\n * independent reasons:\n *\n *   · Safari has never shipped it, desktop or iOS.\n *   · The spec lists `width`, `height`, `min/max-*`, `margin`,\n *     `padding`, `position` and `transform` changes on the anchor\n *     node OR ANY ANCESTOR as *suppression triggers*, which discard\n *     the queued adjustment. A breakpoint swap changes most of those\n *     on most elements, so the browser deliberately stands down in\n *     precisely our case. Scroll anchoring is built for content\n *     INSERTED above the viewport — images finishing loading,\n *     infinite scroll — not for reflow.\n *\n * WHAT THIS DOES INSTEAD. The five section anchors Greg authored as\n * scroll sections sit exactly on the section seams (`Section: Intro`\n * is 2290 tall and #product-design measures at docTop 2290). They are\n * therefore the right things to hold still, and because ScrollSnap\n * parks the viewer ON a section top, at rest the correction is\n * usually near zero.\n *\n *   1. On scroll — passive, one rAF at most — remember the nearest\n *      anchor at or above the viewport top, and how far above.\n *   2. On a WIDTH change, every frame until things stop moving,\n *      re-measure that same anchor and scroll by the difference.\n *\n * Capturing on scroll rather than on resize is the whole trick: by\n * the time a `resize` event fires the reflow has already happened and\n * the anchor's position is spoiled. The stored value predates it.\n *\n * Correcting EVERY frame rather than once at the end means the page\n * appears to hold still while reflowing around the anchor, instead of\n * sliding and then snapping back. It also absorbs late corrections\n * for free — this page makes one ~17px adjustment about 120ms after\n * the last resize event — with no settle detector to tune.\n *\n * The anchor is looked up by id each time, never held as a reference,\n * so a Framer breakpoint swap remounting the whole subtree is a\n * non-event. The id is the identity.\n *\n * COORDINATION. A programmatic scroll write is visible to everything\n * that watches scrolling, so `window.__resizeAnchorActive` is raised\n * for the duration and read in two other files:\n *\n *   · Snapping/ScrollSnap.tsx — releases any snap or hold in flight\n *     (its target is an absolute document position and goes stale the\n *     moment the page reflows), keeps its direction baseline in step,\n *     and refuses to start a new snap. Without this, a correction on\n *     a lengthening page reads as a hard scroll down and triggers a\n *     real snap: a 520ms animation plus a 1750ms pin.\n *   · Header/HeaderScrollAway.tsx — derives direction from the scroll\n *     delta every frame, so an 800px correction would hide the header.\n *\n * It deliberately does NOT reuse `__anchorScrollActive`. That flag\n * means \"a menu jump is running\", and both consumers do jump-specific\n * things with it — ScrollSnap spends section entrance holds, and\n * HeaderScrollAway force-HIDES the header.\n * ═════════════════════════════════════════════════════════════════ */// ── THE ANCHORS ───────────────────────────────────────────────────\n// Authored anchor ids, in document order, each sitting at the top of\n// the thing it names. An id that isn't in the DOM is skipped without\n// complaint, so ONE list serves every page AND every CMS variation: a\n// collection that renders 4 of the 14 images simply contributes 4\n// anchors.\n//\n// WHY ONE PER PHOTO, and not just the section seams. The error in a\n// correction grows with the distance between the anchor and the eye,\n// because everything in between is reflowing too. The slug page's\n// gallery is a single section ~12,000px tall at 1200 and half that at\n// 320, so anchoring on `ph-content` alone would pin a point 5,000px\n// above a viewer nine photos down and let the photo they are actually\n// looking at slide off — the drift this file exists to stop. One\n// anchor per photo keeps that distance under about one photo, the\n// same short lever arm Home gets from its section seams.\n//\n// These are authored on the canvas rather than derived in code on\n// purpose: an id is a real identity, it survives renames and\n// restructuring, it needs no coupling to another override's\n// attributes, and it is visible where the layout is edited.\nconst ANCHOR_IDS=[// Home\n\"intro\",\"product-design\",\"service-design\",\"strategic-practices\",\"depth-breadth\",// /photography/:slug — section seams (these also drive the page's\n// header variant swaps, so they predate this file).\n//\n// `ph-header` IS DELIBERATELY ABSENT. It sits on the FIXED header,\n// which travels with the viewport: measured at scrollY 4664, its\n// rect top was -12 — i.e. ~0 at every scroll position, and it does\n// not move when the page reflows. capture() picks the SMALLEST\n// |top| at or above the viewport top, so a viewport-locked anchor\n// at dist 12 beat the photo just above the viewer's eye at dist\n// 200, and beat everything else by thousands. It won at\n// essentially every position on the page, delta was therefore\n// always ~0, and every correction died in the dead zone: nothing\n// logged, nothing moved, no error. The id stays on the canvas to\n// drive the header variant swaps — it just must never be an\n// anchor here.\n//\n// THE GENERAL RULE: an anchor has to be in normal flow. Anything\n// `position: fixed`, or `sticky` while it is stuck, is a fixed\n// point, and one of them in this list silently disables the whole\n// file for the entire page.\n\"ph-hero\",\"ph-content\",// /photography/:slug — one per gallery photo\n\"ph-img-1\",\"ph-img-2\",\"ph-img-3\",\"ph-img-4\",\"ph-img-5\",\"ph-img-6\",\"ph-img-7\",\"ph-img-8\",\"ph-img-9\",\"ph-img-10\",\"ph-img-11\",\"ph-img-12\",\"ph-img-13\",\"ph-img-14\",// /photography/:slug — below the gallery. `Bottom links` doubles\n// in height at the 4 -> 2 column swap, which matters to anyone\n// reading the footer.\n\"ph-links\",\"ph-footer\"];// ── LOOK-AHEAD, in pixels ─────────────────────────────────────────\n// How far BELOW the viewport top an anchor may sit and still be\n// chosen. 0 — the shipped value — means \"only anchors at or above the\n// top\", so the viewer is always held to the section they are in.\n//\n// Raising it trades that for accuracy near a seam. The error in this\n// correction grows with the distance between the anchor and the eye,\n// because all the content in between is reflowing too; sitting just\n// ABOVE a section's start is therefore the worst case, with the whole\n// previous section as the lever arm. Setting this to, say, 600 would\n// let the next section's own anchor take over for that last stretch,\n// where it is only a few hundred pixels away. Left at 0 because\n// ScrollSnap makes deep positions within a section uncommon.\nconst LOOK_AHEAD_PX=0;// ── TAIL, in milliseconds ─────────────────────────────────────────\n// How long to keep correcting after the LAST resize event. Covers the\n// late layout work this page does once dragging stops — measured at\n// ~120ms here, so 400 is comfortable without leaving the flag raised\n// long enough to be felt. A real wheel or touch ends it early.\nconst TAIL_MS=400;// ── DEAD ZONE, in pixels ──────────────────────────────────────────\n// Corrections smaller than this are skipped, so sub-pixel layout\n// noise never writes a scroll position. 1 is right unless you see the\n// page quiver at a width where nothing should be moving.\nconst MIN_CORRECTION_PX=1;// Logs install, every capture, and every correction — including ones\n// skipped by the dead zone, which are otherwise invisible and are\n// exactly what a \"nothing is happening\" report looks like. Set the\n// DevTools context to preview-module.html or you will be reading the\n// wrong document.\nconst DEBUG=false;/* ── THE ENGINE ────────────────────────────────────────────────────\n * Module scope, installed once, never torn down. This is page-level\n * behaviour that belongs to no single layer: keeping the state here\n * means the host can remount — which a breakpoint swap will do —\n * without losing the anchor mid-correction. Nothing accumulates, so\n * there is nothing to leak.\n * ────────────────────────────────────────────────────────────────── */const FLAG=\"__resizeAnchorActive\";let installed=false;let anchorId=null;let anchorTop=0;let lastWidth=0;let active=false;let tailUntil=0;let rafId=0;let scrollQueued=false;let docRo=null;/* ── THE VIEWPORT-LOCK GUARD ───────────────────────────────────────\n * An anchor has to be in NORMAL FLOW. Anything `position: fixed`, or\n * `sticky` while it is stuck, travels with the viewport: its rect top\n * is ~0 at every scroll position and does not change when the page\n * reflows. capture() picks the smallest |top|, so such an element\n * beats every real anchor by hundreds of pixels, wins at essentially\n * every scroll position, and makes delta ~0 forever. The whole file\n * then does nothing, with no error and no log — which is exactly how\n * `ph-header` (on the fixed header) disabled the slug page.\n *\n * `sticky` is rejected unconditionally even though it is only locked\n * while stuck. Losing one anchor is cheap; losing the page is not.\n *\n * Cached per id and cleared on every width change, since a breakpoint\n * swap can change how an element is positioned. The walk therefore\n * runs at most once per anchor per resize burst.\n * ────────────────────────────────────────────────────────────────── */const lockedCache=new Map;const isViewportLocked=el=>{let n=el;while(n&&n!==document.documentElement){const pos=getComputedStyle(n).position;if(pos===\"fixed\"||pos===\"sticky\")return true;n=n.parentElement;}return false;};// Nearest anchor at or above the viewport top (see LOOK_AHEAD_PX),\n// with its current offset from that top. Called only when we are NOT\n// correcting, so it always records a position the viewer chose.\nconst capture=()=>{let bestId=null;let bestTop=0;let bestDist=Infinity;for(let i=0;i<ANCHOR_IDS.length;i++){const id=ANCHOR_IDS[i];const el=document.getElementById(id);if(!el)continue;let locked=lockedCache.get(id);if(locked===undefined){locked=isViewportLocked(el);lockedCache.set(id,locked);if(DEBUG&&locked){console.log(\"[ResizeStabilizer] SKIPPING\",id,\"— fixed or sticky, cannot be an anchor\");}}if(locked)continue;const top=el.getBoundingClientRect().top;if(top>LOOK_AHEAD_PX)continue;const dist=Math.abs(top);if(dist<bestDist){bestDist=dist;bestId=id;bestTop=top;}}anchorId=bestId;anchorTop=bestTop;if(DEBUG){console.log(\"[ResizeStabilizer] capture\",\"scrollY\",Math.round(window.scrollY),\"->\",bestId===null?\"NO ANCHOR\":bestId,\"top\",Math.round(bestTop));}};// Put the remembered anchor back where it was, relative to the\n// viewport. Re-queried by id: the element it names may be a different\n// DOM node than the one measured, and that is fine.\nconst correct=()=>{if(!anchorId)return;const el=document.getElementById(anchorId);if(!el)return;const top=el.getBoundingClientRect().top;const delta=top-anchorTop;if(Math.abs(delta)<MIN_CORRECTION_PX)return;if(DEBUG){console.log(\"[ResizeStabilizer]\",anchorId,\"top\",Math.round(top),\"want\",Math.round(anchorTop),\"scrollBy\",Math.round(delta));}window.scrollTo({top:window.scrollY+delta,behavior:\"instant\"});};/* ── CORRECTING IN THE RIGHT PHASE ─────────────────────────────────\n * A frame runs: rAF callbacks -> IntersectionObserver -> ResizeObserver\n * -> paint. tick() runs in rAF, so when it measures, the OTHER\n * responsive overrides on the page have not written yet — they are\n * ResizeObserver-driven. `Ph_GalleryRamp` in particular sets the photo\n * width, the photos carry an aspect ratio, and their heights move\n * everything below them. That reflow lands after our scroll is already\n * committed.\n *\n * Measured on /photography/:slug while dragging 1200 -> 700: the error\n * at the anchor was 0.98px when read in rAF and 8.86px when read after\n * the ResizeObserver pass — a 17x difference. We were correcting\n * against a layout that is never painted, and the leftover appeared as\n * a steady ~8px vibration at the drag's own frequency.\n *\n * The fix is to correct again in the ResizeObserver phase, from an\n * observer on `document.documentElement`. What puts that delivery\n * AFTER the ramps' is not depth — it is creation order, and keeping\n * ours newest is the whole job of rearmDocRo() below.\n *\n * Both passes are kept. rAF still covers the tail, where nothing\n * resizes and this observer would never fire, and a second correction\n * in a frame that needs none simply finds delta ~0 and returns. Our\n * own write is a scroll, which changes no layout, so it cannot drive\n * the observer loop itself.\n *\n * THE OBSERVER EXISTS ONLY WHILE A CORRECTION RUNS (2026-09-30). It\n * used to be created at install and left on `<html>` for the life of\n * the page, doing nothing while idle. But merely being attached to the\n * shallowest element on the page made the browser report \"ResizeObserver\n * loop completed with undelivered notifications\" whenever a deeper\n * observer — the photo ramps — changed the page's height in the same\n * frame: the browser cannot re-deliver to a shallower target within one\n * frame, so it logs the error and delivers next frame. Harmless on\n * screen, but every one is an error-tracking event, and the same message\n * is how a REAL layout loop shows up — so idle noise hid the alarm.\n * Created at the start of each correction (rearmDocRo, which also keeps\n * it last in delivery order) and disconnected when it ends.\n * ────────────────────────────────────────────────────────────────── */const onDocResize=()=>{// Only while a width-driven correction is in flight. The document\n// resizes for plenty of reasons that are none of our business —\n// images decoding, sections mounting as they enter the viewport —\n// and correcting for those would fight the page.\nif(!active)return;correct();};/* ── STAYING LAST IN THE ResizeObserver ORDER ──────────────────────\n * ResizeObserver callbacks are delivered in the order the observers\n * were CREATED, so the pass above only reads settled layout while ours\n * is the NEWEST observer on the page. `install()` runs once per page\n * LOAD and never again, which quietly made that a matter of luck.\n *\n * On a fresh load it held: React runs a child's effects before its\n * parent's, so `Ph_GalleryRamp` on `images` builds its observer before\n * the page root's effect calls install(), and we land after it. Follow\n * a link instead — Framer's preview and the published site are both\n * SPAs — and `installed` is already true, so install() returns at once\n * and this observer keeps the slot it took on the FIRST page of the\n * session, while the new page's ramps get fresh, newer ones. We then\n * fire BEFORE them and correct against a layout that is never painted:\n * the exact bug the RO pass exists to fix, back again, and only on\n * pages reached by clicking rather than loading.\n *\n * Measured on /photography/outdoor-escapes reached by navigation, with\n * two probes armed either side of the ramp's observer — same frame,\n * same anchor: -0.98px read before it, -17.23px read after. The error\n * accumulates over the photos ABOVE the anchor, so a deep anchor on a\n * long gallery shows it worst, which is how it reads by eye.\n *\n * Re-creating the observer at the start of every resize burst makes\n * the ordering moot. By then every override on the page has mounted,\n * so a brand new observer is unconditionally the last one — whatever\n * layer hosts this file, and however the page was reached. One object\n * per drag. A component remounting MID-drag still gets a newer\n * observer than ours; the rAF tail absorbs that and the next burst\n * re-arms.\n * ────────────────────────────────────────────────────────────────── */const rearmDocRo=()=>{if(typeof ResizeObserver===\"undefined\")return;if(docRo)docRo.disconnect();docRo=new ResizeObserver(onDocResize);docRo.observe(document.documentElement);};const stop=()=>{active=false;window[FLAG]=false;rafId=0;// Idle, the observer has nothing to do, and attached to <html> it\n// only produces ResizeObserver loop errors. See onDocResize above.\nif(docRo){docRo.disconnect();docRo=null;}// Re-baseline at the new width so the next resize starts from\n// where the viewer actually is now.\ncapture();};const tick=()=>{correct();if(performance.now()<tailUntil){rafId=requestAnimationFrame(tick);return;}stop();};const onResize=()=>{const w=window.innerWidth;// HEIGHT-ONLY RESIZES MUST BE IGNORED. A mobile browser fires\n// `resize` every time its URL bar shows or hides, which happens\n// constantly while scrolling. Correcting for those would fight\n// the viewer's own scrolling on every phone. Only a width change\n// can reflow a layout, so only a width change is our business.\nif(w===lastWidth)return;lastWidth=w;// A breakpoint swap can change how a layer is positioned, so the\n// fixed/sticky verdicts are re-derived on the next capture().\nlockedCache.clear();if(!anchorId)return;tailUntil=performance.now()+TAIL_MS;if(active)return;active=true;window[FLAG]=true;// The newest observer is delivered last, which is the entire point\n// of the RO pass. See rearmDocRo().\nrearmDocRo();rafId=requestAnimationFrame(tick);};// Real input during the tail ends the correction rather than fighting\n// it — the viewer has taken over.\nconst onInput=()=>{if(active)tailUntil=0;};const onScroll=()=>{if(active)return;// our own writes; not a position to remember\nif(scrollQueued)return;scrollQueued=true;requestAnimationFrame(()=>{scrollQueued=false;if(!active)capture();});};const install=()=>{if(installed||typeof window===\"undefined\")return;installed=true;lastWidth=window.innerWidth;capture();if(DEBUG)console.log(\"[ResizeStabilizer] install\");// No observer yet: onResize creates one when a correction starts.\nwindow.addEventListener(\"scroll\",onScroll,{passive:true});window.addEventListener(\"resize\",onResize);window.addEventListener(\"wheel\",onInput,{passive:true});window.addEventListener(\"touchstart\",onInput,{passive:true});window.addEventListener(\"keydown\",onInput);};/* ── THE OVERRIDE ─────────────────────────────────────────────────── */// Framer finds overrides by signature, so this has to be a plain\n// (Component) => Component function declaration.\n//\n// Apply it to ONE page-level layer that exists in every breakpoint —\n// the page root, or `Section: Intro`. The host is only a mounting\n// point: all the state is at module scope, so which layer carries it\n// makes no difference beyond existing.\nexport function withResizeAnchor(Component){return props=>{const isCanvas=RenderTarget.current()===RenderTarget.canvas;useEffect(()=>{if(isCanvas)return;install();},[isCanvas]);return /*#__PURE__*/_jsx(Component,{...props});};}\nexport const __FramerMetadata__ = {\"exports\":{\"withResizeAnchor\":{\"type\":\"reactHoc\",\"name\":\"withResizeAnchor\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./ResizeStabilizer.map"],"mappings":"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"}