{"version":3,"file":"FitScale.DuHRYzPY.mjs","names":["useState","useEffect","useLayoutEffect"],"sources":["https:/framerusercontent.com/modules/TKbkvbE7yjrFPTO1vu5V/nk5HsqAEU88qttvOnbyu/FitScale.js"],"sourcesContent":["import{jsx as _jsx}from\"react/jsx-runtime\";import{useEffect,useLayoutEffect,useState}from\"react\";// The desktop composition is authored at this width, and the tablet\n// breakpoint runs from TABLET_MIN up to it. Both values mirror the page's\n// breakpoint ranges: Desktop 1440+, Tablet 810-1439.98, Phone below 810.\nconst DESIGN_WIDTH=1440;const TABLET_MIN=810;// The print composition's authored height inside the 1440px canvas.\nconst COMPOSITION_HEIGHT=725;// The phone design is authored at this width, the way the desktop design is\n// authored at 1440.\nconst PHONE_WIDTH=390;// The phone breakpoint runs all the way to 809.98, so scaling the 390 canvas\n// to fill it would reach 2.07x — correct arithmetic, absurd typography. Every\n// phone in portrait is at most about 440 points wide, so 1.3 (507px) covers the\n// real devices and anything wider keeps that size and centres, which is what it\n// did before. Raise this only if a device genuinely needs it.\nconst MAX_PHONE_SCALE=1.3;// Framer shares a code override across every breakpoint of a layer — only\n// layout attributes are per-breakpoint — so this cannot be attached to the\n// tablet copy alone. It gates itself on viewport width instead and returns 1,\n// meaning \"do nothing\", on both Desktop and Phone.\nfunction measure(reference){if(typeof window===\"undefined\")return 1;const width=window.innerWidth;if(width>=DESIGN_WIDTH||width<TABLET_MIN)return 1;// Never scale up past the authored size, so a wide tablet matches desktop.\nreturn Math.min(1,width/reference);}// useLayoutEffect would warn during server rendering, where it is a no-op\n// anyway, so fall back to useEffect there.\nconst useIsomorphicLayoutEffect=typeof window===\"undefined\"?useEffect:useLayoutEffect;function useFitScale(reference){// This must start at 1 so the first client render is byte-identical to\n// the server's. Reading the viewport during render instead makes the two\n// diverge, and React responds to that hydration mismatch by keeping the\n// server's markup — which silently pinned every section at zoom 1 and\n// stopped the resize listener from ever being attached (React error 418).\n// Correcting it in a layout effect patches the DOM before the browser\n// paints, so there is no visible unscaled frame.\nconst[scale,setScale]=useState(1);useIsomorphicLayoutEffect(()=>{const update=()=>setScale(measure(reference));update();window.addEventListener(\"resize\",update);return()=>window.removeEventListener(\"resize\",update);},[reference]);return scale;}// Builds the style patch shared by the scaling overrides. Returning nothing\n// but the zoom outside the tablet range keeps Desktop and Phone exactly as\n// authored.\nfunction fitStyle(style,scale){if(scale===1)return{...style,zoom:1};return{...style,zoom:scale,width:`${DESIGN_WIDTH}px`};}/**\n * Scales a section authored at 1440 down to fit a tablet viewport, so the\n * tablet breakpoint is the desktop design at a smaller size rather than a\n * different layout.\n *\n * This uses `zoom`, not `transform: scale()`, and the difference matters.\n * A transform does not participate in layout: the section would keep its full\n * height and leave a gap beneath it, and `100vh` inside a transformed subtree\n * is resolved before the transform, which breaks the showreel's sticky stage\n * (measured: a 900px stage rendered 640px and stopped pinning). `zoom` scales\n * the layout box itself, so the page reflows on its own and vh keeps working.\n *\n * While active the element is pinned to the design width, so\n * DESIGN_WIDTH * zoom lands exactly on the viewport width. Outside the tablet\n * range nothing is applied, leaving each breakpoint's own width alone.\n */export function withFitScale(Component){return props=>{const scale=useFitScale(DESIGN_WIDTH);return /*#__PURE__*/_jsx(Component,{...props,style:fitStyle(props.style,scale)});};}/**\n * The print composition, contained within the tablet viewport.\n *\n * This previously scaled against the print cluster (1068px) rather than the\n * 1440px canvas, on the reasoning that roughly 180px of each side of the canvas\n * is empty, so scaling by the canvas made the prints read smaller than they do\n * on desktop. That held while the prints slid in from off-screen, because the\n * sequence drew the eye and the clipped margins were never the subject.\n *\n * It does not hold now that the tablet showreel is static. Measured at 820px\n * wide, cluster scaling rendered the composition 1106px wide at left -143,\n * clipping artwork off BOTH edges — the portrait print was cut on the left and\n * the Help! badge read \"Hel\" on the right. Scaling by DESIGN_WIDTH instead\n * makes 1440 * zoom land exactly on the viewport width, so the whole\n * composition is visible at every tablet size with nothing cropped.\n */export function withPrintScale(Component){return props=>{const scale=useFitScale(DESIGN_WIDTH);return /*#__PURE__*/_jsx(Component,{...props,style:fitStyle(props.style,scale)});};}/**\n * The showreel Stage, whose height follows the scaled composition.\n *\n * The Stage is authored at 100vh so the desktop pin fills the screen, but\n * viewport height does not shrink with width, so on tablet that left a large\n * band of dead black beneath the artwork — measured at 820 x 1180, a 557px\n * composition sat in a 906px stage, and the stage itself sat inside a 3068px\n * section. With the tablet sequence now static there is nothing for that space\n * to do, so the stage is given the composition's own scaled height instead and\n * the section collapses onto it.\n *\n * It must not apply `zoom` — that would resolve the stage's own vh against a\n * scaled box and break the desktop sticky pin. It only sets the height.\n */export function withPrintStage(Component){return props=>{const scale=useFitScale(DESIGN_WIDTH);if(scale===1)return /*#__PURE__*/_jsx(Component,{...props});return /*#__PURE__*/_jsx(Component,{...props,style:{...props.style,height:`${COMPOSITION_HEIGHT*scale}px`}});};}/**\n * The hero, scaled to whatever width the device actually is.\n *\n * The Phone breakpoint is authored on a 390px canvas and several hero sections\n * were left pinned to that number, so on a 430pt phone they sat 40px short of\n * the screen with black down both sides — reported from a device, and visible\n * in the recording. Most sections can simply be set to 100% instead, and have\n * been. The hero cannot: it is a stack of six overlapping layers whose\n * alignment is pixel-specific. Its buildings are pinned left and right so they\n * would stretch with the section, while the window-colour overlay is pinned on\n * one side only and would not, pulling apart the alignment that took two passes\n * to get right. Scaling keeps every layer in the same relationship.\n *\n * Below 810 the reference is the phone canvas, between 810 and 1440 it is the\n * desktop canvas — the same rule withFitScale applies — and at 1440 and above\n * nothing is applied. 390 and 1440 both resolve to a scale of exactly 1.\n *\n * This also fixes the smaller phones, which were overflowing: a 390px hero in\n * a 375px viewport now scales to 0.962 instead of running off the edge.\n */export function withHeroScale(Component){return props=>{// Both start at their server-rendered values, for the hydration reason\n// documented on useFitScale above.\nconst[fit,setFit]=useState({scale:1,reference:DESIGN_WIDTH});useIsomorphicLayoutEffect(()=>{const update=()=>{const width=window.innerWidth;if(width>=DESIGN_WIDTH){setFit({scale:1,reference:DESIGN_WIDTH});}else if(width>=TABLET_MIN){setFit({scale:width/DESIGN_WIDTH,reference:DESIGN_WIDTH});}else{setFit({scale:Math.min(MAX_PHONE_SCALE,width/PHONE_WIDTH),reference:PHONE_WIDTH});}};update();window.addEventListener(\"resize\",update);return()=>window.removeEventListener(\"resize\",update);},[]);if(fit.scale===1){return /*#__PURE__*/_jsx(Component,{...props,style:{...props.style,zoom:1}});}return /*#__PURE__*/_jsx(Component,{...props,style:{...props.style,zoom:fit.scale,width:`${fit.reference}px`}});};}\nexport const __FramerMetadata__ = {\"exports\":{\"withPrintScale\":{\"type\":\"reactHoc\",\"name\":\"withPrintScale\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withHeroScale\":{\"type\":\"reactHoc\",\"name\":\"withHeroScale\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withPrintStage\":{\"type\":\"reactHoc\",\"name\":\"withPrintStage\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"withFitScale\":{\"type\":\"reactHoc\",\"name\":\"withFitScale\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./FitScale.map"],"mappings":"oIAeA,SAAS,EAAQ,EAAU,CAAC,GAAU,IAAS,OAAY,MAAO,GAAE,IAAM,EAAM,EAAO,WACvF,OADqG,GAAO,GAAc,EAAM,EAAkB,EAC3I,KAAK,IAAI,EAAE,EAAM,CAAS,CAAE,CAEmD,SAAS,EAAY,EAAU,CAOrH,GAAK,CAAC,EAAM,GAAUA,EAAS,CAAC,EAAsM,OAApM,MAA8B,CAAC,IAAM,MAAW,EAAS,EAAQ,CAAS,CAAC,EAAoD,OAAlD,EAAO,EAAE,EAAO,iBAAiB,SAAS,CAAM,MAAY,EAAO,oBAAoB,SAAS,CAAM,CAAE,EAAE,CAAC,CAAS,CAAC,EAAS,CAAM,CAGnP,SAAS,EAAS,EAAM,EAAM,CAAsC,OAAlC,IAAQ,EAAQ,CAAC,GAAG,EAAM,KAAK,CAAC,EAAQ,CAAC,GAAG,EAAM,KAAK,EAAM,MAAM,GAAG,EAAa,GAAG,CAAE,CAevH,SAAgB,EAAa,EAAU,CAAC,MAAO,IAAO,CAAC,IAAM,EAAM,EAAY,CAAY,EAAE,OAAoB,EAAK,EAAU,CAAC,GAAG,EAAM,MAAM,EAAS,EAAM,MAAM,CAAK,CAAC,CAAC,CAAE,CAAE,CAehL,SAAgB,EAAe,EAAU,CAAC,MAAO,IAAO,CAAC,IAAM,EAAM,EAAY,CAAY,EAAE,OAAoB,EAAK,EAAU,CAAC,GAAG,EAAM,MAAM,EAAS,EAAM,MAAM,CAAK,CAAC,CAAC,CAAE,CAAE,CAalL,SAAgB,EAAe,EAAU,CAAC,MAAO,IAAO,CAAC,IAAM,EAAM,EAAY,CAAY,EAA8D,OAAzD,IAAQ,EAAsB,EAAK,EAAU,CAAC,GAAG,CAAK,CAAC,EAAsB,EAAK,EAAU,CAAC,GAAG,EAAM,MAAM,CAAC,GAAG,EAAM,MAAM,OAAO,GAAG,EAAmB,EAAM,GAAG,CAAC,CAAC,CAAE,CAAE,CAmB1Q,SAAgB,EAAc,EAAU,CAAC,MAAO,IAAO,CAE1D,GAAK,CAAC,EAAI,GAAQA,EAAS,CAAC,MAAM,EAAE,UAAU,CAAY,CAAC,EAAihB,OAA/gB,MAA8B,CAAC,IAAM,MAAW,CAAC,IAAM,EAAM,EAAO,WAAmC,EAArB,GAAO,EAAqB,CAAC,MAAM,EAAE,UAAU,CAAY,EAAY,GAAO,EAAmB,CAAC,MAAM,EAAM,EAAa,UAAU,CAAY,EAAgB,CAAC,MAAM,KAAK,IAAI,EAAgB,EAAM,CAAW,EAAE,UAAU,CAAW,CAAC,CAAG,EAAoD,OAAlD,EAAO,EAAE,EAAO,iBAAiB,SAAS,CAAM,MAAY,EAAO,oBAAoB,SAAS,CAAM,CAAE,EAAE,CAAC,CAAC,EAAK,EAAI,QAAQ,EAAuB,EAAK,EAAU,CAAC,GAAG,EAAM,MAAM,CAAC,GAAG,EAAM,MAAM,KAAK,CAAC,CAAC,CAAC,EAAuB,EAAK,EAAU,CAAC,GAAG,EAAM,MAAM,CAAC,GAAG,EAAM,MAAM,KAAK,EAAI,MAAM,MAAM,GAAG,EAAI,UAAU,GAAG,CAAC,CAAC,CAAE,CAAE,iCA5FppB,IAAsD,EAG1F,EAAa,KAAW,EAAW,IACnC,EAAmB,IAEnB,EAAY,IAKZ,EAAgB,IAOhB,EAAiC,IAAS,OAAYC,EAAUC"}