{"version":3,"file":"script_main.CIxXICFL.mjs","names":["serializationHash","variantClassNames","React.useContext","React.useMemo","React.Fragment","getProps","React.forwardRef","useRef","React.useId","css","html","useRef","Cursor","useRef","React.useId","React.createElement","Default","Framer.PageRoot","Framer.lazy","Framer.useCurrentRoute","Framer.useLocaleInfo","Framer.useRouter","React.Fragment","React.memo","React.useCallback","React.useEffect","React.useRef","React.useState","React.useLayoutEffect","Framer.LazyValue","Framer.GracefullyDegradingErrorBoundary","Framer.PageEffectsProvider","Framer.patchRoutesForABTesting","Framer.inferInitialRouteFromPath","Framer.yieldToMain","React.startTransition","Framer.ErrorPlaceholder"],"sources":["https:/framerusercontent.com/modules/1B55vam08teebKwm2k3T/XXPMXDK29IIQ1TXrR5qF/vh_nMD40O.js","https:/framerusercontent.com/modules/l2c9Dfz2TcVrzyjO0eOS/XxuiITWqLp24XXXQCLvs/ScanbrixChrome.js","https:/framerusercontent.com/modules/HdY9XQsKRlK1PVcD6Jb9/cuW3AR9cY3Sy0leoE6yw/ScanbrixSiteFooter.js","https:/framerusercontent.com/modules/fZU8AlZfdY4TcnzlrdfC/WQFa19iWBhK9a71YWLM5/lOqVnEz02.js","framer:toplevel/main"],"sourcesContent":["// Generated by Framer (d31575f)\nimport{jsx as _jsx}from\"react/jsx-runtime\";import{addFonts,cx,useComponentViewport,useLocaleInfo,useVariantState,withCSS}from\"framer\";import{LayoutGroup,motion,MotionConfigContext}from\"framer-motion\";import*as React from\"react\";import{useRef}from\"react\";const serializationHash=\"framer-nN3aO\";const variantClassNames={LjPzaZG89:\"framer-v-c4wx92\"};function addPropertyOverrides(overrides,...variants){const nextOverrides={};variants?.forEach(variant=>variant&&Object.assign(nextOverrides,overrides[variant]));return nextOverrides;}const transition1={bounce:.2,delay:0,duration:.4,type:\"spring\"};const Transition=({value,children})=>{const config=React.useContext(MotionConfigContext);const transition=value??config.transition;const contextValue=React.useMemo(()=>({...config,transition}),[JSON.stringify(transition)]);return /*#__PURE__*/_jsx(MotionConfigContext.Provider,{value:contextValue,children:children});};const Variants=motion.create(React.Fragment);const getProps=({height,id,width,...props})=>{return{...props};};const createLayoutDependency=(props,variants)=>{if(props.layoutDependency)return variants.join(\"-\")+props.layoutDependency;return variants.join(\"-\");};const Component=/*#__PURE__*/React.forwardRef(function(props,ref){const fallbackRef=useRef(null);const refBinding=ref??fallbackRef;const defaultLayoutId=React.useId();const{activeLocale,setLocale}=useLocaleInfo();const componentViewport=useComponentViewport();const{style,className,layoutId,variant,...restProps}=getProps(props);const{baseVariant,classNames,clearLoadingGesture,gestureHandlers,gestureVariant,isLoading,setGestureState,setVariant,variants}=useVariantState({defaultVariant:\"LjPzaZG89\",ref:refBinding,variant,variantClassNames});const layoutDependency=createLayoutDependency(props,variants);const sharedStyleClassNames=[];const scopingClassNames=cx(serializationHash,...sharedStyleClassNames);return /*#__PURE__*/_jsx(LayoutGroup,{id:layoutId??defaultLayoutId,children:/*#__PURE__*/_jsx(Variants,{animate:variants,initial:false,children:/*#__PURE__*/_jsx(Transition,{value:transition1,children:/*#__PURE__*/_jsx(motion.div,{...restProps,...gestureHandlers,className:cx(scopingClassNames,\"framer-c4wx92\",className,classNames),\"data-framer-name\":\"Variant 1\",layoutDependency:layoutDependency,layoutId:\"LjPzaZG89\",ref:refBinding,style:{backgroundColor:\"var(--token-ecc57efd-87d7-43d0-8885-75f6ec18cbe2, rgb(46, 145, 247))\",borderBottomLeftRadius:99,borderBottomRightRadius:99,borderTopLeftRadius:99,borderTopRightRadius:99,...style}})})})});});const css=[\"@supports (aspect-ratio: 1) { body { --framer-aspect-ratio-supported: auto; } }\",\".framer-nN3aO.framer-1ndwjw4, .framer-nN3aO .framer-1ndwjw4 { display: block; }\",\".framer-nN3aO.framer-c4wx92 { height: 18px; overflow: var(--overflow-clip-fallback, clip); position: relative; width: 18px; will-change: var(--framer-will-change-override, transform); }\"];/**\n * This is a generated Framer component.\n * @framerIntrinsicHeight 18\n * @framerIntrinsicWidth 18\n * @framerCanvasComponentVariantDetails {\"propertyName\":\"variant\",\"data\":{\"default\":{\"layout\":[\"fixed\",\"fixed\"]}}}\n * @framerImmutableVariables true\n * @framerDisplayContentsDiv false\n * @framerAutoSizeImages true\n * @framerComponentViewportWidth true\n * @framerColorSyntax true\n */const Framervh_nMD40O=withCSS(Component,css,\"framer-nN3aO\");export default Framervh_nMD40O;Framervh_nMD40O.displayName=\"cursor\";Framervh_nMD40O.defaultProps={height:18,width:18};addFonts(Framervh_nMD40O,[{explicitInter:true,fonts:[]}],{supportsExplicitInterCodegen:true});\nexport const __FramerMetadata__ = {\"exports\":{\"Props\":{\"type\":\"tsType\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"default\":{\"type\":\"reactComponent\",\"name\":\"Framervh_nMD40O\",\"slots\":[],\"annotations\":{\"framerImmutableVariables\":\"true\",\"framerCanvasComponentVariantDetails\":\"{\\\"propertyName\\\":\\\"variant\\\",\\\"data\\\":{\\\"default\\\":{\\\"layout\\\":[\\\"fixed\\\",\\\"fixed\\\"]}}}\",\"framerIntrinsicWidth\":\"18\",\"framerColorSyntax\":\"true\",\"framerAutoSizeImages\":\"true\",\"framerContractVersion\":\"1\",\"framerIntrinsicHeight\":\"18\",\"framerDisplayContentsDiv\":\"false\",\"framerComponentViewportWidth\":\"true\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./vh_nMD40O.map","// Generated from index.html by tools/build-framer-page.mjs. Do not edit.\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useEffect}from\"react\";const css='\\n/* ===========================================================================\\n   0. DISPLAY FACE — IBM Plex Sans Bold (SIL OFL, self-hosted)\\n   Headlines, statements and big numerals only. Body copy stays on the\\n   system stack so UI text keeps the native, serious tone.\\n   ======================================================================== */\\n@font-face{\\n  font-family:\"IBM Plex Sans\";\\n  src:url(\"https://framerusercontent.com/assets/9pNls7yt19FCEkLyHhfPAHQNAg.woff2\") format(\"woff2\");\\n  font-weight:700; font-style:normal; font-display:swap;\\n  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;\\n}\\n@font-face{\\n  font-family:\"IBM Plex Sans\";\\n  src:url(\"https://framerusercontent.com/assets/mKeM5ruDbqqplzAPZaFhw1KfYs4.woff2\") format(\"woff2\");\\n  font-weight:700; font-style:normal; font-display:swap;\\n  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;\\n}\\n\\n/* ===========================================================================\\n   1. TOKENS\\n   ======================================================================== */\\n:root{\\n  /* Value ladder. The app sits on a warm off-white; cards go pure white so\\n     the step between page and card does the work a border would. */\\n  --bone:      #F4F2ED;\\n  --bone-deep: #E8E5DD;   /* section panels */\\n  --bone-well: #DEDAD0;   /* recessed / hairline on bone */\\n  --white:     #FFFFFF;\\n\\n  --ink:   #0B0B0C;\\n  --ink-2: #55534F;\\n  --ink-3: #6B6864;   /* 4.9:1 on bone — passes WCAG AA for body text */\\n  --ink-4: #6B6864;   /* 4.9:1 on bone — muted \"was\" figures, statement unlit words */\\n\\n  --line:   rgba(11,11,12,.08);\\n  --line-2: rgba(11,11,12,.15);\\n\\n  /* The one accent. */\\n  --blue:      #2889EF;\\n  --blue-deep: #1668C8;\\n  --blue-wash: #E7EFFB;\\n\\n  --dark:   #0A0B0D;\\n  --dark-2: #14161A;\\n\\n  /* Avatar colours are real app data, not chrome — they may stay off-palette */\\n  --av-1:#2889EF; --av-2:#F97316; --av-3:#2A6F4F;\\n\\n  --r-sm:10px; --r-md:16px; --r-lg:22px; --r-xl:28px; --r-2xl:40px;\\n\\n  /* Shadows carry a cool cast rather than neutral grey: light in the real\\n     world is blue, and a slate-tinted shadow is what makes a white card read\\n     as lit rather than pasted on. */\\n  --sh-sm: 0 1px 2px rgba(17,26,45,.05), 0 3px 10px rgba(17,26,45,.045);\\n  --sh-md: 0 2px 4px rgba(17,26,45,.05), 0 10px 26px rgba(17,26,45,.07);\\n  --sh-lg: 0 4px 8px rgba(17,26,45,.05), 0 24px 56px rgba(17,26,45,.10);\\n  --sh-blue: 0 10px 30px -8px rgba(40,137,239,.36);\\n  --sh-device:\\n    0 0 0 .5px rgba(0,0,0,.55),\\n    0 0 0 1px rgba(255,255,255,.09),\\n    0 1px 2px rgba(0,0,0,.18),\\n    0 10px 22px -6px rgba(11,11,12,.22),\\n    0 32px 64px -16px rgba(11,11,12,.30);\\n\\n  --sans: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"SF Pro Text\",\\n          \"Inter\", \"Helvetica Neue\", Arial, sans-serif;\\n  --display: \"IBM Plex Sans\", -apple-system, BlinkMacSystemFont, \"SF Pro Display\",\\n          \"Helvetica Neue\", Arial, sans-serif;\\n  --mono: ui-monospace, \"SF Mono\", \"JetBrains Mono\", Menlo, monospace;\\n\\n  --maxw: 1200px;\\n  --gut: 28px;\\n  --ease: cubic-bezier(.22,.68,.24,1);\\n}\\n\\n*,*::before,*::after{box-sizing:border-box}\\n/* No overflow on <html>: `overflow-x:clip` here establishes a clip region that\\n   a position:fixed + backdrop-filter descendant (the nav) can get clipped by.\\n   body\\'s overflow-x:hidden below is the horizontal guard. */\\nhtml{-webkit-text-size-adjust:100%; scroll-behavior:smooth}\\nbody{\\n  margin:0; background:var(--bone); color:var(--ink);\\n  font-family:var(--sans); font-size:17px; line-height:1.5;\\n  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;\\n  overflow-x:hidden;\\n}\\nbody.menu-open{overflow:hidden}\\nimg,svg{display:block; max-width:100%}\\nbutton{font:inherit; color:inherit; border:0; background:none; cursor:pointer}\\na{color:inherit; text-decoration:none}\\nh1,h2,h3,h4,p{margin:0}\\nul{margin:0; padding:0; list-style:none}\\n::selection{background:var(--blue); color:#fff}\\n\\n/* Anchor targets scroll clear of the fixed nav */\\n[id]{scroll-margin-top:104px}\\n\\n/* Keyboard focus — visible, on-brand, never removed */\\n:focus-visible{outline:2px solid var(--blue); outline-offset:3px; border-radius:4px}\\n\\n.wrap{width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gut)}\\n.section{padding-block:clamp(60px,7vw,112px); position:relative}\\n.panel{\\n  background:var(--bone-deep); border-radius:var(--r-2xl);\\n  margin-inline:14px; padding-block:clamp(52px,6vw,96px);\\n  position:relative; overflow:hidden;\\n}\\n\\n/* Scroll progress — the only permanently visible piece of chrome */\\n.progress{\\n  position:fixed; top:0; left:0; height:2px; z-index:200;\\n  width:100%; transform:scaleX(0); transform-origin:0 50%;\\n  background:var(--blue);\\n  will-change:transform;\\n}\\n\\n/* Cursor dot trail — desktop only, progressive enhancement */\\n.cursor-trail{\\n  position:fixed; inset:0; z-index:160;\\n  pointer-events:none; overflow:hidden;\\n}\\n.cursor-trail__dot{\\n  position:absolute; left:0; top:0;\\n  width:7px; height:7px; border-radius:50%;\\n  background:var(--blue);\\n  opacity:0;\\n  transform:translate3d(-100px,-100px,0);\\n  will-change:transform, opacity;\\n}\\n.cursor-trail__dot--lead{\\n  width:9px; height:9px;\\n  background:var(--blue-deep);\\n  box-shadow:0 0 0 3px rgba(40,137,239,.12);\\n}\\n@media (prefers-reduced-motion:reduce){ .cursor-trail{display:none} }\\n\\n/* ===========================================================================\\n   2. GLASS — used only for things genuinely floating over content\\n   ======================================================================== */\\n.glass{\\n  -webkit-backdrop-filter:blur(20px) saturate(180%);\\n  backdrop-filter:blur(20px) saturate(180%);\\n  background:rgba(250,249,246,.72);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.9),\\n    inset 0 0 0 1px rgba(11,11,12,.06),\\n    0 1px 2px rgba(11,11,12,.04),\\n    0 18px 40px -12px rgba(11,11,12,.18);\\n}\\n/* Near-opaque variant for panels that straddle both dark and light backdrops\\n   (the hero callouts overhang the device onto the page). A translucent fill\\n   has almost no contrast against bone, so the panel edge stops reading. */\\n.glass--solid{\\n  -webkit-backdrop-filter:none; backdrop-filter:none;\\n  background:linear-gradient(155deg,rgba(255,255,255,.8) 0%,rgba(255,255,255,0) 52%),#FCFCFB;\\n  box-shadow:inset 0 1px 0 rgba(255,255,255,1), inset 0 0 0 1px rgba(11,11,12,.07);\\n}\\n@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){\\n  .glass{background:rgba(250,249,246,.96)}\\n}\\n\\n/* Blueprint grid. Single hairline weight, masked so it fades out — texture,\\n   not decoration. */\\n.grid-bg{\\n  position:absolute; inset:0; pointer-events:none; z-index:0;\\n  background-image:\\n    linear-gradient(to right, rgba(11,11,12,.05) 1px, transparent 1px),\\n    linear-gradient(to bottom, rgba(11,11,12,.05) 1px, transparent 1px);\\n  background-size:80px 80px;\\n  mask-image:radial-gradient(115% 88% at 62% 4%, #000 0%, transparent 72%);\\n  -webkit-mask-image:radial-gradient(115% 88% at 62% 4%, #000 0%, transparent 72%);\\n}\\n\\n/* ===========================================================================\\n   3. TYPE & PRIMITIVES\\n   ======================================================================== */\\n/* Display type is where the page gets its voice — the scale steps up half a\\n   notch versus body copy, which stays on the system font throughout. */\\n.h1{font-family:var(--display); font-size:clamp(2.55rem,4.6vw,4.15rem); line-height:0.98; letter-spacing:-.03em; font-weight:700}\\n.h1 .dim{color:var(--ink-3)}\\n.h2{font-family:var(--display); font-size:clamp(2.05rem,3.8vw,3.35rem); line-height:1.03; letter-spacing:-.026em; font-weight:700}\\n.h3{font-size:clamp(1.15rem,1.7vw,1.4rem); line-height:1.2; letter-spacing:-.02em; font-weight:640}\\n.lead{font-size:clamp(1.05rem,1.32vw,1.22rem); line-height:1.55; color:var(--ink-2); letter-spacing:-.012em}\\n.body{color:var(--ink-2); font-size:1rem; line-height:1.6}\\n.small{font-size:.875rem; line-height:1.5; color:var(--ink-3)}\\n.tnum{font-variant-numeric:tabular-nums}\\n\\n/* Eyebrows are set like dimension annotations on a drawing: a measurement\\n   line with end ticks on either side of the label. Mono, because that\\'s what\\n   dimensions are set in. This motif recurs across the page — it is the\\n   brand\\'s graphic signature, not decoration. */\\n.eyebrow{\\n  display:inline-flex; align-items:center; gap:12px;\\n  font-family:var(--mono); font-size:.72rem; font-weight:600;\\n  letter-spacing:.11em; text-transform:uppercase;\\n  color:var(--ink-3); margin-bottom:20px;\\n}\\n.eyebrow::before,.eyebrow::after{\\n  content:\"\"; width:26px; height:9px; flex:0 0 auto;\\n  background:\\n    linear-gradient(var(--blue),var(--blue)) left center/1.5px 9px no-repeat,\\n    linear-gradient(var(--blue),var(--blue)) center/100% 1px no-repeat;\\n}\\n.eyebrow::after{\\n  background:\\n    linear-gradient(var(--blue),var(--blue)) right center/1.5px 9px no-repeat,\\n    linear-gradient(var(--blue),var(--blue)) center/100% 1px no-repeat;\\n}\\n.eyebrow--onDark{color:rgba(255,255,255,.66)}\\n\\n.badge{\\n  display:inline-flex; align-items:center; gap:10px;\\n  padding:8px 16px 8px 13px; border-radius:99px;\\n  font-size:.8125rem; font-weight:500; color:var(--ink-2); letter-spacing:-.005em;\\n}\\n.badge b{font-weight:640; color:var(--ink)}\\n.badge .dot{\\n  width:6px; height:6px; border-radius:99px; background:var(--blue); flex:0 0 auto;\\n  box-shadow:0 0 0 0 rgba(40,137,239,.5); animation:pulse 2.6s var(--ease) infinite;\\n}\\n@keyframes pulse{\\n  0%{box-shadow:0 0 0 0 rgba(40,137,239,.45)}\\n  70%{box-shadow:0 0 0 7px rgba(40,137,239,0)}\\n  100%{box-shadow:0 0 0 0 rgba(40,137,239,0)}\\n}\\n\\n.btn{\\n  display:inline-flex; align-items:center; gap:11px;\\n  padding:0 22px; height:54px; border-radius:15px;\\n  font-size:.97rem; font-weight:600; letter-spacing:-.012em;\\n  transition:transform .22s var(--ease), box-shadow .22s var(--ease), background .2s, color .2s;\\n  position:relative; overflow:hidden;\\n}\\n.btn:active{transform:translateY(1px) scale(.98)}\\n.btn--line{background:transparent; color:var(--ink); box-shadow:inset 0 0 0 1px var(--line-2)}\\n.btn--line:hover{box-shadow:inset 0 0 0 1px var(--ink), var(--sh-sm); transform:translateY(-2px)}\\n.btn--line:active{box-shadow:inset 0 0 0 1px var(--ink)}\\n.btn--lineDark{background:transparent; color:#fff; box-shadow:inset 0 0 0 1px rgba(255,255,255,.22)}\\n.btn--lineDark:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5), 0 8px 24px rgba(0,0,0,.25); transform:translateY(-2px)}\\n.btn--lineDark:active{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}\\n.btn .sub{display:block; font-size:.68rem; font-weight:500; opacity:.6; letter-spacing:0; line-height:1.1}\\n.btn .main{display:block; line-height:1.15}\\n.btn__ic{\\n  width:36px; height:36px; border-radius:11px; flex:0 0 auto;\\n  display:grid; place-items:center;\\n  background:rgba(40,137,239,.12); color:var(--blue-deep);\\n  transition:background .22s var(--ease), transform .22s var(--ease);\\n}\\n.btn__ic svg{width:18px; height:18px}\\n.btn__tx{display:flex; flex-direction:column; align-items:flex-start; gap:1px; text-align:left}\\n.btn__arrow{\\n  color:var(--blue); opacity:.5; flex:0 0 auto; margin-left:2px;\\n  transition:transform .22s var(--ease), opacity .22s var(--ease);\\n}\\n.btn--walkthrough{\\n  background:linear-gradient(180deg, #fff 0%, var(--blue-wash) 100%);\\n  color:var(--ink);\\n  box-shadow:inset 0 0 0 1px rgba(40,137,239,.24), var(--sh-sm);\\n  padding-inline:14px 18px;\\n  gap:12px;\\n}\\n.btn--walkthrough--soft{\\n  background:rgba(255,255,255,.55);\\n  box-shadow:inset 0 0 0 1px var(--line-2);\\n}\\n.btn--walkthrough--soft .btn__ic{background:var(--bone-deep); color:var(--ink-3)}\\n.btn--walkthrough--soft .btn__arrow{color:var(--ink-4)}\\n.btn--walkthrough--soft:hover{\\n  background:rgba(255,255,255,.88);\\n  box-shadow:inset 0 0 0 1px var(--bone-well), var(--sh-sm);\\n}\\n.btn--walkthrough--soft:hover .btn__ic{background:var(--bone-well); color:var(--ink-2)}\\n.btn--walkthrough--soft:hover .btn__arrow{color:var(--ink-3)}\\n.btn--walkthrough .sub{color:var(--ink-3); opacity:1; font-weight:500}\\n.btn--walkthrough:hover{\\n  transform:translateY(-2px);\\n  box-shadow:inset 0 0 0 1px rgba(40,137,239,.4), 0 12px 30px rgba(40,137,239,.16);\\n  background:linear-gradient(180deg, #fff 0%, #dce9fb 100%);\\n}\\n.btn--walkthrough:hover .btn__ic{background:rgba(40,137,239,.18); transform:scale(1.04)}\\n.btn--walkthrough:hover .btn__arrow{opacity:1; transform:translateX(3px)}\\n.btn--walkthrough:active{transform:translateY(0)}\\n.btn--walkthrough--dark{\\n  background:rgba(255,255,255,.09);\\n  color:#fff;\\n  -webkit-backdrop-filter:blur(12px) saturate(140%);\\n  backdrop-filter:blur(12px) saturate(140%);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.14),\\n    inset 0 0 0 1px rgba(255,255,255,.24),\\n    0 8px 28px rgba(0,0,0,.28);\\n}\\n.btn--walkthrough--dark .btn__ic{background:rgba(255,255,255,.14); color:#fff}\\n.btn--walkthrough--dark .sub{color:rgba(255,255,255,.62); opacity:1}\\n.btn--walkthrough--dark .btn__arrow{color:rgba(255,255,255,.75)}\\n.btn--walkthrough--dark:hover{\\n  background:rgba(255,255,255,.14);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.2),\\n    inset 0 0 0 1px rgba(255,255,255,.38),\\n    0 14px 36px rgba(0,0,0,.34),\\n    0 0 40px rgba(40,137,239,.18);\\n}\\n.btn--walkthrough--dark:hover .btn__ic{background:rgba(255,255,255,.2)}\\n@media (hover:none){\\n  .btn--walkthrough:hover,.btn--walkthrough--dark:hover{transform:none}\\n  .btn--walkthrough:hover .btn__arrow,.btn--walkthrough--dark:hover .btn__arrow{transform:none}\\n}\\n\\n\\n/* Apple App Store marketing badge — scale only, per Apple guidelines. */\\n.app-store-badge{\\n  display:inline-block; line-height:0; border-radius:8px;\\n  transition:transform .2s var(--ease), box-shadow .2s var(--ease);\\n}\\n/* Primary CTA on the page — it earns a lift and a little light of its own\\n   instead of just fading on hover. */\\n.app-store-badge:hover{transform:translateY(-2px); box-shadow:var(--sh-blue)}\\n.app-store-badge:active{transform:translateY(0); box-shadow:none}\\n.app-store-badge img{display:block; height:44px; width:auto}\\n.app-store-badge--sm img{height:36px}\\n.app-store-badge--wide{display:flex; justify-content:center; width:100%}\\n\\n.card{\\n  background:var(--white); border-radius:var(--r-xl); box-shadow:var(--sh-sm);\\n  transition:transform .28s var(--ease), box-shadow .28s var(--ease);\\n}\\n.card:hover{transform:translateY(-3px); box-shadow:var(--sh-md)}\\n@media (hover:none){.card:hover{transform:none; box-shadow:var(--sh-sm)}}\\n.card-pad{padding:clamp(22px,2.4vw,34px)}\\n\\n.chip{\\n  display:inline-flex; align-items:center; gap:7px;\\n  height:32px; padding:0 13px; border-radius:99px;\\n  font-size:.8rem; font-weight:560; color:var(--ink-2);\\n  background:rgba(255,255,255,.75); box-shadow:inset 0 0 0 1px var(--line);\\n}\\n.chip--blue{background:var(--blue-wash); box-shadow:inset 0 0 0 1px rgba(40,137,239,.2); color:var(--blue-deep)}\\n.chip--quiet{background:transparent; box-shadow:inset 0 0 0 1px var(--line-2); color:var(--ink-3)}\\n.tick{color:var(--blue); flex:0 0 auto}\\n\\n/* ===========================================================================\\n   4. DEVICES — pre-rendered iPhone 15 Pro mockup images\\n   ======================================================================== */\\n.device{\\n  position:relative; width:100%; max-width:352px;\\n  display:block;\\n  isolation:isolate;\\n  transform:translateZ(0);\\n}\\n.device img,\\n.device picture{\\n  display:block; width:100%; height:auto;\\n}\\n\\n/* ===========================================================================\\n   NAV — floats. No fill at rest; the glass pill materialises on scroll.\\n   ======================================================================== */\\n.nav{position:fixed; top:0; left:0; right:0; z-index:150; padding-top:16px}\\n.nav .wrap{position:relative}   /* containing block for the absolute .mnav */\\n.nav__in{\\n  display:flex; align-items:center; gap:24px;\\n  height:60px; padding-inline:8px 8px;\\n  border-radius:22px;\\n  /* At rest: completely transparent. The links sit on the page itself. */\\n  background:transparent; box-shadow:none;\\n  -webkit-backdrop-filter:none; backdrop-filter:none;\\n  transition:background .45s var(--ease), box-shadow .45s var(--ease),\\n             padding .45s var(--ease), backdrop-filter .45s var(--ease),\\n             -webkit-backdrop-filter .45s var(--ease);\\n}\\n.nav.is-stuck .nav__in{\\n  padding-inline:18px;\\n  /* Opaque enough to stay legible over content even if the blur does not\\n     composite (older WebKit, forced-colours, screenshot pipelines). */\\n  background:rgba(250,249,246,.84);\\n  -webkit-backdrop-filter:blur(22px) saturate(180%);\\n  backdrop-filter:blur(22px) saturate(180%);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.9),\\n    inset 0 0 0 1px rgba(11,11,12,.06),\\n    0 1px 2px rgba(11,11,12,.04),\\n    0 16px 36px -14px rgba(11,11,12,.20);\\n}\\n.logo{display:flex; align-items:center; gap:10px; font-size:1.06rem; font-weight:680; letter-spacing:-.03em}\\n.logo img{width:29px; height:29px; flex:0 0 auto}\\n.nav__links{display:flex; gap:2px; margin-inline:auto}\\n.nav__links a{\\n  position:relative; padding:11px 14px; border-radius:11px;\\n  font-size:.92rem; font-weight:520; color:var(--ink-2); letter-spacing:-.012em;\\n  transition:color .18s;\\n}\\n.nav__links a.is-active{color:var(--ink); font-weight:600}\\n.nav__links a::after{\\n  content:\"\"; position:absolute; left:14px; right:14px; bottom:5px; height:1px;\\n  background:var(--ink); transform:scaleX(0); transform-origin:0 50%;\\n  transition:transform .3s var(--ease);\\n}\\n.nav__links a:hover{color:var(--ink)}\\n.nav__links a:hover::after,.nav__links a.is-active::after{transform:scaleX(1)}\\n/* \"More\" — external pages that sit outside this single-page flow. */\\n.nav__more{position:relative}\\n.nav__more-btn{\\n  position:relative; padding:11px 28px 11px 14px; border-radius:11px;\\n  font-size:.92rem; font-weight:520; color:var(--ink-2); letter-spacing:-.012em;\\n  transition:color .18s; cursor:pointer; background:transparent; border:0;\\n  font-family:inherit;\\n}\\n.nav__more-btn::after{\\n  content:\"\"; position:absolute; right:12px; top:50%; width:7px; height:7px;\\n  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;\\n  transform:translateY(-62%) rotate(45deg); opacity:.55; transition:transform .2s var(--ease);\\n}\\n.nav__more.is-open .nav__more-btn::after{transform:translateY(-38%) rotate(225deg)}\\n.nav__more-btn:hover,.nav__more.is-open .nav__more-btn{color:var(--ink)}\\n.nav__drop{\\n  position:absolute; top:calc(100% + 8px); right:0; min-width:168px;\\n  padding:6px; border-radius:14px;\\n  background:rgba(250,249,246,.96);\\n  -webkit-backdrop-filter:blur(22px) saturate(180%);\\n  backdrop-filter:blur(22px) saturate(180%);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.9),\\n    inset 0 0 0 1px rgba(11,11,12,.06),\\n    0 16px 40px -10px rgba(11,11,12,.18);\\n  opacity:0; transform:translateY(-6px) scale(.98); transform-origin:top right;\\n  transition:opacity .22s var(--ease), transform .22s var(--ease);\\n  pointer-events:none; z-index:20;\\n}\\n.nav__more.is-open .nav__drop{opacity:1; transform:none; pointer-events:auto}\\n.nav__drop a{\\n  display:block; padding:10px 12px; border-radius:10px;\\n  font-size:.9rem; font-weight:520; color:var(--ink-2); letter-spacing:-.012em;\\n  transition:background .15s, color .15s;\\n}\\n.nav__drop a:hover{background:rgba(11,11,12,.04); color:var(--ink)}\\n.nav__drop a::after{display:none}\\n/* margin-left:auto keeps the CTA group hard right even when .nav__links is\\n   display:none at narrow widths and its own auto margins stop applying. */\\n.nav__cta{display:flex; align-items:center; gap:10px; margin-left:auto}\\n/* Mobile: the welcome screen in the hero already shows its own Get Started\\n   button, so the nav\\'s download badge would be a second, redundant CTA\\n   before the visitor has scrolled anywhere. It reappears once the hero is\\n   out of view — see .nav.is-past-hero below and the scroll handler in JS. */\\n@media (max-width:960px){\\n  .nav__cta .app-store-badge{display:none}\\n  .nav.is-past-hero .nav__cta .app-store-badge{display:inline-block}\\n}\\n.nav__cta .btn{height:42px; padding-inline:17px; font-size:.9rem; border-radius:12px}\\n.nav__burger{display:none; width:42px; height:42px; border-radius:12px; align-items:center; justify-content:center; box-shadow:inset 0 0 0 1px var(--line-2)}\\n.nav__burger-bars{position:relative; width:18px; height:12px; display:block}\\n.nav__burger-bars i{\\n  position:absolute; left:0; width:18px; height:2px; border-radius:2px; background:var(--ink);\\n  transition:transform .3s var(--ease), top .3s var(--ease);\\n}\\n.nav__burger-bars i:nth-child(1){top:1px}\\n.nav__burger-bars i:nth-child(2){top:9px}\\n.nav.menu-open .nav__burger-bars i:nth-child(1){top:5px; transform:rotate(45deg)}\\n.nav.menu-open .nav__burger-bars i:nth-child(2){top:5px; transform:rotate(-45deg)}\\n\\n/* Mobile menu panel — a glass sheet dropping from under the nav pill.\\n   Absolutely positioned so the closed panel takes up no layout space: when it\\n   was in normal flow, its 358px height pushed the whole page down. */\\n.mnav{\\n  display:none; flex-direction:column; gap:2px;\\n  position:absolute; top:100%; left:var(--gut); right:var(--gut);\\n  margin-top:10px; padding:12px; border-radius:22px;\\n  background:rgba(250,249,246,.92);\\n  -webkit-backdrop-filter:blur(22px) saturate(180%);\\n  backdrop-filter:blur(22px) saturate(180%);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.9),\\n    inset 0 0 0 1px rgba(11,11,12,.06),\\n    0 24px 56px -12px rgba(11,11,12,.25);\\n  opacity:0; transform:translateY(-10px) scale(.99); transform-origin:top center;\\n  transition:opacity .3s var(--ease), transform .3s var(--ease);\\n  pointer-events:none;\\n}\\n.nav.menu-open .mnav{opacity:1; transform:none; pointer-events:auto}\\n.mnav a{\\n  padding:14px 16px; border-radius:13px;\\n  font-size:1.05rem; font-weight:600; letter-spacing:-.02em; color:var(--ink);\\n}\\n.mnav a:active{background:rgba(11,11,12,.05)}\\n.mnav__talk{margin-top:8px; text-align:center; background:var(--ink); color:#fff !important}\\n@media (max-width:960px){ .mnav{display:flex} }\\n@media (prefers-reduced-motion:reduce){ .mnav{transition:none} }\\n\\n/* ===========================================================================\\n   HERO\\n   ======================================================================== */\\n.hero{position:relative; overflow:hidden; padding-top:clamp(104px,11vw,150px); padding-bottom:clamp(40px,5vw,72px)}\\n.hero__in{position:relative; z-index:2; display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.9fr); gap:40px; align-items:center}\\n.hero__copy{max-width:645px}\\n.hero__h1{margin:20px 0 24px}\\n.hero__headline s{\\n  text-decoration-thickness:.07em;\\n  text-decoration-color:currentColor;\\n}\\n.hero__actions{display:flex; flex-wrap:wrap; align-items:center; gap:12px; margin-top:32px}\\n/* The risk-reversal belongs beside the ask, not four screens later. */\\n.hero__offer{\\n  display:flex; flex-wrap:wrap; align-items:center; column-gap:14px; row-gap:6px;\\n  margin-top:18px; font-size:.875rem; color:var(--ink-2); letter-spacing:-.005em;\\n}\\n.hero__offer b{font-weight:640; color:var(--ink)}\\n.hero__offer .tick{color:var(--blue); flex:0 0 auto}\\n.hero__offer span{display:inline-flex; align-items:center; gap:7px}\\n/* Desktop-only QR — an iOS app pitched to people sitting at a workstation\\n   needs a bridge from this screen to their phone. Hidden where the App Store\\n   badge itself is tappable. */\\n.qrcard{\\n  display:flex; align-items:center; gap:13px;\\n  padding:9px 16px 9px 10px; border-radius:16px;\\n}\\n.qrcard img{\\n  width:72px; height:72px; border-radius:9px;\\n  image-rendering:pixelated;\\n}\\n.qrcard__tx{display:flex; flex-direction:column; gap:2px}\\n.qrcard__k{font-size:.8rem; font-weight:640; letter-spacing:-.015em; line-height:1.3}\\n.qrcard__v{font-size:.72rem; color:var(--ink-3); line-height:1.35; max-width:150px}\\n@media (max-width:1079px), (hover:none){ .qrcard{display:none} }\\n.stage{\\n  position:relative; height:clamp(480px,44vw,620px); perspective:1600px;\\n}\\n/* Neutral ground shadow — soft ellipse under the phone */\\n.stage::before{\\n  content:\"\"; position:absolute; left:50%; bottom:9%; z-index:1;\\n  width:min(260px,62%); height:40px; transform:translateX(-50%);\\n  background:radial-gradient(50% 50% at 50% 50%, rgba(11,11,12,.18), transparent 70%);\\n  filter:blur(14px); pointer-events:none;\\n}\\n.stage__device{\\n  position:absolute; left:50%; top:50%; z-index:2;\\n  width:clamp(248px,22vw,296px);\\n  transform:translate(-50%,-50%) rotateY(calc(-8deg + var(--hero-ry, 0deg))) rotateX(calc(2deg + var(--hero-rx, 0deg)));\\n  transform-style:preserve-3d;\\n}\\n.stage__device .device{\\n  transition:transform .45s var(--ease);\\n}\\n.stage:hover .stage__device .device{\\n  transform:scale(1.015);\\n}\\n\\n/* ---------------------------------------------------------------------------\\n   BLUEPRINT REVEAL — the one animation the real app plays on this exact\\n   screen. Reverse-engineered from the app\\'s own source (BlueprintHeroView in\\n   iOS-app/Scanbrix .../Marketing/OnboardingDesignSystem.swift): dots pop at\\n   each corner, the outline draws itself, interior walls follow, then the\\n   dimension line and its \"4.82 m\" label — same shape, same choreography,\\n   same timing as what a visitor would see opening the app itself. The static\\n   mockup screenshot already shows this at rest (post-animation), so the\\n   overlay only needs to play once on load, then it matches what\\'s under it\\n   pixel for pixel. A gradient patch (matched to the app\\'s own background)\\n   covers the baked-in art underneath while the redraw runs.\\n   Box below is the measured position of that artwork within the screenshot,\\n   as a % of the phone\\'s screen region (mockup-onboard-hero.png, 1419\\xd72796). */\\n.bp-patch{\\n  position:absolute; z-index:2; left:11%; top:11.3%; width:78%; height:33.7%;\\n  background:linear-gradient(to bottom, #F6F5F0, #F5F2EB);\\n  border-radius:10px;\\n}\\n.bp{\\n  position:absolute; z-index:3; left:15.5%; top:14.8%; width:68.9%; height:26.5%;\\n  overflow:visible;\\n}\\n.bp-dot{opacity:0; transform-box:fill-box; transform-origin:50% 50%; transform:scale(.2)}\\n/* pathLength=\"1\" is set as an attribute on each <path> in the markup below,\\n   which normalizes stroke-dasharray/-dashoffset to the 0–1 range here\\n   regardless of the path\\'s actual geometric length. */\\n.bp-outline{fill:none; stroke:var(--ink); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; stroke-dasharray:1; stroke-dashoffset:1}\\n.bp-interior{fill:none; stroke:var(--ink); stroke-opacity:.55; stroke-width:1.5; stroke-linecap:round; stroke-dasharray:1; stroke-dashoffset:1}\\n.bp-dim{fill:none; stroke:var(--blue); stroke-width:1.5; stroke-linecap:round; stroke-dasharray:1; stroke-dashoffset:1}\\n.bp-label{\\n  position:absolute; z-index:4; left:65.4%; top:16%; transform:translate(-50%,-50%) scale(.85);\\n  opacity:0; white-space:nowrap; padding:2px 7px; border-radius:99px;\\n  background:rgba(252,252,251,.94); box-shadow:inset 0 0 0 1px rgba(11,11,12,.06);\\n  font-family:var(--mono); font-size:.68rem; font-weight:600; color:var(--blue-deep);\\n}\\n@keyframes bpDot{to{opacity:1; transform:scale(1)}}\\n@keyframes bpDraw{to{stroke-dashoffset:0}}\\n@keyframes bpLabel{to{opacity:1; transform:translate(-50%,-50%) scale(1)}}\\n.hero.is-ready .bp-dot{animation:bpDot .45s cubic-bezier(.34,1.4,.64,1) forwards}\\n.hero.is-ready .bp-outline{animation:bpDraw 1.5s ease-in-out .55s forwards}\\n.hero.is-ready .bp-interior{animation:bpDraw .7s ease-in-out 1.95s forwards}\\n.hero.is-ready .bp-dim{animation:bpDraw .45s ease-out 2.6s forwards}\\n.hero.is-ready .bp-label{animation:bpLabel .4s cubic-bezier(.34,1.4,.64,1) 2.95s forwards}\\n/* nth-of-type, not nth-child: three <path> siblings precede the circles in\\n   the markup, which would otherwise throw off a plain child count. These\\n   need the same \".hero.is-ready\" prefix as the base rule above — otherwise\\n   the base rule\\'s higher specificity (it matches three classes vs. these\\n   rules\\' one class + pseudo-class) always wins the cascade for\\n   animation-delay, and every dot pops on the same 0s beat. */\\n.hero.is-ready .bp-dot:nth-of-type(1){animation-delay:0s}\\n.hero.is-ready .bp-dot:nth-of-type(2){animation-delay:.06s}\\n.hero.is-ready .bp-dot:nth-of-type(3){animation-delay:.12s}\\n.hero.is-ready .bp-dot:nth-of-type(4){animation-delay:.18s}\\n.hero.is-ready .bp-dot:nth-of-type(5){animation-delay:.24s}\\n.hero.is-ready .bp-dot:nth-of-type(6){animation-delay:.3s}\\n.hero.is-ready .bp-dot:nth-of-type(7){animation-delay:.36s}\\n.hero.is-ready .bp-dot:nth-of-type(8){animation-delay:.42s}\\n.hero.is-ready .bp-dot:nth-of-type(9){animation-delay:.48s}\\n.hero.is-ready .bp-dot:nth-of-type(10){animation-delay:.54s}\\n@media (prefers-reduced-motion:reduce){\\n  .bp-dot{opacity:1; transform:scale(1); animation:none}\\n  .bp-outline,.bp-interior,.bp-dim{stroke-dashoffset:0; animation:none}\\n  .bp-label{opacity:1; transform:translate(-50%,-50%) scale(1); animation:none}\\n}\\n\\n/* Floating callouts — outboard of the device so the screen stays readable */\\n.callout{\\n  position:absolute; z-index:8; border-radius:17px; transform-style:flat;\\n  box-shadow:0 1px 2px rgba(11,11,12,.08), 0 10px 24px rgba(11,11,12,.13), 0 24px 48px rgba(11,11,12,.09);\\n}\\n.callout--a{left:-58%; top:8%}\\n.callout--b{right:-52%; top:30%}\\n.callout--c{left:-54%; bottom:21%}\\n.callout--d{right:-50%; bottom:-6%}\\n.callout__in{display:flex; align-items:center; gap:11px; padding:10px 15px; border-radius:inherit; white-space:nowrap}\\n.callout__tx{display:flex; flex-direction:column; gap:1px; min-width:0}\\n.callout__k{display:block; font-size:.8rem; font-weight:640; letter-spacing:-.015em; line-height:1.25}\\n.callout__v{display:block; font-size:.715rem; color:var(--ink-3); line-height:1.25}\\n.callout__ic{width:32px; height:32px; border-radius:11px; flex:0 0 auto; display:grid; place-items:center}\\n.callout__ic--b{background:var(--blue-wash); color:var(--blue)}\\n.callout__ic--d{background:var(--ink); color:#fff}\\n.callout img.fmt{width:21px; height:21px; object-fit:contain; transition:opacity .4s var(--ease), transform .4s var(--ease)}\\n.callout__tx--cycle{transition:opacity .4s var(--ease), transform .4s var(--ease)}\\n.callout__in.is-cycling .fmt,\\n.callout__in.is-cycling .callout__tx--cycle{opacity:0; transform:translateY(5px)}\\n\\n/* Overlap is deliberately shallow: the initials are centred, so a deeper\\n   overlap (plus the next avatar\\'s 2px ring) clips the letter beside it. */\\n.avatars{display:flex; align-items:center}\\n.avatars i{\\n  width:34px; height:34px; flex:0 0 auto; border-radius:99px; margin-left:-8px;\\n  box-shadow:0 0 0 2px var(--white); display:grid; place-items:center;\\n  font-size:.66rem; font-weight:680; color:#fff; letter-spacing:-.01em; font-style:normal;\\n}\\n.avatars i:first-child{margin-left:0}\\n\\n/* ===========================================================================\\n   MARQUEE — looping credibility strip under the hero\\n   ======================================================================== */\\n.marquee{\\n  overflow:hidden; position:relative; padding-block:30px;\\n  border-top:1px solid var(--bone-well); border-bottom:1px solid var(--bone-well);\\n  mask-image:linear-gradient(to right,transparent,#000 10%,#000 90%,transparent);\\n  -webkit-mask-image:linear-gradient(to right,transparent,#000 10%,#000 90%,transparent);\\n}\\n.marquee__track{display:flex; width:max-content; animation:marqueeLoop 32s linear infinite; will-change:transform}\\n.marquee:hover .marquee__track{animation-play-state:paused}\\n@keyframes marqueeLoop{to{transform:translateX(-50%)}}\\n.marquee__grp{display:flex; align-items:center; gap:44px; padding-right:44px}\\n.marquee__i{display:flex; align-items:center; gap:10px; font-size:.98rem; font-weight:600; letter-spacing:-.018em; white-space:nowrap}\\n.marquee__i img{width:26px; height:26px; object-fit:contain}\\n.marquee__i code{font-family:var(--mono); font-size:.8rem; font-weight:500; color:var(--ink-3)}\\n.marquee__i--txt{color:var(--ink-3); font-weight:560}\\n.marquee__dot{width:4px; height:4px; border-radius:99px; background:var(--ink-4); flex:0 0 auto}\\n\\n/* ===========================================================================\\n   STATEMENT — scroll-driven ink fill, the editorial pause between sections\\n   ======================================================================== */\\n.statement{padding-block:clamp(64px,8vw,120px); position:relative}\\n.statement p{\\n  font-family:var(--display);\\n  font-size:clamp(1.9rem,5.2vw,4.2rem); line-height:1.08; font-weight:700;\\n  letter-spacing:-.024em; text-transform:uppercase; max-width:1080px;\\n}\\n.statement .sw{color:var(--ink-4); transition:color .3s var(--ease)}\\n.statement .sw.lit{color:var(--ink)}\\n.statement .sw--accent.lit{color:var(--blue)}\\n\\n/* ===========================================================================\\n   PROOF\\n   ======================================================================== */\\n.proof{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--bone-well)}\\n.proof__i{background:var(--bone); padding:38px 28px 36px}\\n.proof__was{font-size:.78rem; color:var(--ink-4); letter-spacing:-.01em; min-height:1.2em}\\n.proof__was s{text-decoration-thickness:1px}\\n.proof__n{font-family:var(--display); font-size:clamp(2.3rem,3.5vw,3.3rem); font-weight:700; letter-spacing:-.032em; line-height:1.02; margin-top:5px}\\n.proof__n em{font-style:normal; font-size:.5em; font-weight:620; letter-spacing:-.02em; color:var(--ink-2); margin-left:.22em}\\n.proof__l{font-size:.85rem; color:var(--ink-3); margin-top:8px; letter-spacing:-.01em}\\n\\n/* Engineering title block under the proof figures. The accuracy answer is\\n   the make-or-break question for this audience — it does not belong folded\\n   inside the FAQ. Every value here restates a claim already on the page. */\\n.spec{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--bone-well); margin-top:1px}\\n.spec__i{background:var(--bone); padding:22px 28px 24px; display:flex; flex-direction:column; gap:7px}\\n.spec__k{\\n  display:flex; align-items:center; gap:8px;\\n  font-family:var(--mono); font-size:.63rem; font-weight:600;\\n  letter-spacing:.12em; text-transform:uppercase; color:var(--ink-3);\\n}\\n.spec__k::before{content:\"\"; width:5px; height:5px; border-radius:99px; background:var(--blue); flex:0 0 auto}\\n.spec__v{font-size:.96rem; font-weight:640; letter-spacing:-.016em; color:var(--ink)}\\n.spec__s{font-size:.8rem; line-height:1.45; color:var(--ink-3)}\\n\\n/* ===========================================================================\\n   COMPARE\\n   ======================================================================== */\\n.cmp{display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:40px; position:relative; z-index:2}\\n.cmp__col{\\n  border-radius:var(--r-xl); padding:clamp(24px,2.6vw,36px);\\n  transition:transform .28s var(--ease), box-shadow .28s var(--ease);\\n}\\n.cmp__col--old{background:transparent; box-shadow:inset 0 0 0 1px var(--bone-well)}\\n.cmp__col--new{background:var(--white); box-shadow:var(--sh-lg)}\\n.cmp__col--new:hover{transform:translateY(-3px); box-shadow:var(--sh-lg), 0 10px 28px rgba(11,11,12,.07)}\\n.cmp__head{display:flex; align-items:center; justify-content:space-between; gap:16px; margin-bottom:26px}\\n.cmp__title{font-size:1.05rem; font-weight:660; letter-spacing:-.02em}\\n.cmp__steps{display:grid; gap:2px}\\n.cmp__step{display:grid; grid-template-columns:1fr auto; gap:14px; align-items:center; padding:13px 0; border-bottom:1px solid var(--line)}\\n.cmp__step:last-child{border-bottom:0}\\n.cmp__step span{font-size:.94rem; color:var(--ink-2); letter-spacing:-.012em}\\n.cmp__step b{font-size:.86rem; font-weight:620; color:var(--ink); font-variant-numeric:tabular-nums}\\n.cmp__step--dim span,.cmp__step--dim b{color:var(--ink-3)}\\n.cmp__bar{height:6px; border-radius:99px; background:rgba(11,11,12,.07); overflow:hidden; margin-top:26px}\\n.cmp__bar i{display:block; height:100%; border-radius:99px; width:0; transition:width 1.2s var(--ease) .15s}\\n.cmp__bar--old i{background:var(--ink-4)}\\n.cmp__bar--new i{background:var(--blue)}\\n.is-in .cmp__bar--old i{width:100%}\\n.is-in .cmp__bar--new i{width:14%}\\n.cmp__total{font-size:.82rem; color:var(--ink-3); margin-top:14px; letter-spacing:-.01em}\\n.cmp__total b{color:var(--ink); font-weight:640}\\n\\n/* ===========================================================================\\n   STEPS\\n   ======================================================================== */\\n.steps{display:grid; grid-template-columns:repeat(3,1fr); gap:20px; margin-top:40px; position:relative; z-index:2}\\n.step{display:flex; flex-direction:column; overflow:hidden; padding:0}\\n.step__art{\\n  position:relative; min-height:320px; padding:32px 20px 56px; overflow:hidden;\\n  background:var(--bone); box-shadow:inset 0 -1px 0 var(--line);\\n  display:flex; align-items:flex-start; justify-content:center;\\n}\\n.step__art::after{\\n  content:\"\"; position:absolute; bottom:44px; left:50%; z-index:0;\\n  width:min(140px,52%); height:18px; transform:translateX(-50%);\\n  background:radial-gradient(50% 50% at 50% 50%, rgba(11,11,12,.12), transparent 72%);\\n  filter:blur(8px); pointer-events:none;\\n}\\n.step__art .device{max-width:188px; margin-bottom:-52px; margin-top:0}\\n/* Oversized ghost numeral — editorial texture behind the device */\\n.step__ghost{\\n  position:absolute; top:6px; left:16px; z-index:0;\\n  font-family:var(--mono); font-weight:700; font-size:6rem; line-height:1;\\n  letter-spacing:-.06em; color:rgba(11,11,12,.06); pointer-events:none;\\n  font-variant-numeric:tabular-nums;\\n}\\n.step__art .device{position:relative; z-index:1}\\n.step__body{padding:26px 26px 30px}\\n.step__n{\\n  display:inline-flex; align-items:center; gap:8px;\\n  font-family:var(--mono); font-size:.72rem; font-weight:600; letter-spacing:.08em;\\n  color:var(--ink-3); margin-bottom:14px;\\n}\\n.step__n::after{content:\"\"; width:22px; height:1px; background:var(--bone-well)}\\n.step__n--hide{display:none}\\n.step__t{font-size:1.12rem; font-weight:640; letter-spacing:-.022em; margin-bottom:8px}\\n\\n/* Flip-clock word in section headings */\\n.flip-txt{\\n  display:inline-block; position:relative;\\n  min-width:6.4em; height:1.06em; overflow:hidden;\\n  vertical-align:text-bottom; perspective:480px;\\n  color:var(--blue-deep);\\n}\\n.flip-txt__word{\\n  display:inline-block; transform-origin:50% 100%;\\n  backface-visibility:hidden; white-space:nowrap;\\n}\\n.flip-txt.is-out .flip-txt__word{animation:flipOut .42s cubic-bezier(.4,0,.2,1) forwards}\\n.flip-txt.is-in .flip-txt__word{animation:flipIn .42s cubic-bezier(.4,0,.2,1) forwards}\\n@keyframes flipOut{\\n  0%{transform:rotateX(0deg); opacity:1}\\n  100%{transform:rotateX(-88deg); opacity:0}\\n}\\n@keyframes flipIn{\\n  0%{transform:rotateX(88deg); opacity:0}\\n  100%{transform:rotateX(0deg); opacity:1}\\n}\\n\\n/* ===========================================================================\\n   ON-SITE — real-world capture photo split\\n   ======================================================================== */\\n.onsite{display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(28px,4vw,56px); align-items:center; margin-top:40px; position:relative; z-index:2}\\n.onsite__photo{\\n  position:relative; border-radius:var(--r-2xl); overflow:hidden;\\n  box-shadow:var(--sh-lg); aspect-ratio:4/3; background:var(--bone-deep);\\n}\\n.onsite__photo img{width:100%; height:100%; object-fit:cover; object-position:center 42%}\\n.onsite__cap{\\n  position:absolute; left:18px; bottom:18px; right:18px;\\n  padding:14px 16px; border-radius:14px;\\n  background:rgba(250,249,246,.88); backdrop-filter:blur(12px);\\n  box-shadow:inset 0 1px 0 rgba(255,255,255,.9), 0 8px 24px rgba(11,11,12,.12);\\n  font-size:.84rem; color:var(--ink-2); letter-spacing:-.01em;\\n}\\n.onsite__cap b{color:var(--ink); font-weight:640}\\n\\n/* ===========================================================================\\n   DESKTOP SHOWCASE — Revit / SketchUp / AutoCAD tabbed viewer\\n   ======================================================================== */\\n.desk{margin-top:40px; position:relative; z-index:2}\\n.desk__tabs-wrap{\\n  margin-bottom:22px;\\n}\\n.desk__tablist{\\n  display:flex; flex-wrap:wrap; align-items:center; gap:8px 10px;\\n}\\n.desk__pick-hint{\\n  display:inline-flex; align-items:center; gap:6px;\\n  margin:0; padding:0 0 0 4px;\\n  font-size:.78rem; color:var(--ink-3); letter-spacing:-.01em;\\n  flex:1 1 100%; max-width:100%;\\n}\\n.desk__pick-hint svg{flex:0 0 auto; color:var(--ink-3); opacity:.7}\\n@media (min-width:641px){\\n  .desk__pick-hint{flex:0 1 auto; margin-left:6px}\\n}\\n.desk__tabs{display:flex; flex-wrap:wrap; gap:8px}\\n.desk__tab{\\n  display:inline-flex; align-items:center; gap:9px;\\n  min-height:44px; height:44px; padding:0 16px; border-radius:12px;\\n  font-size:.9rem; font-weight:560; color:var(--ink-2); letter-spacing:-.012em;\\n  background:var(--white); box-shadow:inset 0 0 0 1px var(--line);\\n  transition:background .2s, color .2s, box-shadow .2s, transform .2s var(--ease);\\n}\\n.desk__tab img{width:20px; height:20px; object-fit:contain}\\n.desk__tab:hover{color:var(--ink); transform:translateY(-1px)}\\n.desk__tab.is-active{\\n  background:var(--ink); color:#fff; box-shadow:var(--sh-md);\\n}\\n.desk__tab.is-active code{color:rgba(255,255,255,.65)}\\n.desk__tab code{font-family:var(--mono); font-size:.76rem; font-weight:500; color:var(--ink-3)}\\n.desk__frame{\\n  border-radius:var(--r-xl); overflow:hidden;\\n  box-shadow:var(--sh-lg), 0 0 0 1px rgba(11,11,12,.06);\\n  background:var(--dark);\\n}\\n.desk__bar{\\n  display:flex; align-items:center; gap:8px; height:38px; padding:0 14px;\\n  background:linear-gradient(180deg,#1E2024,#14161A);\\n  border-bottom:1px solid rgba(255,255,255,.06);\\n}\\n.desk__dot{width:10px; height:10px; border-radius:99px; flex:0 0 auto}\\n.desk__dot--r{background:#FF5F57}\\n.desk__dot--y{background:#FEBC2E}\\n.desk__dot--g{background:#28C840}\\n.desk__title{\\n  margin-left:10px; font-size:.72rem; font-weight:500; color:rgba(255,255,255,.42);\\n  letter-spacing:-.01em; font-family:var(--mono);\\n}\\n.desk__viewport{\\n  display:grid; line-height:0;\\n  position:relative;\\n  background:#14161A;\\n}\\n.desk__panel{\\n  grid-area:1/1; width:100%;\\n  opacity:0; transition:opacity .45s var(--ease);\\n  pointer-events:none;\\n}\\n.desk__viewport .desk__panel picture{display:block}\\n.desk__viewport .desk__panel img{height:auto; display:block; width:100%}\\n.desk__panel.is-active{opacity:1; z-index:1; pointer-events:auto}\\n.desk__meta{\\n  display:grid; grid-template-columns:repeat(3,1fr); gap:1px;\\n  background:var(--bone-well); margin-top:20px; border-radius:var(--r-lg); overflow:hidden;\\n}\\n.desk__meta-i{background:var(--white); padding:18px 20px}\\n.desk__meta-i b{display:block; font-size:.92rem; font-weight:640; letter-spacing:-.014em; margin-bottom:4px}\\n.desk__meta-i span{font-size:.8rem; color:var(--ink-3); line-height:1.45}\\n.desk__panel[hidden]{display:none!important}\\n\\n/* Deliverable downloads */\\n.desk__actions{\\n  display:flex; flex-wrap:wrap; align-items:center; gap:12px;\\n  margin-top:18px;\\n}\\n.desk__dl{\\n  display:inline-flex; align-items:center; gap:9px;\\n  min-height:44px; padding:0 18px; border-radius:12px;\\n  font-size:.9rem; font-weight:600; letter-spacing:-.012em;\\n  background:var(--white); box-shadow:inset 0 0 0 1px var(--line-2);\\n  transition:transform .2s var(--ease), box-shadow .2s var(--ease);\\n}\\n.desk__dl:hover{transform:translateY(-1px); box-shadow:var(--sh-sm)}\\n.desk__dl svg{color:var(--blue)}\\n\\n/* ---------------------------------------------------------------------------\\n   SAMPLE PACK — the lead magnet.\\n   Deliberately a soft gate: the direct downloads above stay one click away.\\n   This is the smaller yes for someone not ready to install an app or book a\\n   call, and the only place on the page that captures intent.\\n   ------------------------------------------------------------------------ */\\n.magnet{\\n  margin-top:20px; padding:clamp(22px,2.4vw,30px);\\n  border-radius:var(--r-xl); background:var(--white);\\n  box-shadow:var(--sh-sm), inset 0 0 0 1px var(--line);\\n  position:relative; overflow:hidden;\\n}\\n.magnet__in{position:relative; display:grid; grid-template-columns:1fr auto; gap:26px; align-items:center}\\n.magnet__k{font-size:1.02rem; font-weight:660; letter-spacing:-.02em}\\n.magnet__s{font-size:.85rem; color:var(--ink-3); line-height:1.5; margin-top:5px; max-width:44ch}\\n.magnet__form{display:flex; gap:9px; align-items:center}\\n.magnet__field{\\n  height:50px; width:clamp(200px,22vw,268px); padding:0 16px;\\n  border-radius:13px; border:0; background:var(--bone);\\n  box-shadow:inset 0 0 0 1px var(--line-2);\\n  font-family:var(--sans); font-size:.94rem; color:var(--ink);\\n  transition:box-shadow .2s var(--ease), background .2s;\\n}\\n.magnet__field::placeholder{color:var(--ink-4); opacity:.85}\\n.magnet__field:focus{outline:0; background:var(--white); box-shadow:inset 0 0 0 1.5px var(--blue)}\\n.magnet__go{\\n  height:50px; padding:0 20px; border-radius:13px; white-space:nowrap;\\n  background:var(--ink); color:#fff; font-size:.92rem; font-weight:620; letter-spacing:-.012em;\\n  display:inline-flex; align-items:center; gap:9px;\\n  transition:transform .2s var(--ease), box-shadow .2s var(--ease), background .2s;\\n}\\n.magnet__go:hover{transform:translateY(-2px); box-shadow:0 8px 22px rgba(11,11,12,.2)}\\n.magnet__go:active{transform:translateY(0)}\\n.magnet__note{font-size:.74rem; color:var(--ink-4); margin-top:9px}\\n/* Result line — assertive so screen readers hear the outcome */\\n.magnet__msg{font-size:.85rem; font-weight:560; margin-top:10px; display:none}\\n.magnet__msg.is-on{display:block}\\n.magnet__msg--ok{color:#1D7A45}\\n.magnet__msg--err{color:#B4291F}\\n.magnet.is-done .magnet__form,.magnet.is-done .magnet__note{display:none}\\n\\n@media (max-width:860px){\\n  .magnet__in{grid-template-columns:1fr; gap:18px}\\n  .magnet__form{flex-wrap:wrap}\\n  .magnet__field{width:100%; flex:1 1 200px}\\n  .magnet__go{flex:1 1 auto; justify-content:center}\\n}\\n\\n/* Pricing calculator */\\n.calc{\\n  margin-top:20px; padding:clamp(24px,2.8vw,34px); border-radius:var(--r-xl);\\n  background:var(--white); box-shadow:var(--sh-sm);\\n}\\n.calc--standalone{margin-top:24px}\\n.calc__head{margin-bottom:18px}\\n.calc__head .h3{margin-bottom:6px}\\n.calc__row{display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap}\\n.calc__val{font-family:var(--display); font-size:clamp(1.6rem,2.4vw,2rem); font-weight:700; letter-spacing:-.022em}\\n.calc__val small{font-size:.55em; font-weight:560; color:var(--ink-3); margin-left:.25em}\\n.calc input[type=range]{\\n  width:100%; margin-top:10px; accent-color:var(--blue);\\n  min-height:44px; cursor:pointer;\\n}\\n.calc__slide-hint{\\n  display:inline-flex; align-items:center; gap:8px; margin-top:14px;\\n  padding:8px 12px; border-radius:10px;\\n  font-size:.8rem; font-weight:560; color:var(--blue-deep);\\n  background:var(--blue-wash);\\n  box-shadow:inset 0 0 0 1px rgba(40,137,239,.14);\\n  transition:opacity .3s var(--ease), transform .3s var(--ease);\\n}\\n.calc__slide-hint.is-dismissed{opacity:0; transform:translateY(-4px); pointer-events:none}\\n.calc__slide-hint svg{flex:0 0 auto; color:var(--blue)}\\n.calc__hint{font-size:.82rem; color:var(--ink-3); margin-top:10px}\\n.calc__min{font-size:.82rem; color:var(--ink-2); margin-top:6px; font-weight:560}\\n\\n/* Visually hidden (marquee label, etc.) */\\n.sr-only{\\n  position:absolute; width:1px; height:1px; padding:0; margin:-1px;\\n  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;\\n}\\n\\n/* SCOPE — itemised deliverable spec */\\n.scope{\\n  margin-top:28px; position:relative; z-index:2;\\n  padding:clamp(22px,2.8vw,34px);\\n  border-radius:var(--r-xl);\\n  background:linear-gradient(165deg, var(--white) 0%, #faf8f5 100%);\\n  box-shadow:var(--sh-sm), inset 0 1px 0 rgba(255,255,255,.9);\\n  border:1px solid rgba(11,11,12,.06);\\n  overflow:hidden;\\n}\\n.scope__head{margin-bottom:20px; position:relative}\\n.scope__badge{\\n  display:inline-flex; align-items:center; gap:6px;\\n  margin-bottom:10px; padding:5px 11px; border-radius:99px;\\n  font-size:.68rem; font-weight:640; letter-spacing:.06em; text-transform:uppercase;\\n  color:var(--blue-deep); background:rgba(255,255,255,.72);\\n  box-shadow:inset 0 0 0 1px rgba(40,137,239,.22);\\n}\\n.scope__badge::before{\\n  content:\"\"; width:6px; height:6px; border-radius:99px; background:var(--blue);\\n  animation:scopePulse 2.4s ease-in-out infinite;\\n}\\n@keyframes scopePulse{\\n  0%,100%{opacity:1; transform:scale(1)}\\n  50%{opacity:.55; transform:scale(.82)}\\n}\\n.scope__head .h3{margin-bottom:6px}\\n.scope__lead{max-width:48ch; color:var(--ink-3)}\\n.scope__track-wrap{position:relative}\\n.scope__swipe-hint{\\n  display:none; margin:0 0 10px;\\n  font-size:.72rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase;\\n  color:var(--ink-3);\\n}\\n.scope__cards{\\n  display:grid; grid-template-columns:repeat(4,1fr); gap:12px;\\n}\\n.scope__card{\\n  position:relative; padding:16px 16px 14px; border-radius:16px;\\n  background:rgba(255,255,255,.88);\\n  box-shadow:inset 0 0 0 1px rgba(11,11,12,.06), 0 8px 24px rgba(11,11,12,.04);\\n  transition:transform .35s var(--ease), box-shadow .35s var(--ease);\\n}\\n.scope__card::before{\\n  content:\"\"; position:absolute; top:0; left:16px; right:16px; height:3px;\\n  border-radius:0 0 4px 4px; opacity:.9;\\n}\\n.scope__card--shell::before{background:linear-gradient(90deg, var(--blue-deep), var(--blue))}\\n.scope__card--openings::before{background:linear-gradient(90deg, var(--blue), #5aa8f5)}\\n.scope__card--fixed::before{background:linear-gradient(90deg, #5aa8f5, #7dbbf7)}\\n.scope__card--draw::before{background:linear-gradient(90deg, var(--blue-deep), #3d8fd9)}\\n.scope__card:hover{\\n  transform:translateY(-3px);\\n  box-shadow:inset 0 0 0 1px rgba(11,11,12,.06), 0 14px 32px rgba(11,11,12,.08);\\n}\\n.scope__card-top{\\n  display:flex; align-items:flex-start; gap:11px; margin-bottom:12px;\\n}\\n.scope__icon{\\n  display:grid; place-items:center; flex:0 0 auto;\\n  width:38px; height:38px; border-radius:11px;\\n  background:var(--blue-wash); color:var(--blue-deep);\\n  box-shadow:inset 0 1px 0 rgba(255,255,255,.9);\\n}\\n.scope__card--openings .scope__icon{background:rgba(40,137,239,.12); color:var(--blue-deep)}\\n.scope__card--fixed .scope__icon{background:rgba(40,137,239,.18); color:var(--blue)}\\n.scope__card--draw .scope__icon{background:var(--blue-wash); color:var(--blue-deep)}\\n.scope__icon svg{width:20px; height:20px}\\n.scope__card h4{\\n  font-size:.92rem; font-weight:640; letter-spacing:-.018em; line-height:1.25;\\n  margin:0 0 2px;\\n}\\n.scope__count{\\n  font-size:.7rem; font-weight:600; letter-spacing:.03em; text-transform:uppercase;\\n  color:var(--ink-3);\\n}\\n.scope__card ul{display:grid; gap:7px}\\n.scope__card li{\\n  display:grid; grid-template-columns:auto 1fr; gap:8px;\\n  font-size:.82rem; line-height:1.38; color:var(--ink-2);\\n}\\n.scope__card li svg{margin-top:3px}\\n.scope__note{\\n  margin-top:18px; padding:14px 16px; border-radius:12px;\\n  background:rgba(255,255,255,.72);\\n  box-shadow:inset 0 0 0 1px var(--bone-well);\\n  font-size:.84rem; color:var(--ink-3); line-height:1.45;\\n}\\n.scope__note a{color:var(--blue-deep); font-weight:600; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:2px}\\n@media (max-width:960px){\\n  .scope__cards{grid-template-columns:repeat(2,1fr)}\\n}\\n@media (max-width:640px){\\n  .desk__tablist{gap:16px}\\n  .scope{padding:18px 0 20px; background:linear-gradient(180deg, var(--white) 0%, #faf8f5 100%)}\\n  .scope__head,.scope__note{margin-inline:18px}\\n  .scope__swipe-hint{display:block; margin-inline:18px}\\n  .scope__cards{\\n    display:flex; overflow-x:auto; overflow-y:hidden; scroll-snap-type:x mandatory;\\n    gap:12px; padding:2px 18px 6px;\\n    -webkit-overflow-scrolling:touch;\\n    scrollbar-width:none;\\n    /* Horizontal swipe only — without this a touch drag with any vertical\\n       component gets captured by the carousel instead of the page scroll. */\\n    touch-action:pan-x;\\n  }\\n  .scope__cards::-webkit-scrollbar{display:none}\\n  .scope__card{\\n    flex:0 0 min(76vw, 290px); scroll-snap-align:start;\\n  }\\n  .scope__card:hover{transform:none}\\n}\\n\\n/* ===========================================================================\\n   BENTO\\n   ---------------------------------------------------------------------------\\n   The tall order card and the notes card share the left column; team and\\n   freebie stack on the right. Phones are sized to fit inside each art tray.\\n   ======================================================================== */\\n.bento{display:grid; grid-template-columns:repeat(6,1fr); gap:16px; margin-top:40px; position:relative; z-index:2}\\n.bento > *{border-radius:var(--r-xl); overflow:hidden; position:relative}\\n.b-tall{grid-column:span 4}\\n.b-side{grid-column:span 2}\\n.b-notes{grid-column:span 4}\\n.b-half{grid-column:span 3}\\n.b-t{font-size:1.06rem; font-weight:640; letter-spacing:-.022em; margin-bottom:7px}\\n/* Cards in the grid are stretched to their row height. Letting the art tray\\n   take the slack keeps stray whitespace out of the text block underneath. */\\n.bento .card{display:flex; flex-direction:column; min-width:0}\\n.bento .card > *{min-width:0}\\n.bento .card > .card-pad{flex:0 0 auto}\\n\\n/* Phones hang out of the bottom of each tray and are clipped there. The\\n   negative margins are tuned against the 393:852 device ratio so every phone\\n   keeps roughly 34px of clear space above its top edge. */\\n.b-art{\\n  position:relative; overflow:hidden;\\n  box-shadow:inset 0 -1px 0 var(--line); background:var(--bone);\\n}\\n.b-art:not(.b-art--duo){flex:1 1 auto}\\n.b-art--tall{min-height:348px; display:grid; place-items:end center}\\n.b-art--tall .device{max-width:190px; margin-bottom:-98px}\\n.bento .b-art.b-art--duo{\\n  flex:0 0 326px; height:326px; min-height:0; max-height:326px;\\n  display:flex; align-items:flex-end; justify-content:center; gap:20px; padding-inline:24px;\\n}\\n.bento .b-art.b-art--duo .device{max-width:172px; margin-bottom:-76px}\\n.bento .b-art.b-art--duo .device:nth-child(2){margin-bottom:-90px}\\n.b-art--side{min-height:288px; display:grid; place-items:end center}\\n.b-art--side .device{max-width:156px; margin-bottom:-82px}\\n/* Notes tray: a short clip window onto the *bottom* of the phone. The sibling\\n   cards hang their device downwards so the tray frames the top of the screen —\\n   the opposite of what\\'s needed here, and the reason this phone has to be much\\n   wider than the others: the notes band is only the bottom ~21% of the screen,\\n   so a 170px phone rendered its type at roughly 0.4x life size. At ~340px the\\n   UI sits close to actual size and stays legible. */\\n/* Two-class selector on purpose: `.b-art:not(.b-art--duo){flex:1 1 auto}` above\\n   outranks a lone `.b-art--notes`, so the tray kept growing to fill the row and\\n   pulled more empty screen into view. */\\n.bento .b-art--notes{\\n  flex:0 0 auto; height:clamp(186px,23vw,210px);\\n  display:flex; align-items:flex-end; justify-content:center;\\n  overflow:hidden;\\n  /* The phone rests clear of the tray floor rather than bleeding past it like\\n     the sibling cards — its bottom bezel is in shot, so butting it against the\\n     card body read as a collision. */\\n  padding-bottom:18px;\\n  background:var(--bone-deep);\\n  box-shadow:inset 0 -1px 0 var(--line);\\n}\\n.bento .b-art--notes .device{\\n  max-width:clamp(288px,46%,344px); margin:0; flex-shrink:0;\\n}\\n.b-notes__body{\\n  flex:1; min-width:0;\\n  display:flex; flex-direction:column; justify-content:center;\\n  padding:clamp(20px,2.2vw,26px);\\n}\\n/* A chip is a pill, never a full-width bar. In a column flex container the\\n   default align-items:stretch blows it out to the card width. */\\n.b-notes__body > .chip{align-self:flex-start}\\n\\n.flow{display:grid; gap:10px}\\n.flow__s{\\n  display:grid; grid-template-columns:auto 1fr; gap:12px; align-items:start;\\n  padding:12px 14px; border-radius:14px; background:var(--bone);\\n  font-size:.88rem; color:var(--ink-2); line-height:1.45;\\n}\\n.flow__s b{color:var(--ink); font-weight:620}\\n.flow__n{\\n  width:24px; height:24px; border-radius:8px; flex:0 0 auto;\\n  display:grid; place-items:center;\\n  font-family:var(--mono); font-size:.7rem; font-weight:700;\\n  background:var(--blue-wash); color:var(--blue-deep);\\n}\\n\\n/* The offer card — the one place blue fills a whole surface.\\n   Content is centred as a single group: pinning the icon top and the copy\\n   bottom left a void in the middle once the row got shorter. */\\n.freebie{background:var(--blue); color:#fff; display:flex; flex-direction:column; justify-content:center; gap:22px}\\n.freebie .b-t{color:#fff}\\n.freebie p{color:rgba(255,255,255,.78); font-size:.95rem; line-height:1.5}\\n.freebie__n{font-family:var(--display); font-size:clamp(2.3rem,3.4vw,3rem); font-weight:700; letter-spacing:-.028em; line-height:1}\\n.freebie__ic{width:46px; height:46px; border-radius:14px; background:rgba(255,255,255,.16); display:grid; place-items:center; flex:0 0 auto}\\n\\n/* ===========================================================================\\n   ROLES\\n   ======================================================================== */\\n.roles{display:grid; grid-template-columns:repeat(4,1fr); gap:20px; margin-top:40px; position:relative; z-index:2}\\n.role{\\n  padding:clamp(24px,2.4vw,32px); display:flex; flex-direction:column; gap:15px;\\n  transition:transform .28s var(--ease), box-shadow .28s var(--ease);\\n}\\n.role:hover{transform:translateY(-4px); box-shadow:var(--sh-md)}\\n@media (hover:none){.role:hover{transform:none; box-shadow:var(--sh-sm)}}\\n.role__ic{width:54px; height:54px; border-radius:16px; display:grid; place-items:center; background:var(--blue-wash); color:var(--blue)}\\n.role__t{font-size:1.1rem; font-weight:640; letter-spacing:-.022em}\\n.role ul{display:grid; gap:10px; margin-top:2px}\\n.role li{display:grid; grid-template-columns:auto 1fr; gap:11px; font-size:.925rem; color:var(--ink-2); line-height:1.45}\\n.role li svg{margin-top:4px}\\n\\n/* ===========================================================================\\n   TESTIMONIALS\\n   ======================================================================== */\\n.quotes{display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:40px; position:relative; z-index:2}\\n.quote{padding:clamp(26px,2.5vw,32px); display:flex; flex-direction:column; gap:20px}\\n.quote__m{font-size:2.4rem; line-height:.7; color:var(--blue-deep); height:.6em}\\n.quote__t{font-size:1.04rem; line-height:1.5; letter-spacing:-.015em; color:var(--ink)}\\n.quote__b{display:flex; align-items:center; gap:12px; margin-top:auto}\\n.quote__av{width:40px; height:40px; border-radius:99px; display:grid; place-items:center; font-size:.8rem; font-weight:680; color:#fff; flex:0 0 auto}\\n.quote__n{font-size:.9rem; font-weight:640; letter-spacing:-.014em}\\n.quote__r{font-size:.79rem; color:var(--ink-3)}\\n/* The quote with the numbers in it is the section\\'s argument — set it like\\n   an editorial pull-quote, not a card among cards. */\\n.quote--lead{\\n  grid-column:1/-1; background:transparent; box-shadow:none;\\n  padding:clamp(6px,1vw,14px) 0 18px; gap:26px;\\n}\\n.quote--lead .quote__m{font-size:3.2rem; color:var(--blue)}\\n.quote--lead .quote__t{\\n  font-family:var(--display); font-weight:500;\\n  font-size:clamp(1.4rem,2.5vw,2.05rem); line-height:1.24;\\n  letter-spacing:-.02em; max-width:1000px; color:var(--ink);\\n}\\n.quote--lead .quote__r{font-family:var(--mono); font-size:.72rem; letter-spacing:.06em; text-transform:uppercase}\\n\\n/* ===========================================================================\\n   PRICING\\n   ======================================================================== */\\n.price{display:grid; grid-template-columns:1.1fr .9fr; gap:20px; margin-top:48px; align-items:stretch; position:relative; z-index:2}\\n.price__c{\\n  padding:clamp(26px,2.8vw,38px); border-radius:var(--r-xl);\\n  display:flex; flex-direction:column;\\n  transition:transform .28s var(--ease), box-shadow .28s var(--ease);\\n}\\n.price__c--hero{background:var(--white); box-shadow:var(--sh-lg)}\\n.price__c--hero:hover{transform:translateY(-4px); box-shadow:var(--sh-lg), 0 12px 32px rgba(11,11,12,.08)}\\n.price__c--alt{\\n  background:rgba(255,255,255,.78);\\n  box-shadow:var(--sh-sm), inset 0 0 0 1px rgba(11,11,12,.06);\\n}\\n.price__c--alt:hover{\\n  transform:translateY(-3px);\\n  box-shadow:var(--sh-md), inset 0 0 0 1px rgba(11,11,12,.06);\\n}\\n.price__c ul{flex:1}\\n.price__c .app-store-badge--wide,\\n.price__c > .btn{margin-top:auto}\\n.price__amt{display:flex; align-items:baseline; gap:10px; margin:18px 0 6px; flex-wrap:wrap}\\n.price__amt b{font-family:var(--display); font-size:clamp(2.1rem,3.6vw,2.9rem); font-weight:700; letter-spacing:-.028em; line-height:1}\\n.price__amt span{font-size:.95rem; color:var(--ink-3)}\\n.price ul{display:grid; gap:11px; margin:26px 0 28px}\\n.price li{display:grid; grid-template-columns:auto 1fr; gap:11px; font-size:.94rem; color:var(--ink-2)}\\n.price li svg{margin-top:4px}\\n\\n/* ===========================================================================\\n   BLOG\\n   ======================================================================== */\\n.blog-grid{\\n  display:grid; grid-template-columns:repeat(6,1fr); gap:16px;\\n  margin-top:40px; position:relative; z-index:2;\\n}\\n.blog-card{\\n  border-radius:var(--r-xl); overflow:hidden; position:relative;\\n  display:flex; flex-direction:column; min-width:0;\\n}\\n.blog-card--lead{grid-column:span 6}\\n.blog-card--sm{grid-column:span 2}\\n.blog-card__link{display:flex; flex-direction:column; height:100%; color:inherit}\\n.blog-card--lead .blog-card__link{\\n  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);\\n  min-height:100%;\\n}\\n.blog-card__art{\\n  background:var(--bone-deep);\\n  display:flex; align-items:center; justify-content:center;\\n  padding:clamp(14px,2vw,22px);\\n  box-shadow:inset 0 -1px 0 var(--line);\\n}\\n.blog-card--lead .blog-card__art{min-height:clamp(200px,24vw,280px)}\\n.blog-card--sm .blog-card__art{aspect-ratio:16/10}\\n.blog-card__art img{\\n  display:block; max-width:100%; max-height:100%;\\n  width:auto; height:auto; object-fit:contain;\\n  border-radius:10px;\\n}\\n.blog-card__body{\\n  padding:clamp(18px,2vw,24px);\\n  display:flex; flex-direction:column; gap:8px; flex:1;\\n}\\n.blog-card__date{\\n  font-family:var(--mono); font-size:.68rem; font-weight:600;\\n  letter-spacing:.08em; text-transform:uppercase; color:var(--ink-3);\\n}\\n.blog-card__title{\\n  font-size:clamp(1rem,1.4vw,1.12rem); font-weight:640;\\n  letter-spacing:-.018em; line-height:1.35; color:var(--ink);\\n}\\n.blog-card--lead .blog-card__title{\\n  font-family:var(--display);\\n  font-size:clamp(1.2rem,1.8vw,1.45rem); letter-spacing:-.022em;\\n}\\n.blog-card__desc{\\n  font-size:.92rem; line-height:1.55; color:var(--ink-2);\\n  letter-spacing:-.01em; margin-top:2px;\\n}\\n.blog-card--lead .blog-card__desc{\\n  font-size:.95rem; line-height:1.58; max-width:42ch;\\n}\\n.blog-card__more{\\n  margin-top:auto; padding-top:6px;\\n  font-size:.84rem; font-weight:600; color:var(--blue-deep);\\n  letter-spacing:-.01em;\\n}\\n.blog-foot{\\n  margin-top:24px; text-align:center; position:relative; z-index:2;\\n}\\n@media (max-width:1080px){\\n  .blog-grid{grid-template-columns:repeat(2,1fr)}\\n  .blog-card--lead{grid-column:span 2}\\n  .blog-card--sm{grid-column:span 1}\\n}\\n@media (max-width:720px){\\n  .blog-grid{grid-template-columns:1fr}\\n  .blog-card--lead,.blog-card--sm{grid-column:span 1}\\n  .blog-card--lead .blog-card__link{grid-template-columns:1fr}\\n  .blog-card--lead .blog-card__art{min-height:clamp(180px,52vw,240px)}\\n}\\n\\n/* ===========================================================================\\n   FAQ\\n   ======================================================================== */\\n.faq{max-width:820px; margin:48px auto 0; border-top:1px solid var(--bone-well); position:relative; z-index:2}\\n.faq details{border-bottom:1px solid var(--bone-well)}\\n.faq summary{\\n  display:flex; align-items:center; justify-content:space-between; gap:20px;\\n  padding:24px 4px; cursor:pointer; list-style:none;\\n  font-size:1.06rem; font-weight:600; letter-spacing:-.022em;\\n  transition:color .2s;\\n}\\n.faq summary:hover{color:var(--blue-deep)}\\n.faq summary::-webkit-details-marker{display:none}\\n.faq summary .pm{position:relative; width:18px; height:18px; flex:0 0 auto}\\n.faq summary .pm::before,.faq summary .pm::after{\\n  content:\"\"; position:absolute; background:var(--ink-3); border-radius:2px;\\n  transition:transform .3s var(--ease), opacity .22s;\\n}\\n.faq summary .pm::before{left:0; top:8px; width:18px; height:2px}\\n.faq summary .pm::after{top:0; left:8px; width:2px; height:18px}\\n.faq details[open] summary .pm::after{transform:rotate(90deg); opacity:0}\\n.faq__a{padding:0 60px 26px 4px; color:var(--ink-2); font-size:1rem; line-height:1.6}\\n\\n/* ===========================================================================\\n   DARK CTA + FOOTER\\n   ======================================================================== */\\n.cta{\\n  position:relative; overflow:hidden; background:var(--dark); color:#fff;\\n  border-radius:var(--r-2xl); margin:0 14px;\\n  padding:clamp(70px,7vw,110px) 0 clamp(48px,6vw,72px);\\n}\\n/* One light source, one hue — but two offset lobes that drift slowly, so the\\n   closing section reads as lit rather than printed. */\\n.cta__glow{\\n  position:absolute; z-index:0; width:1100px; height:760px; left:50%; top:-46%;\\n  transform:translateX(-50%);\\n  background:\\n    radial-gradient(42% 46% at 38% 52%, rgba(40,137,239,.34), rgba(40,137,239,0) 70%),\\n    radial-gradient(38% 42% at 66% 44%, rgba(96,178,255,.24), rgba(96,178,255,0) 72%);\\n  animation:auroraDrift 18s ease-in-out infinite alternate;\\n}\\n@keyframes auroraDrift{\\n  from{transform:translateX(-50%) translateY(0) scale(1)}\\n  to{transform:translateX(-46%) translateY(26px) scale(1.07)}\\n}\\n@media (prefers-reduced-motion:reduce){ .cta__glow{animation:none} }\\n.cta__grid{\\n  position:absolute; inset:0; z-index:0; pointer-events:none;\\n  background-image:\\n    linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),\\n    linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px);\\n  background-size:80px 80px;\\n  mask-image:radial-gradient(80% 60% at 50% 0%, #000, transparent 78%);\\n  -webkit-mask-image:radial-gradient(80% 60% at 50% 0%, #000, transparent 78%);\\n}\\n.cta__in{position:relative; z-index:2; text-align:center}\\n.cta .h2{max-width:840px; margin-inline:auto}\\n.cta__sub{color:rgba(255,255,255,.62); max-width:580px; margin:22px auto 0; font-size:1.06rem; line-height:1.55}\\n.cta__actions{display:flex; justify-content:center; align-items:center; flex-wrap:wrap; gap:12px; margin-top:36px}\\n.cta__row{display:flex; justify-content:center; gap:16px; margin-top:26px; flex-wrap:wrap}\\n.cta__row span{font-size:.84rem; color:rgba(255,255,255,.58)}\\n.cta__art{\\n  display:flex; justify-content:center; align-items:flex-end; gap:24px;\\n  margin-top:62px; min-height:clamp(400px,42vw,500px);\\n  padding-top:12px;\\n}\\n.cta__art .device{max-width:228px; flex:0 0 auto}\\n.cta__art .device:nth-child(1){transform:translateY(10px) rotate(-4deg)}\\n.cta__art .device:nth-child(2){transform:translateY(0)}\\n.cta__art .device:nth-child(3){transform:translateY(10px) rotate(4deg)}\\n\\n.foot{padding:76px 0 40px}\\n.foot__in{display:grid; grid-template-columns:1.4fr repeat(3,1fr); gap:36px}\\n.foot h4{font-size:.76rem; font-weight:620; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-3); margin-bottom:18px}\\n.foot ul{display:grid; gap:11px}\\n.foot li a{font-size:.9rem; color:var(--ink-2); letter-spacing:-.012em; transition:color .16s}\\n.foot li a:hover{color:var(--blue-deep)}\\n.foot__bot{\\n  display:flex; justify-content:space-between; align-items:center; gap:20px; flex-wrap:wrap;\\n  margin-top:56px; padding-top:26px; border-top:1px solid var(--bone-well);\\n  font-size:.83rem; color:var(--ink-3);\\n}\\n/* ===========================================================================\\n   6. MOTION\\n   ---------------------------------------------------------------------------\\n   All \"from\" states are gated on html.js, so with JS off every element\\n   renders in its final, visible state.\\n   ======================================================================== */\\n\\n/* Word-by-word reveal for display headings. JS wraps each word in\\n   .w > span; the inner span slides up out of the clipped outer span. */\\n.w{display:inline-block; overflow:hidden; vertical-align:top}\\n.w > span{display:inline-block}\\n.js .w > span{transform:translateY(105%)}\\n.js .w.is-revealing > span{will-change:transform}\\n.js .is-in .w > span,\\n.js .w.is-in > span{transform:none; transition:transform .82s var(--ease)}\\n\\n/* Generic reveal */\\n.js .rv{opacity:0; transform:translateY(24px); transition:opacity .75s var(--ease), transform .75s var(--ease)}\\n.js .rv.is-in{opacity:1; transform:none}\\n.rv-d1{transition-delay:.06s} .rv-d2{transition-delay:.12s} .rv-d3{transition-delay:.18s}\\n.rv-d4{transition-delay:.24s} .rv-d5{transition-delay:.30s}\\n\\n/* Hero device + callouts */\\n.js .stage__device{\\n  opacity:0;\\n  transform:translate(-50%,-50%) translateY(36px) rotateY(-18deg) scale(.94);\\n  transition:opacity .9s ease, transform 1.2s cubic-bezier(.19,.85,.24,1);\\n}\\n.js .hero.is-ready .stage__device{\\n  opacity:1;\\n  transform:translate(-50%,-50%) rotateY(calc(-8deg + var(--hero-ry, 0deg))) rotateX(calc(2deg + var(--hero-rx, 0deg)));\\n}\\n.js .callout{opacity:0; transform:translateY(12px) scale(.96); transition:opacity .6s ease, transform .7s cubic-bezier(.19,.85,.24,1)}\\n.js .hero.is-ready .callout{opacity:1; transform:none}\\n/* Mobile LCP: keep the hero device visible without waiting for React hydration\\n   or the deferred page script — hiding it until JS runs was pushing LCP to 4–9s. */\\n@media (max-width:960px){\\n  .js .rv,.js .rv-blur{opacity:1; transform:none; filter:none}\\n  .js .w > span{transform:none}\\n  .js .stage__device,\\n  .js .hero.is-ready .stage__device{\\n    opacity:1;\\n    transform:translate(-50%,-50%);\\n  }\\n  .js .callout,\\n  .js .hero.is-ready .callout{opacity:1; transform:none}\\n}\\n/* Keyed off placement classes: nth-of-type would also count the sibling\\n   .device element and shift every delay by one. */\\n.hero.is-ready .callout--a{transition-delay:.78s}\\n.hero.is-ready .callout--b{transition-delay:.94s}\\n.hero.is-ready .callout--c{transition-delay:1.10s}\\n.hero.is-ready .callout--d{transition-delay:1.26s}\\n\\n/* Pointer-tracked tilt. JS sets --rx/--ry; CSS owns the transform so it\\n   composes with the reveal transform cleanly. */\\n.tilt{transition:transform .4s var(--ease)}\\n.tilt.is-tilting{transition:transform .12s linear}\\n.tilt.is-tilting{transform:perspective(1000px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg))}\\n\\n@media (hover:none){ .tilt.is-tilting{transform:none} }\\n\\n@media (prefers-reduced-motion:reduce){\\n  *{animation:none !important; transition-duration:.01ms !important}\\n  .js .rv,.js .rv-blur{opacity:1; transform:none; filter:none}\\n  .statement .sw{color:var(--ink)}\\n  .statement .sw--accent{color:var(--blue)}\\n  .flip-txt.is-out .flip-txt__word,.flip-txt.is-in .flip-txt__word{animation:none}\\n  .js .w > span{transform:none}\\n  .js .stage__device{opacity:1; transform:translate(-50%,-50%)}\\n  .js .callout{opacity:1; transform:none}\\n  .progress{display:none}\\n  html{scroll-behavior:auto}\\n}\\n\\n/* ===========================================================================\\n   7. DEPTH + 3D — BIM-inspired spatial feel\\n   ======================================================================== */\\n\\n/* Parallax-ready layers */\\n.parallax{will-change:transform}\\n\\n/* Gentle float on hero callouts — inner only so reveal transform stays clean */\\n@keyframes floatCallout{\\n  0%,100%{transform:translateY(0)}\\n  50%{transform:translateY(-7px)}\\n}\\n.hero.is-ready .callout__in{animation:floatCallout 5.5s ease-in-out infinite}\\n.hero.is-ready .callout--a .callout__in{animation-delay:0s}\\n.hero.is-ready .callout--b .callout__in{animation-delay:-1.4s}\\n.hero.is-ready .callout--c .callout__in{animation-delay:-2.8s}\\n.hero.is-ready .callout--d .callout__in{animation-delay:-4.2s}\\n\\n/* Blur + rise reveal — richer scroll entrance */\\n.js .rv-blur{\\n  opacity:0; transform:translateY(28px) scale(.985);\\n  filter:blur(8px);\\n  transition:opacity .8s var(--ease), transform .8s var(--ease), filter .8s var(--ease);\\n}\\n.js .rv-blur.is-in{opacity:1; transform:none; filter:blur(0)}\\n\\n/* Slide-in from sides for split columns */\\n.js .rv-left{opacity:0; transform:translateX(-32px); transition:opacity .75s var(--ease), transform .75s var(--ease)}\\n.js .rv-right{opacity:0; transform:translateX(32px); transition:opacity .75s var(--ease), transform .75s var(--ease)}\\n.js .rv-left.is-in,.js .rv-right.is-in{opacity:1; transform:none}\\n/* Once these columns go full-width they can\\'t slide sideways without pushing\\n   the document wider than the viewport, which creates a horizontal scrollbar\\n   on touch devices. Below the stacking breakpoint they rise instead. */\\n@media (max-width:960px){\\n  .js .rv-left,.js .rv-right{transform:translateY(24px)}\\n}\\n\\n/* 3D isometric section icons */\\n.icon-3d{\\n  display:grid; place-items:center;\\n  width:54px; height:54px; border-radius:16px;\\n  background:linear-gradient(155deg,#fff 0%,var(--blue-wash) 55%,#d4e6fb 100%);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.95),\\n    inset 0 -2px 4px rgba(40,137,239,.08),\\n    0 4px 10px rgba(40,137,239,.16),\\n    0 14px 32px rgba(11,11,12,.07);\\n  transform-style:preserve-3d;\\n  transition:transform .4s var(--ease), box-shadow .4s var(--ease);\\n}\\n.role:hover .icon-3d{\\n  transform:translateY(-5px) rotateX(10deg) rotateY(-14deg) scale(1.04);\\n  box-shadow:\\n    inset 0 1px 0 rgba(255,255,255,.95),\\n    0 8px 22px rgba(40,137,239,.28),\\n    0 24px 48px rgba(11,11,12,.11);\\n}\\n.icon-3d svg{width:30px; height:30px; filter:drop-shadow(0 2px 3px rgba(40,137,239,.2))}\\n/* The role marks are detailed line drawings (building, chair, hat, tripod) —\\n   they need more of the tile than the simpler glyphs to stay legible. */\\n.role__ic.icon-3d svg{width:36px; height:36px}\\n.role__ic.icon-3d{background:linear-gradient(155deg,#fff 0%,var(--blue-wash) 55%,#d4e6fb 100%)}\\n\\n/* Freebie 3D gift icon */\\n.freebie__ic{\\n  transform-style:preserve-3d;\\n  transition:transform .4s var(--ease);\\n  box-shadow:inset 0 1px 0 rgba(255,255,255,.25), 0 8px 20px rgba(0,0,0,.15);\\n}\\n.freebie:hover .freebie__ic{transform:rotateX(12deg) rotateY(-18deg) scale(1.06)}\\n\\n/* Card depth lift on scroll-in and hover */\\n.bento .card,.step,.quote,.blog-card{\\n  transition:transform .45s var(--ease), box-shadow .45s var(--ease);\\n}\\n.bento .card.is-in:hover,.step.is-in:hover,.blog-card.is-in:hover{transform:translateY(-5px); box-shadow:var(--sh-lg)}\\n@media (hover:none){\\n  .bento .card.is-in:hover,.step.is-in:hover,.blog-card.is-in:hover{transform:none; box-shadow:var(--sh-sm)}\\n}\\n.quote.is-in:hover{transform:translateY(-4px); box-shadow:var(--sh-md)}\\n/* The pull-quote isn\\'t a card — it shouldn\\'t lift like one */\\n.quote--lead.is-in:hover{transform:none; box-shadow:none}\\n/* Role cards were the only grid that never answered the cursor */\\n.role{transition:transform .45s var(--ease), box-shadow .45s var(--ease)}\\n.role.is-in:hover{transform:translateY(-5px); box-shadow:var(--sh-lg)}\\n\\n/* Proof stat pop */\\n.js .proof__i{opacity:0; transform:translateY(20px) scale(.96); transition:opacity .7s var(--ease), transform .7s var(--ease)}\\n.js .proof.is-in .proof__i{opacity:1; transform:none}\\n.js .proof.is-in .proof__i:nth-child(1){transition-delay:.04s}\\n.js .proof.is-in .proof__i:nth-child(2){transition-delay:.12s}\\n.js .proof.is-in .proof__i:nth-child(3){transition-delay:.20s}\\n.js .proof.is-in .proof__i:nth-child(4){transition-delay:.28s}\\n\\n/* Dark CTA devices — subtle scroll parallax hook */\\n.cta__art .device{transition:transform .5s var(--ease)}\\n\\n/* Eyebrow line draw-in */\\n.js .eyebrow::before{transform:scaleX(0); transform-origin:0 50%; transition:transform .6s var(--ease) .1s}\\n.js .is-in .eyebrow::before,.js .eyebrow.is-in::before{transform:scaleX(1)}\\n\\n/* ===========================================================================\\n   RESPONSIVE\\n   ======================================================================== */\\n/* Lower-bounded on purpose. These selectors are more specific than the\\n   single-column reset at 600px (`.b-side:not(.freebie)` is 0,2,0 vs `.b-side`\\n   at 0,1,0), so an unbounded max-width query would leak past the 600px\\n   breakpoint, keep `span 2` on the team card and force a phantom second\\n   column on mobile. */\\n@media (min-width:601px) and (max-width:1080px){\\n  /* On a 4-column grid the desktop spans (4,2,4,2,2,2) do not tile: the notes\\n     card can\\'t fit beside the team card, so it wraps to its own row and leaves\\n     a hole next to Team, and Map is left stranded alone at the end.\\n     Reordering to 4 \\xb7 2+2 \\xb7 4 \\xb7 2+2 fills every row. Order is set here only,\\n     so the desktop layout (notes left, offer right) is untouched. */\\n  .bento{grid-template-columns:repeat(4,1fr)}\\n  .b-tall{grid-column:span 4; order:1}\\n  .b-side:not(.freebie){grid-column:span 2; order:2}\\n  .freebie{grid-column:span 2; order:3}\\n  .b-notes{grid-column:span 4; order:4}\\n  .b-half{grid-column:span 2; order:5}\\n}\\n\\n/* Secondary Framer pages (blog, contact, legal, etc.)\\n   Hide legacy purple gradients and skip scroll-reveal opacity that delays CMS lists. */\\nbody:not(:has(#hero)) [data-framer-name=\"Background Gradient\"]{display:none!important}\\nbody:not(:has(#hero)) [data-framer-appear-id]{\\n  opacity:1!important;\\n  transform:none!important;\\n  will-change:auto!important;\\n}\\nbody:not(:has(#hero)) #main,\\nbody:not(:has(#hero)) [data-framer-root]{background:var(--bone)!important}\\nbody:not(:has(#hero)) .framer-text h1,\\nbody:not(:has(#hero)) .framer-text h2,\\nbody:not(:has(#hero)) .framer-text h3{color:var(--ink)!important}\\nbody:not(:has(#hero)) .framer-text p,\\nbody:not(:has(#hero)) .framer-text li{color:var(--ink-2)!important}\\n\\n@media (max-width:960px){\\n  .nav__links{display:none}\\n  .nav__burger{display:flex}\\n  .nav__cta .btn--line{display:none}\\n  .hero__in{grid-template-columns:1fr}\\n  .hero__copy{max-width:none}\\n  .stage{height:560px; margin-top:16px}\\n  /* Phone sits square-on at this width — the perspective tilt reads as a\\n     rendering mistake once the device is centred rather than off to one side. */\\n  .stage__device{left:50%; transform:translate(-50%,-50%)!important; width:262px}\\n  .hero.is-ready .stage__device{transform:translate(-50%,-50%)!important}\\n  /* All four callouts stay. There is no room to sit fully outboard at this\\n     width, so they alternate left/right and overlap the phone — pinned to the\\n     calm bands of the screenshot (status bar, the gap under the plan, the gap\\n     above the button, the bottom bezel) rather than across its content. */\\n  .callout--a{left:-3%; right:auto; top:1%}\\n  .callout--b{right:-3%; left:auto; top:45%}\\n  .callout--c{left:-3%; right:auto; bottom:21%}\\n  .callout--d{right:-3%; left:auto; bottom:-3%}\\n  .callout__in{padding:9px 12px; gap:9px}\\n  .callout__k{font-size:.76rem}\\n  .callout__v{font-size:.68rem}\\n  .callout__ic{width:28px; height:28px; border-radius:9px}\\n  .callout img.fmt{width:18px; height:18px}\\n  .avatars i{width:27px; height:27px; font-size:.58rem; margin-left:-7px}\\n  .steps,.quotes{grid-template-columns:1fr}\\n  .step__art{min-height:auto; padding:28px 20px 24px}\\n  .step__art .device{margin-bottom:0; max-width:min(200px,54vw)}\\n  .roles{grid-template-columns:repeat(2,1fr)}\\n  .cmp,.price{grid-template-columns:1fr}\\n  .onsite{grid-template-columns:1fr}\\n  .desk__meta{grid-template-columns:1fr}\\n  .proof,.spec{grid-template-columns:1fr 1fr}\\n  .foot__in{grid-template-columns:1fr 1fr}\\n  /* Keep all three screens — they read as a set. Shrink and tighten the gap\\n     rather than dropping any, which left a lone phone looking unintentional. */\\n  .cta__art{gap:12px; min-height:270px}\\n  .cta__art .device{max-width:150px}\\n}\\n@media (max-width:600px){\\n  :root{--gut:20px; --r-2xl:28px}\\n  body{font-size:16px}\\n  .bento{grid-template-columns:1fr}\\n  .roles{grid-template-columns:1fr}\\n  .b-tall,.b-side,.b-half,.b-notes{grid-column:span 1; order:0}\\n  .b-tall{align-self:stretch}\\n  /* Single column: the offer card is sized purely by its own content, so the\\n     only way to shorten it is to shrink the content. */\\n  .freebie{gap:16px}\\n  .freebie__ic{width:40px; height:40px; border-radius:12px}\\n  .freebie__ic svg{width:21px; height:21px}\\n  .freebie__n{font-size:2rem}\\n  .b-notes__body{padding:22px 22px 26px}\\n  .bento .b-art.b-art--duo{\\n    flex:0 0 auto; height:auto; max-height:none;\\n    gap:12px; padding:24px 16px; align-items:center;\\n  }\\n  .b-art--tall,.b-art--side{\\n    height:auto; min-height:0; padding:24px 16px;\\n    place-items:center;\\n  }\\n  .bento .b-art.b-art--duo .device,\\n  .b-art--tall .device,.b-art--side .device{\\n    max-width:min(148px,38vw); margin-bottom:0; transform:none;\\n  }\\n  /* Deliberately not shrunk to 148px like its siblings — this phone is a\\n     magnifier on one UI band, not a whole-screen thumbnail. */\\n  .bento .b-art--notes{height:clamp(164px,45vw,182px); padding-bottom:14px}\\n  .bento .b-art--notes .device{max-width:min(296px,84vw); transform:none}\\n  .bento .b-art.b-art--duo .device:nth-child(2){margin-bottom:0}\\n  /* Two columns of spec at phone width leaves ~150px per value — the\\n     tolerance figure wraps mid-number. One column reads properly. */\\n  .spec{grid-template-columns:1fr}\\n  .btn{width:100%; justify-content:center}\\n  .nav__cta .btn{width:auto}\\n  .foot__in{grid-template-columns:1fr}\\n  .faq__a{padding-right:8px}\\n  .foot{padding-bottom:calc(40px + 72px)}\\n  .cta__art{gap:7px; min-height:210px}\\n  .cta__art .device{max-width:105px}\\n  .step__art{padding:24px 16px 20px}\\n  .step__art .device{max-width:min(168px,58vw)}\\n}\\n';const html='<div class=\"progress\" id=\"progress\"></div>\\n\\n<svg width=\"0\" height=\"0\" style=\"position:absolute\" aria-hidden=\"true\"><defs>\\n  <symbol id=\"i-arrow\" viewBox=\"0 0 16 16\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 8h9.5M8.5 4l4 4-4 4\"/></symbol>\\n  <symbol id=\"i-check\" viewBox=\"0 0 14 14\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M2.5 7.4 5.4 10.2 11.5 3.9\"/></symbol>\\n  <symbol id=\"i-cube\" viewBox=\"0 0 20 20\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" d=\"M10 2.6 17 6.3v7.4L10 17.4 3 13.7V6.3z\"/><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" opacity=\".55\" d=\"M3 6.3 10 10l7-3.7M10 10v7.4\"/></symbol>\\n  <symbol id=\"i-ruler\" viewBox=\"0 0 20 20\"><rect x=\"1.6\" y=\"6.4\" width=\"16.8\" height=\"7.2\" rx=\"1.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" d=\"M6 6.6v2.6M10 6.6v3.6M14 6.6v2.6\"/></symbol>\\n  <symbol id=\"i-users\" viewBox=\"0 0 20 20\"><circle cx=\"7.6\" cy=\"7\" r=\"2.9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" d=\"M2.4 16.4c.5-2.7 2.6-4.2 5.2-4.2s4.7 1.5 5.2 4.2M13.4 4.5a2.7 2.7 0 0 1 0 5.1M15.2 12.6c1.5.5 2.5 1.8 2.8 3.8\"/></symbol>\\n  <symbol id=\"i-file\" viewBox=\"0 0 20 20\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" d=\"M11.4 2.6H5.6v14.8h8.8V5.6z\"/><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" d=\"M11.4 2.6v3h3\"/></symbol>\\n  <symbol id=\"i-clock\" viewBox=\"0 0 20 20\"><circle cx=\"10\" cy=\"10\" r=\"7.4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" d=\"M10 5.8V10l3 2\"/></symbol>\\n  <symbol id=\"i-gift\" viewBox=\"0 0 22 22\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linejoin=\"round\" d=\"M3.4 9h15.2v9.4H3.4zM2.6 5.6h16.8V9H2.6zM11 5.6v12.8\"/><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linejoin=\"round\" d=\"M11 5.6C9.5 5.6 6.6 5.4 6.6 3.9S9.7 3.2 11 5.6c1.3-2.4 4.4-2.2 4.4-.7S12.5 5.6 11 5.6z\"/></symbol>\\n  <symbol id=\"i-pin\" viewBox=\"0 0 20 20\"><path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" d=\"M10 17.4s5.4-5 5.4-9A5.4 5.4 0 0 0 4.6 8.4c0 4 5.4 9 5.4 9z\"/><circle cx=\"10\" cy=\"8.2\" r=\"2.1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/></symbol>\\n  <symbol id=\"i-info\" viewBox=\"0 0 20 20\"><circle cx=\"10\" cy=\"10\" r=\"7.4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" d=\"M10 9.2v4.6\"/><circle cx=\"10\" cy=\"6.4\" r=\".9\" fill=\"currentColor\"/></symbol>\\n</defs></svg>\\n\\n<!-- ==========================================================================\\n     NAV\\n     ======================================================================= -->\\n<header class=\"nav\" id=\"nav\">\\n  <div class=\"wrap\">\\n    <div class=\"nav__in\">\\n      <a class=\"logo\" href=\"https://www.scanbrix.com/\">\\n        <img src=\"https://framerusercontent.com/images/8G5OQTatiSleYLitSo5hsJRKcIg.png\" alt=\"\" width=\"29\" height=\"29\"> Scanbrix\\n      </a>\\n      <nav class=\"nav__links\" aria-label=\"Primary\">\\n        <a href=\"https://www.scanbrix.com/#how\" data-nav=\"how\">How it works</a>\\n        <a href=\"https://www.scanbrix.com/#deliverables\" data-nav=\"deliverables\">Deliverables</a>\\n        <a href=\"https://www.scanbrix.com/#features\" data-nav=\"features\">Features</a>\\n        <a href=\"https://www.scanbrix.com/#pricing\" data-nav=\"pricing\">Pricing</a>\\n        <div class=\"nav__more\" id=\"nav-more\">\\n          <button class=\"nav__more-btn\" type=\"button\" id=\"nav-more-btn\" aria-expanded=\"false\" aria-haspopup=\"true\" aria-controls=\"nav-more-drop\">More</button>\\n          <div class=\"nav__drop\" id=\"nav-more-drop\" role=\"menu\">\\n            <a href=\"https://www.scanbrix.com/blog\" role=\"menuitem\">Blog</a>\\n            <a href=\"https://www.scanbrix.com/faqs\" role=\"menuitem\">FAQ</a>\\n            <a href=\"https://www.scanbrix.com/contact\" role=\"menuitem\">Contact</a>\\n          </div>\\n        </div>\\n      </nav>\\n      <div class=\"nav__cta\">\\n        <a class=\"btn btn--line\" href=\"https://www.scanbrix.com/contact\">Talk to us</a>\\n        <a class=\"app-store-badge app-store-badge--sm\" href=\"https://apps.apple.com/app/scanbrix-lidar-3d-scanner/id6753146245\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"Download on the App Store\">\\n          <img src=\"https://framerusercontent.com/images/bcWU6MszuFCx8QhrMjePUvwZeVw.svg\" alt=\"Download on the App Store\" width=\"120\" height=\"40\">\\n        </a>\\n        <button class=\"nav__burger\" id=\"burger\" aria-label=\"Menu\" aria-expanded=\"false\" aria-controls=\"mnav\">\\n          <span class=\"nav__burger-bars\" aria-hidden=\"true\"><i></i><i></i></span>\\n        </button>\\n      </div>\\n    </div>\\n\\n    <!-- Mobile menu. Toggled by #burger; closes on link tap or Escape. -->\\n    <nav class=\"mnav\" id=\"mnav\" aria-label=\"Mobile\">\\n      <a href=\"https://www.scanbrix.com/#how\">How it works</a>\\n      <a href=\"https://www.scanbrix.com/#deliverables\">Deliverables</a>\\n      <a href=\"https://www.scanbrix.com/#features\">Features</a>\\n      <a href=\"https://www.scanbrix.com/#pricing\">Pricing</a>\\n      <a href=\"https://www.scanbrix.com/blog\">Blog</a>\\n      <a href=\"https://www.scanbrix.com/faqs\">FAQ</a>\\n      <a href=\"https://www.scanbrix.com/contact\">Contact</a>\\n      <a href=\"https://www.scanbrix.com/contact\" class=\"mnav__talk\">Talk to us</a>\\n    </nav>\\n  </div>\\n</header>';/**\n * Site chrome: the stylesheet, the scroll-progress bar, the SVG icon sprite and\n * the header nav. Lives in the layout template so every page is styled.\n *\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n * @framerIntrinsicWidth 1440\n */export default function ScanbrixChrome(){useEffect(()=>{document.documentElement.classList.add(\"js\");},[]);return /*#__PURE__*/_jsxs(\"div\",{style:{width:\"100%\"},children:[/*#__PURE__*/_jsx(\"style\",{dangerouslySetInnerHTML:{__html:css}}),/*#__PURE__*/_jsx(\"div\",{dangerouslySetInnerHTML:{__html:html}})]});}\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"ScanbrixChrome\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerIntrinsicWidth\":\"1440\",\"framerSupportedLayoutHeight\":\"any-prefer-fixed\",\"framerSupportedLayoutWidth\":\"any-prefer-fixed\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./ScanbrixChrome.map","// Generated from index.html by tools/build-framer-page.mjs. Do not edit.\nimport{jsx as _jsx}from\"react/jsx-runtime\";import{useEffect,useRef}from\"react\";const html='<footer class=\"foot\" id=\"contact\">\\n  <div class=\"wrap\">\\n    <div class=\"foot__in\">\\n      <div>\\n        <a class=\"logo\" href=\"https://www.scanbrix.com/\" style=\"margin-bottom:16px\">\\n          <img src=\"https://framerusercontent.com/images/8G5OQTatiSleYLitSo5hsJRKcIg.png\" alt=\"\" width=\"29\" height=\"29\"> Scanbrix\\n        </a>\\n        <p class=\"small\" style=\"max-width:300px\">\\n          Scan any space with your iPhone. Native Revit, SketchUp and AutoCAD\\n          as-builts back in about two business days.\\n        </p>\\n        <a class=\"app-store-badge\" href=\"https://apps.apple.com/app/scanbrix-lidar-3d-scanner/id6753146245\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"margin-top:22px\" aria-label=\"Download on the App Store\">\\n          <img src=\"https://framerusercontent.com/images/bcWU6MszuFCx8QhrMjePUvwZeVw.svg\" alt=\"Download on the App Store\" width=\"135\" height=\"44\">\\n        </a>\\n      </div>\\n      <div>\\n        <h4>Product</h4>\\n        <ul>\\n          <li><a href=\"https://www.scanbrix.com/#how\">How it works</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#features\">Features</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#deliverables\">Deliverables</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#pricing\">Pricing</a></li>\\n        </ul>\\n      </div>\\n      <div>\\n        <h4>Built for</h4>\\n        <ul>\\n          <li><a href=\"https://www.scanbrix.com/#who\">Architects</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#who\">Interior designers</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#who\">Contractors</a></li>\\n          <li><a href=\"https://www.scanbrix.com/#who\">Surveyors</a></li>\\n          <li><a href=\"https://www.scanbrix.com/contact\">Enterprise</a></li>\\n        </ul>\\n      </div>\\n      <div>\\n        <h4>Company</h4>\\n        <ul>\\n          <li><a href=\"https://www.scanbrix.com/blog\">Blog</a></li>\\n          <li><a href=\"https://www.scanbrix.com/faqs\">FAQ</a></li>\\n          <li><a href=\"https://www.scanbrix.com/contact\">Contact</a></li>\\n          <li><a href=\"https://www.scanbrix.com/legal/privacy-policy\">Privacy</a></li>\\n          <li><a href=\"https://www.scanbrix.com/legal/terms-of-service\">Terms</a></li>\\n        </ul>\\n      </div>\\n    </div>\\n    <div class=\"foot__bot\">\\n      <span>\\xa9 <span id=\"yr\">2026</span> Scanbrix. All rights reserved.</span>\\n      <span>Made for people who\\'d rather be designing than measuring.</span>\\n    </div>\\n  </div>\\n</footer>';const js=\"\\n/* ===========================================================================\\n   MOTION — progressive enhancement only. The page is complete without it.\\n   ======================================================================== */\\n(function () {\\n  'use strict';\\n  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\\n  var isHome = !!document.getElementById('hero');\\n\\n  /* ---------------------------------------------------------------------\\n     1. Split headings into words for the clip-and-slide reveal.\\n     Each word becomes .w > span. <br> and inline markup are preserved by\\n     walking text nodes rather than rewriting innerHTML wholesale.\\n  --------------------------------------------------------------------- */\\n  function splitWords(root) {\\n    var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);\\n    var nodes = [], n;\\n    while ((n = walker.nextNode())) { if (n.nodeValue.trim()) nodes.push(n); }\\n    nodes.forEach(function (node) {\\n      var frag = document.createDocumentFragment();\\n      node.nodeValue.split(/(\\\\s+)/).forEach(function (tok) {\\n        if (!tok) return;\\n        if (!tok.trim()) { frag.appendChild(document.createTextNode(tok)); return; }\\n        var outer = document.createElement('span');\\n        outer.className = 'w';\\n        var inner = document.createElement('span');\\n        inner.textContent = tok;\\n        outer.appendChild(inner);\\n        frag.appendChild(outer);\\n      });\\n      node.parentNode.replaceChild(frag, node);\\n    });\\n    // stagger, in document order\\n    var i = 0;\\n    root.querySelectorAll('.w > span').forEach(function (s) {\\n      s.style.transitionDelay = (i * 0.038).toFixed(3) + 's';\\n      s.addEventListener('transitionend', function once(ev) {\\n        if (ev.propertyName !== 'transform') return;\\n        s.parentElement.classList.remove('is-revealing');\\n        s.removeEventListener('transitionend', once);\\n      });\\n      i++;\\n    });\\n    root.querySelectorAll('.w').forEach(function (w) { w.classList.add('is-revealing'); });\\n  }\\n  if (!reduce) {\\n    function runSplitWords() {\\n      document.querySelectorAll('.splitwords').forEach(splitWords);\\n    }\\n    /* Defer word-splitting so first paint and hydration aren't blocked. */\\n    if ('requestIdleCallback' in window) {\\n      requestIdleCallback(runSplitWords, { timeout: 1800 });\\n    } else {\\n      setTimeout(runSplitWords, 1);\\n    }\\n  }\\n\\n  /* ---------------------------------------------------------------------\\n     2. Count-up for the proof figures\\n  --------------------------------------------------------------------- */\\n  function countUp(el) {\\n    var to = parseFloat(el.dataset.to);\\n    if (reduce || !isFinite(to) || el.dataset.counted) return;\\n    el.dataset.counted = '1';\\n\\n    var dur = 1100, start = null, finished = false;\\n    var fmt = function (v) { return to >= 1000 ? Math.round(v).toLocaleString('en-US') : String(Math.round(v)); };\\n    function settle() { finished = true; el.textContent = fmt(to); }\\n\\n    /* Safety net: rAF is throttled in background tabs and stops entirely if the\\n       tab is hidden, which would otherwise strand the figure at 0. */\\n    var guard = setTimeout(function () { if (!finished) settle(); }, dur + 600);\\n\\n    el.textContent = fmt(0);\\n    function tick(ts) {\\n      if (start === null) start = ts;\\n      var p = Math.min(1, (ts - start) / dur);\\n      el.textContent = fmt(to * (1 - Math.pow(1 - p, 3)));\\n      if (p < 1) { requestAnimationFrame(tick); }\\n      else { clearTimeout(guard); settle(); }\\n    }\\n    requestAnimationFrame(tick);\\n  }\\n\\n  /* ---------------------------------------------------------------------\\n     3. Reveal observer — drives .rv, .rv-blur, heading words, bars and counters\\n  --------------------------------------------------------------------- */\\n  var revealTargets = document.querySelectorAll('.rv, .rv-blur, .rv-left, .rv-right, .splitwords, .cmp, .proof');\\n  function showAll() {\\n    revealTargets.forEach(function (el) { el.classList.add('is-in'); });\\n    document.querySelectorAll('.count').forEach(function (el) {\\n      var to = parseFloat(el.dataset.to);\\n      el.textContent = to >= 1000 ? to.toLocaleString('en-US') : to;\\n    });\\n  }\\n  if (reduce || !('IntersectionObserver' in window)) {\\n    showAll();\\n  } else {\\n    var io = new IntersectionObserver(function (entries) {\\n      entries.forEach(function (e) {\\n        if (!e.isIntersecting) return;\\n        e.target.classList.add('is-in');\\n        e.target.querySelectorAll('.count').forEach(countUp);\\n        io.unobserve(e.target);\\n      });\\n    }, { rootMargin: '0px 0px -10% 0px', threshold: 0.15 });\\n    revealTargets.forEach(function (el) { io.observe(el); });\\n  }\\n\\n  /* ---------------------------------------------------------------------\\n     4. Hero entrance\\n  --------------------------------------------------------------------- */\\n  var hero = document.getElementById('hero');\\n  function startHero() {\\n    /* Absent on pages that reuse this script for the nav and footer alone. */\\n    if (!hero || hero.classList.contains('is-ready')) return;\\n    hero.classList.add('is-ready');\\n    hero.querySelectorAll('.splitwords').forEach(function (el) { el.classList.add('is-in'); });\\n  }\\n  /* Two frames lets the \\\"from\\\" state paint so the entrance actually animates.\\n     The timeout is a safety net: rAF is starved in background tabs, and the\\n     hero device sits at opacity 0 until this runs — so it must not be the\\n     only trigger, or the hero can render blank. */\\n  /* Run immediately — deferring this via requestIdleCallback delayed LCP on mobile. */\\n  startHero();\\n\\n  /* ---------------------------------------------------------------------\\n     5. Nav state + scroll progress + parallax, in one rAF-throttled handler\\n     Secondary pages only need the nav + progress bar — skip homepage-only work.\\n  --------------------------------------------------------------------- */\\n  var nav = document.getElementById('nav');\\n  var bar = document.getElementById('progress');\\n  var parallaxEls = isHome ? document.querySelectorAll('[data-parallax]') : [];\\n  var heroEl = isHome ? document.getElementById('hero') : null;\\n  var stage = isHome ? document.querySelector('.stage__device') : null;\\n  var ctaDevices = isHome ? document.querySelectorAll('.cta__art .device') : [];\\n  var navLinks = document.querySelectorAll('.nav__links a[data-nav]');\\n  var navSections = [];\\n  navLinks.forEach(function (link) {\\n    var id = link.getAttribute('data-nav');\\n    var sec = document.getElementById(id);\\n    if (sec) navSections.push({ id: id, el: sec, link: link });\\n  });\\n  var statements = [];\\n  if (isHome) {\\n    document.querySelectorAll('.statement').forEach(function (sec) {\\n      statements.push({ el: sec, words: sec.querySelectorAll('.sw') });\\n    });\\n  }\\n  var cachedDocHeight = document.documentElement.scrollHeight;\\n  var cachedHeroBottom = heroEl ? heroEl.offsetTop + heroEl.offsetHeight : 0;\\n  function refreshLayoutCache() {\\n    cachedDocHeight = document.documentElement.scrollHeight;\\n    if (heroEl) cachedHeroBottom = heroEl.offsetTop + heroEl.offsetHeight;\\n  }\\n  window.addEventListener('resize', refreshLayoutCache, { passive: true });\\n  var queued = false;\\n  function onScroll() {\\n    if (queued) return;\\n    queued = true;\\n    requestAnimationFrame(function () {\\n      queued = false;\\n      var y = window.scrollY || 0;\\n      var vh = window.innerHeight;\\n\\n      /* --- read phase: batch all layout queries before any writes --- */\\n      var navRects = navSections.map(function (item) {\\n        return item.el.getBoundingClientRect();\\n      });\\n      var parallaxRects = [];\\n      parallaxEls.forEach(function (el) {\\n        parallaxRects.push({ el: el, rect: el.getBoundingClientRect() });\\n      });\\n      var heroRect = (stage && heroEl && window.innerWidth > 960) ? heroEl.getBoundingClientRect() : null;\\n      var statementRects = [];\\n      if (!reduce) {\\n        statements.forEach(function (st) {\\n          statementRects.push({ st: st, rect: st.el.getBoundingClientRect() });\\n        });\\n      }\\n      var ctaRect = null;\\n      if (ctaDevices.length) {\\n        var ctaEl = ctaDevices[0].closest('.cta');\\n        if (ctaEl) ctaRect = ctaEl.getBoundingClientRect();\\n      }\\n\\n      /* --- write phase --- */\\n      nav.classList.toggle('is-stuck', y > 24);\\n      nav.classList.toggle('is-past-hero', y > cachedHeroBottom - 90);\\n\\n      var activeId = '';\\n      if (isHome) {\\n        var navLine = 140;\\n        for (var i = navSections.length - 1; i >= 0; i--) {\\n          var r = navRects[i];\\n          if (r.top <= navLine) {\\n            activeId = navSections[i].id;\\n            break;\\n          }\\n        }\\n      }\\n      navLinks.forEach(function (link) {\\n        link.classList.toggle('is-active', isHome && link.getAttribute('data-nav') === activeId);\\n      });\\n\\n      var max = cachedDocHeight - vh;\\n      bar.style.transform = 'scaleX(' + (max > 0 ? Math.min(1, y / max) : 0) + ')';\\n\\n      parallaxRects.forEach(function (item) {\\n        var rate = parseFloat(item.el.dataset.parallax) || 0.15;\\n        var center = item.rect.top + item.rect.height * 0.5;\\n        var offset = (center - vh * 0.5) * rate * -0.12;\\n        item.el.style.transform = 'translate3d(0,' + offset.toFixed(2) + 'px,0)';\\n      });\\n\\n      if (heroRect && heroRect.bottom > 0 && heroRect.top < vh) {\\n        var progress = Math.min(1, Math.max(0, y / (heroRect.height * 0.8)));\\n        stage.style.setProperty('--hero-ry', (-progress * 5) + 'deg');\\n        stage.style.setProperty('--hero-rx', (progress * 3) + 'deg');\\n      }\\n\\n      if (!reduce) {\\n        statementRects.forEach(function (item) {\\n          var r = item.rect;\\n          if (r.bottom < 0 || r.top > vh) return;\\n          var p = (vh * 0.85 - r.top) / (r.height + vh * 0.45);\\n          p = Math.min(1, Math.max(0, p));\\n          var lit = Math.round(p * item.st.words.length);\\n          item.st.words.forEach(function (w, i) { w.classList.toggle('lit', i < lit); });\\n        });\\n      }\\n\\n      if (ctaRect && ctaRect.top < vh && ctaRect.bottom > 0) {\\n        ctaDevices.forEach(function (dev, i) {\\n          var p = Math.min(1, Math.max(0, (vh - ctaRect.top) / (vh + ctaRect.height * 0.3)));\\n          var spread = (i - 1) * p * 12;\\n          var lift = (1 - Math.abs(i - 1)) * p * -14;\\n          var rot = (i - 1) * 4 * p;\\n          var baseY = i === 1 ? 0 : 10;\\n          dev.style.transform = 'translateY(' + (baseY + lift).toFixed(1) + 'px) translateX(' + spread.toFixed(1) + 'px) rotate(' + rot.toFixed(1) + 'deg)';\\n        });\\n      }\\n    });\\n  }\\n  window.addEventListener('scroll', onScroll, { passive: true });\\n  window.addEventListener('resize', onScroll, { passive: true });\\n  onScroll();\\n  /* Refresh doc height after images/fonts settle without blocking scroll. */\\n  window.addEventListener('load', refreshLayoutCache, { passive: true });\\n\\n  /* ---------------------------------------------------------------------\\n     6. Pointer-tracked card tilt. Fine pointers only — on touch the\\n        transform would stick after the tap ends.\\n  --------------------------------------------------------------------- */\\n  if (!reduce && window.matchMedia('(hover:hover) and (pointer:fine)').matches) {\\n    document.querySelectorAll('.tilt').forEach(function (card) {\\n      var raf = null;\\n      var cachedRect = null;\\n      card.addEventListener('pointerenter', function () {\\n        cachedRect = card.getBoundingClientRect();\\n      });\\n      card.addEventListener('pointermove', function (ev) {\\n        if (raf) return;\\n        raf = requestAnimationFrame(function () {\\n          raf = null;\\n          if (!cachedRect) cachedRect = card.getBoundingClientRect();\\n          var px = (ev.clientX - cachedRect.left) / cachedRect.width - 0.5;\\n          var py = (ev.clientY - cachedRect.top) / cachedRect.height - 0.5;\\n          card.style.setProperty('--ry', (px * 5).toFixed(2) + 'deg');\\n          card.style.setProperty('--rx', (-py * 5).toFixed(2) + 'deg');\\n          card.classList.add('is-tilting');\\n        });\\n      });\\n      card.addEventListener('pointerleave', function () {\\n        cachedRect = null;\\n        card.classList.remove('is-tilting');\\n        card.style.setProperty('--ry', '0deg');\\n        card.style.setProperty('--rx', '0deg');\\n      });\\n    });\\n  }\\n\\n  document.getElementById('yr').textContent = new Date().getFullYear();\\n\\n  /* ---------------------------------------------------------------------\\n     Sample-pack capture.\\n\\n     Posts to /api/sample-pack (Vercel serverless). Set\\n     GOOGLE_SHEETS_WEBHOOK_URL and SENDGRID_API_KEY in Vercel.\\n     See scripts/google-sheets-webhook.gs and api/sample-pack.js.\\n  --------------------------------------------------------------------- */\\n  (function samplePack() {\\n    var LEAD_ENDPOINT = 'https://website-20-eight.vercel.app/api/sample-pack';\\n    var INBOX = 'support@scanbrix.com';\\n    var valid = /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]{2,}$/;\\n\\n    function mailtoFallback(email, source, box, say) {\\n      var subject = 'Send me the Scanbrix sample files';\\n      var body = 'Please send the Revit, SketchUp and AutoCAD sample files to: ' +\\n                 email + '\\\\n\\\\n(Requested from the ' + source + ' section.)';\\n      window.location.href = 'mailto:' + INBOX +\\n        '?subject=' + encodeURIComponent(subject) +\\n        '&body=' + encodeURIComponent(body);\\n      box.classList.add('is-done');\\n      say('Opening your mail app — just hit send and the pack is on its way.', 'ok');\\n    }\\n\\n    document.querySelectorAll('[data-magnet]').forEach(function (form) {\\n      var box = form.closest('.magnet');\\n      var field = form.querySelector('.magnet__field');\\n      var msg = box.querySelector('.magnet__msg');\\n      var btn = form.querySelector('.magnet__go');\\n\\n      function say(text, kind) {\\n        msg.textContent = text;\\n        msg.className = 'magnet__msg is-on magnet__msg--' + kind;\\n      }\\n\\n      form.addEventListener('submit', function (ev) {\\n        ev.preventDefault();\\n        var email = (field.value || '').trim();\\n\\n        if (!valid.test(email)) {\\n          say('That email doesn’t look right — mind checking it?', 'err');\\n          field.focus();\\n          return;\\n        }\\n\\n        var source = 'deliverables';\\n\\n        btn.disabled = true;\\n        var original = btn.innerHTML;\\n        btn.textContent = 'Sending…';\\n\\n        fetch(LEAD_ENDPOINT, {\\n          method: 'POST',\\n          headers: { 'Content-Type': 'application/json' },\\n          body: JSON.stringify({ email: email, source: source, page: window.location.pathname })\\n        }).then(function (res) {\\n          if (res.status === 503) {\\n            btn.disabled = false;\\n            btn.innerHTML = original;\\n            mailtoFallback(email, source, box, say);\\n            return;\\n          }\\n          if (!res.ok) throw new Error(res.status);\\n          if (typeof window.scanbrixTrack === 'function') {\\n            window.scanbrixTrack('sample_pack_submitted', {\\n              source: source,\\n              page_path: window.location.pathname,\\n            });\\n          }\\n          box.classList.add('is-done');\\n          say('On its way. Check ' + email + ' in a minute.', 'ok');\\n        }).catch(function () {\\n          btn.disabled = false;\\n          btn.innerHTML = original;\\n          say('That didn’t send. Email ' + INBOX + ' and we’ll get them to you.', 'err');\\n        });\\n      });\\n    });\\n  })();\\n\\n  /* ---------------------------------------------------------------------\\n     7. Desktop deliverables tab switcher\\n  --------------------------------------------------------------------- */\\n  (function deskTabs() {\\n    var root = document.getElementById('desk');\\n    if (!root) return;\\n    var tabs = root.querySelectorAll('.desk__tab');\\n    var panels = root.querySelectorAll('.desk__panel');\\n    var title = document.getElementById('desk-filename');\\n    var dl = document.getElementById('desk-dl');\\n    var dlLabel = document.getElementById('desk-dl-label');\\n    var names = {\\n      revit: 'Sample File Revit.rvt \\xb7 3D View',\\n      sketchup: 'Sample File SketchUp.skp \\xb7 Floor Plan',\\n      autocad: 'Sample File Revit.dwg \\xb7 Floor Plans & Elevations'\\n    };\\n    var downloads = {\\n      revit: { href: 'https://drive.google.com/uc?export=download&id=1Sq4Oqo_IBfBC_Ldg2kocD7TsQXQzjPKy', label: 'Download sample .rvt' },\\n      sketchup: { href: 'https://drive.google.com/uc?export=download&id=1Rd9nDDb2h2DrQYaFpQH3UoZLi6AOBDn2', label: 'Download sample .skp' },\\n      autocad: { href: 'https://drive.google.com/uc?export=download&id=1BQGIG-FDHv-h9-PoOW40BKmRdVAsSDvV', label: 'Download sample .dwg' }\\n    };\\n\\n    function setDesk(key) {\\n      tabs.forEach(function (t) {\\n        var on = t.dataset.desk === key;\\n        t.classList.toggle('is-active', on);\\n        t.setAttribute('aria-selected', on ? 'true' : 'false');\\n        t.tabIndex = on ? 0 : -1;\\n      });\\n      panels.forEach(function (panel) {\\n        var on = panel.dataset.desk === key;\\n        panel.classList.toggle('is-active', on);\\n        panel.hidden = !on;\\n      });\\n      if (title) title.textContent = names[key] || '';\\n      var file = downloads[key];\\n      if (dl && file) {\\n        dl.href = file.href;\\n        if (dlLabel) dlLabel.textContent = file.label;\\n      }\\n    }\\n\\n    tabs.forEach(function (tab, idx) {\\n      tab.tabIndex = idx === 0 ? 0 : -1;\\n      tab.addEventListener('click', function () { setDesk(tab.dataset.desk); });\\n      tab.addEventListener('keydown', function (ev) {\\n        var keys = ['ArrowLeft', 'ArrowRight', 'Home', 'End'];\\n        if (keys.indexOf(ev.key) === -1) return;\\n        ev.preventDefault();\\n        var list = Array.prototype.slice.call(tabs);\\n        var i = list.indexOf(tab);\\n        if (ev.key === 'ArrowRight') i = (i + 1) % list.length;\\n        if (ev.key === 'ArrowLeft') i = (i - 1 + list.length) % list.length;\\n        if (ev.key === 'Home') i = 0;\\n        if (ev.key === 'End') i = list.length - 1;\\n        list[i].focus();\\n        setDesk(list[i].dataset.desk);\\n      });\\n    });\\n\\n    document.querySelectorAll('[data-desk-link]').forEach(function (link) {\\n      link.addEventListener('click', function () {\\n        setDesk(link.dataset.deskLink);\\n      });\\n    });\\n\\n    setDesk('revit');\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     8. Hero format callout — cycles Revit / SketchUp / AutoCAD\\n  --------------------------------------------------------------------- */\\n  (function fmtCallout() {\\n    var wrap = document.querySelector('#fmt-callout .callout__in');\\n    var logo = document.getElementById('fmt-cycle-logo');\\n    var name = document.getElementById('fmt-cycle-name');\\n    var ext = document.getElementById('fmt-cycle-ext');\\n    if (!wrap || !logo || !name || !ext || reduce) return;\\n\\n    var formats = [\\n      { logo: 'https://framerusercontent.com/images/4k4HvtN2GWTysoZLcYEelNsURo.png', name: 'Revit', ext: '.rvt', alt: 'Revit' },\\n      { logo: 'https://framerusercontent.com/images/b9H0heLoBXBa6YWgZSZxO9vXeY.png', name: 'SketchUp', ext: '.skp', alt: 'SketchUp' },\\n      { logo: 'https://framerusercontent.com/images/Cgef2NhvAZLkZdo2XH2RLxPegc.png', name: 'AutoCAD', ext: '.dwg', alt: 'AutoCAD' }\\n    ];\\n    var i = 0, busy = false, timer = null, calloutRoot = document.getElementById('fmt-callout');\\n\\n    function next() {\\n      if (busy || document.hidden) return;\\n      busy = true;\\n      wrap.classList.add('is-cycling');\\n      setTimeout(function () {\\n        i = (i + 1) % formats.length;\\n        var f = formats[i];\\n        logo.src = f.logo;\\n        logo.alt = f.alt;\\n        name.textContent = f.name;\\n        ext.textContent = f.ext;\\n        wrap.classList.remove('is-cycling');\\n        busy = false;\\n      }, 380);\\n    }\\n\\n    function start() { if (!timer) timer = setInterval(next, 3200); }\\n    function stop() { if (timer) { clearInterval(timer); timer = null; } }\\n\\n    if (calloutRoot && 'IntersectionObserver' in window) {\\n      var coIo = new IntersectionObserver(function (entries) {\\n        entries.forEach(function (e) { e.isIntersecting ? start() : stop(); });\\n      }, { threshold: 0.2 });\\n      coIo.observe(calloutRoot);\\n    } else {\\n      start();\\n    }\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     9. Flip-clock — Revit / SketchUp / AutoCAD in how-it-works heading\\n  --------------------------------------------------------------------- */\\n  (function formatFlip() {\\n    var root = document.getElementById('format-flip');\\n    if (!root || reduce) return;\\n    var word = root.querySelector('.flip-txt__word');\\n    if (!word) return;\\n\\n    var words = ['Revit.', 'SketchUp.', 'AutoCAD.'];\\n    var i = 0, busy = false, timer = null;\\n\\n    function cycle() {\\n      if (busy || document.hidden) return;\\n      busy = true;\\n      root.classList.add('is-out');\\n      setTimeout(function () {\\n        i = (i + 1) % words.length;\\n        word.textContent = words[i];\\n        root.classList.remove('is-out');\\n        root.classList.add('is-in');\\n        setTimeout(function () {\\n          root.classList.remove('is-in');\\n          busy = false;\\n        }, 420);\\n      }, 420);\\n    }\\n\\n    function start() { if (!timer) timer = setInterval(cycle, 3000); }\\n    function stop() { if (timer) { clearInterval(timer); timer = null; } }\\n\\n    if ('IntersectionObserver' in window) {\\n      var flipIo = new IntersectionObserver(function (entries) {\\n        entries.forEach(function (e) { e.isIntersecting ? start() : stop(); });\\n      }, { threshold: 0.3 });\\n      flipIo.observe(root);\\n    } else {\\n      start();\\n    }\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     10. Mobile menu — burger toggles the glass sheet; closes on link tap,\\n         Escape, or resizing up to desktop.\\n  --------------------------------------------------------------------- */\\n  (function mobileMenu() {\\n    var burger = document.getElementById('burger');\\n    var mnav = document.getElementById('mnav');\\n    if (!burger || !mnav) return;\\n    var focusables = function () {\\n      return mnav.querySelectorAll('a, button, [tabindex]:not([tabindex=\\\"-1\\\"])');\\n    };\\n\\n    function setOpen(open) {\\n      nav.classList.toggle('menu-open', open);\\n      document.body.classList.toggle('menu-open', open);\\n      burger.setAttribute('aria-expanded', open ? 'true' : 'false');\\n      if (open) {\\n        var first = focusables()[0];\\n        if (first) first.focus();\\n      } else {\\n        burger.focus();\\n      }\\n    }\\n    burger.addEventListener('click', function () {\\n      setOpen(!nav.classList.contains('menu-open'));\\n    });\\n    mnav.addEventListener('click', function (ev) {\\n      if (ev.target.closest('a')) setOpen(false);\\n    });\\n    mnav.addEventListener('keydown', function (ev) {\\n      if (ev.key !== 'Tab' || !nav.classList.contains('menu-open')) return;\\n      var items = focusables();\\n      if (!items.length) return;\\n      var first = items[0];\\n      var last = items[items.length - 1];\\n      if (ev.shiftKey && document.activeElement === first) {\\n        ev.preventDefault();\\n        last.focus();\\n      } else if (!ev.shiftKey && document.activeElement === last) {\\n        ev.preventDefault();\\n        first.focus();\\n      }\\n    });\\n    document.addEventListener('keydown', function (ev) {\\n      if (ev.key === 'Escape') setOpen(false);\\n    });\\n    window.addEventListener('resize', function () {\\n      if (window.innerWidth > 960) setOpen(false);\\n    }, { passive: true });\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     10b. Desktop \\\"More\\\" dropdown — click/tap toggle, closes on outside\\n          click, Escape, or resize to mobile.\\n  --------------------------------------------------------------------- */\\n  (function navMoreMenu() {\\n    var wrap = document.getElementById('nav-more');\\n    var btn = document.getElementById('nav-more-btn');\\n    var drop = document.getElementById('nav-more-drop');\\n    if (!wrap || !btn || !drop) return;\\n\\n    function setOpen(open) {\\n      wrap.classList.toggle('is-open', open);\\n      btn.setAttribute('aria-expanded', open ? 'true' : 'false');\\n    }\\n\\n    btn.addEventListener('click', function (ev) {\\n      ev.stopPropagation();\\n      setOpen(!wrap.classList.contains('is-open'));\\n    });\\n    drop.addEventListener('click', function () { setOpen(false); });\\n    document.addEventListener('click', function (ev) {\\n      if (!wrap.contains(ev.target)) setOpen(false);\\n    });\\n    document.addEventListener('keydown', function (ev) {\\n      if (ev.key === 'Escape') setOpen(false);\\n    });\\n    window.addEventListener('resize', function () {\\n      if (window.innerWidth <= 960) setOpen(false);\\n    }, { passive: true });\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     11. Pricing calculator\\n  --------------------------------------------------------------------- */\\n  (function priceCalc() {\\n    var range = document.getElementById('calc-range');\\n    var sqft = document.getElementById('calc-sqft');\\n    var total = document.getElementById('calc-total');\\n    var minNote = document.getElementById('calc-min-note');\\n    var slideHint = document.getElementById('calc-slide-hint');\\n    if (!range || !sqft || !total) return;\\n\\n    function dismissSlideHint() {\\n      if (slideHint) slideHint.classList.add('is-dismissed');\\n    }\\n\\n    var RATE = 0.2;\\n    var MIN_ORDER = 50;\\n    var MIN_SQFT = 250;\\n\\n    function update() {\\n      var n = parseInt(range.value, 10) || 0;\\n      sqft.textContent = n.toLocaleString('en-US');\\n      var raw = Math.round(n * RATE);\\n      var cost = Math.max(MIN_ORDER, raw);\\n      total.textContent = '$' + cost.toLocaleString('en-US');\\n      if (minNote) minNote.hidden = n >= MIN_SQFT;\\n    }\\n\\n    range.addEventListener('input', function () {\\n      dismissSlideHint();\\n      update();\\n    });\\n    range.addEventListener('pointerdown', dismissSlideHint, { once: true });\\n    update();\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     13. Pause marquee when off-screen\\n  --------------------------------------------------------------------- */\\n  (function marqueePause() {\\n    var track = document.querySelector('.marquee__track');\\n    var wrap = document.querySelector('.marquee');\\n    if (!track || !wrap || !('IntersectionObserver' in window)) return;\\n    var io = new IntersectionObserver(function (entries) {\\n      entries.forEach(function (e) {\\n        track.style.animationPlayState = e.isIntersecting ? 'running' : 'paused';\\n      });\\n    }, { threshold: 0.05 });\\n    io.observe(wrap);\\n  }());\\n\\n  /* ---------------------------------------------------------------------\\n     14. Cursor dot trail — fine pointers only\\n  --------------------------------------------------------------------- */\\n  (function cursorTrail() {\\n    if (!isHome || reduce || !window.matchMedia('(hover:hover) and (pointer:fine)').matches) return;\\n\\n    var COUNT = 6;\\n    var container = document.createElement('div');\\n    container.className = 'cursor-trail';\\n    container.setAttribute('aria-hidden', 'true');\\n    document.body.appendChild(container);\\n\\n    var dots = [];\\n    var positions = [];\\n    var i;\\n    for (i = 0; i < COUNT; i++) {\\n      var dot = document.createElement('span');\\n      dot.className = 'cursor-trail__dot' + (i === 0 ? ' cursor-trail__dot--lead' : '');\\n      container.appendChild(dot);\\n      dots.push(dot);\\n      positions.push({ x: -120, y: -120 });\\n    }\\n\\n    var mouse = { x: -120, y: -120 };\\n    var visible = false;\\n    var initialized = false;\\n    var running = false;\\n\\n    function frame() {\\n      positions[0].x += (mouse.x - positions[0].x) * 0.42;\\n      positions[0].y += (mouse.y - positions[0].y) * 0.42;\\n\\n      for (i = 1; i < COUNT; i++) {\\n        var ease = Math.max(0.16, 0.36 - i * 0.03);\\n        positions[i].x += (positions[i - 1].x - positions[i].x) * ease;\\n        positions[i].y += (positions[i - 1].y - positions[i].y) * ease;\\n      }\\n\\n      for (i = 0; i < COUNT; i++) {\\n        var scale = Math.max(0.45, 1 - i * 0.09);\\n        var opacity = visible ? Math.max(0, 0.85 - i * 0.12) : 0;\\n        dots[i].style.opacity = opacity.toFixed(3);\\n        dots[i].style.transform =\\n          'translate3d(' + positions[i].x.toFixed(2) + 'px,' + positions[i].y.toFixed(2) + 'px,0) ' +\\n          'translate(-50%,-50%) scale(' + scale.toFixed(3) + ')';\\n      }\\n\\n      if (visible && !document.hidden) {\\n        requestAnimationFrame(frame);\\n      } else {\\n        running = false;\\n      }\\n    }\\n\\n    function start() {\\n      if (running) return;\\n      running = true;\\n      requestAnimationFrame(frame);\\n    }\\n\\n    document.addEventListener('mousemove', function (e) {\\n      mouse.x = e.clientX;\\n      mouse.y = e.clientY;\\n      if (!initialized) {\\n        for (i = 0; i < COUNT; i++) {\\n          positions[i].x = e.clientX;\\n          positions[i].y = e.clientY;\\n        }\\n        initialized = true;\\n      }\\n      if (!visible) visible = true;\\n      start();\\n    }, { passive: true });\\n\\n    document.addEventListener('mouseleave', function () {\\n      visible = false;\\n    });\\n\\n    document.addEventListener('visibilitychange', function () {\\n      if (document.hidden) visible = false;\\n    });\\n  }());\\n}());\\n\";/**\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n * @framerIntrinsicWidth 1440\n */export default function ScanbrixSiteFooter(){const started=useRef(false);useEffect(()=>{if(started.current)return;started.current=true;try{new Function(js)();}catch(error){console.error(\"Scanbrix page script failed\",error);}},[]);return /*#__PURE__*/_jsx(\"div\",{style:{width:\"100%\"},dangerouslySetInnerHTML:{__html:html}});}\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"ScanbrixSiteFooter\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerSupportedLayoutHeight\":\"any-prefer-fixed\",\"framerIntrinsicWidth\":\"1440\",\"framerSupportedLayoutWidth\":\"any-prefer-fixed\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./ScanbrixSiteFooter.map","// Generated by Framer (0116799)\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{addFonts,ComponentViewportProvider,Container,cx,GeneratedComponentContext,getFonts,RenderTarget,useCustomCursors,useHydratedBreakpointVariants,useIsOnFramerCanvas,useLocaleInfo,withCSS}from\"framer\";import{LayoutGroup,motion}from\"framer-motion\";import*as React from\"react\";import{useRef}from\"react\";import Cursor from\"#framer/local/canvasComponent/vh_nMD40O/vh_nMD40O.js\";import ScanbrixChrome from\"#framer/local/codeFile/cUGpnNy/ScanbrixChrome.js\";import ScanbrixSiteFooter from\"#framer/local/codeFile/yf_qcqL/ScanbrixSiteFooter.js\";const ScanbrixChromeFonts=getFonts(ScanbrixChrome);const ScanbrixSiteFooterFonts=getFonts(ScanbrixSiteFooter);const CursorFonts=getFonts(Cursor);const breakpoints={AsxOrhbRb:\"(min-width: 750px) and (max-width: 1299.98px)\",H7kz2U8Bz:\"(max-width: 749.98px)\",zX55Yfv8l:\"(min-width: 1300px)\"};const isBrowser=()=>typeof document!==\"undefined\";const serializationHash=\"framer-i4OpE\";const variantClassNames={AsxOrhbRb:\"framer-v-1g0itah\",H7kz2U8Bz:\"framer-v-ci0gsn\",zX55Yfv8l:\"framer-v-a76y4f\"};const breakpointRules={H7kz2U8Bz:[\".framer-i4OpE.framer-a76y4f { padding: 0px 0px 20px 0px; }\"]};const breakpointKeys=Object.keys(breakpointRules);const selectors={H7kz2U8Bz:\".framer-ci0gsn-override\"};const rules=[\".framer-i4OpE.framer-7wofot, .framer-i4OpE .framer-7wofot { display: block; }\",\".framer-i4OpE.framer-a76y4f { align-content: center; align-items: center; background-color: var(--token-a36d64c4-7dd2-4634-9c85-c24f13463c3f, #ffffff); display: flex; flex-direction: column; flex-wrap: nowrap; gap: 10px; height: min-content; justify-content: flex-start; overflow: var(--overflow-clip-fallback, clip); padding: 0px 0px 2px 0px; position: relative; width: 100%; }\",\".framer-i4OpE .framer-leli1m-container { flex: none; height: auto; order: -1000; position: relative; width: 100%; }\",\".framer-i4OpE .framer-coebst { background: transparent; flex-grow: 1; height: 0px; margin: 0px; margin-bottom: -10px; position: relative; width: 0px; }\",\".framer-i4OpE .framer-18svx11-container { flex: none; height: auto; order: 1003; position: relative; width: 100%; }\",'[data-layout-template=\"true\"] > #overlay { margin-bottom: -10px; }'];const mediaQueries={AsxOrhbRb:\"(min-width: 750px) and (max-width: 1299.98px)\",H7kz2U8Bz:\"(max-width: 749.98px)\",zX55Yfv8l:\"(min-width: 1300px)\"};const humanReadableVariantMap={Desktop:\"zX55Yfv8l\",Phone:\"H7kz2U8Bz\",Tablet:\"AsxOrhbRb\"};const HTMLStyle=({value})=>{const onCanvas=useIsOnFramerCanvas();if(onCanvas)return null;return /*#__PURE__*/_jsx(\"style\",{dangerouslySetInnerHTML:{__html:value},\"data-framer-html-style\":\"\"});};const getProps=({height,id,width,...props})=>{return{...props,variant:humanReadableVariantMap[props.variant]??props.variant??\"zX55Yfv8l\"};};const transition1={bounce:.3,delay:0,duration:.6,type:\"spring\"};const cursor={alignment:\"center\",component:Cursor,offset:{x:25,y:25},placement:\"bottom\",transition:transition1,variant:\"LjPzaZG89\"};const Component=/*#__PURE__*/React.forwardRef(function(props,ref){const fallbackRef=useRef(null);const refBinding=ref??fallbackRef;const defaultLayoutId=React.useId();const{activeLocale,setLocale}=useLocaleInfo();const{style,className,layoutId,variant,children,...restProps}=getProps(props);const[baseVariant,hydratedBaseVariant]=useHydratedBreakpointVariants(variant,breakpoints,false);const gestureVariant=undefined;const sharedStyleClassNames=[];const scopingClassNames=cx(serializationHash,...sharedStyleClassNames);useCustomCursors({uffksn:cursor});return /*#__PURE__*/_jsx(GeneratedComponentContext.Provider,{value:{activeVariantId:baseVariant,humanReadableVariantMap,isLayoutTemplate:true,primaryVariantId:\"zX55Yfv8l\",variantClassNames},children:/*#__PURE__*/_jsxs(LayoutGroup,{id:layoutId??defaultLayoutId,children:[/*#__PURE__*/_jsx(HTMLStyle,{value:\":root body { background: var(--token-a36d64c4-7dd2-4634-9c85-c24f13463c3f, rgb(255, 255, 255)); }\"}),/*#__PURE__*/_jsxs(motion.div,{...restProps,className:cx(scopingClassNames,\"framer-a76y4f\",className),\"data-framer-cursor\":\"uffksn\",\"data-layout-template\":true,ref:refBinding,style:{...style},children:[/*#__PURE__*/_jsx(ComponentViewportProvider,{children:/*#__PURE__*/_jsx(Container,{className:\"framer-leli1m-container\",\"data-code-component-plugin-id\":\"api\",\"data-framer-name\":\"ScanbrixChromeV3\",isAuthoredByUser:true,name:\"ScanbrixChromeV3\",nodeId:\"z18fHi92y\",scopeId:\"lOqVnEz02\",children:/*#__PURE__*/_jsx(ScanbrixChrome,{height:\"100%\",id:\"z18fHi92y\",layoutId:\"z18fHi92y\",name:\"ScanbrixChromeV3\",style:{width:\"100%\"},width:\"100%\"})})}),children,/*#__PURE__*/_jsx(\"div\",{className:\"framer-coebst\"}),/*#__PURE__*/_jsx(ComponentViewportProvider,{children:/*#__PURE__*/_jsx(Container,{className:\"framer-18svx11-container\",\"data-code-component-plugin-id\":\"api\",\"data-framer-name\":\"ScanbrixFooterV3\",isAuthoredByUser:true,name:\"ScanbrixFooterV3\",nodeId:\"DCTZOrKui\",scopeId:\"lOqVnEz02\",children:/*#__PURE__*/_jsx(ScanbrixSiteFooter,{height:\"100%\",id:\"DCTZOrKui\",layoutId:\"DCTZOrKui\",name:\"ScanbrixFooterV3\",style:{width:\"100%\"},width:\"100%\"})})})]}),/*#__PURE__*/_jsx(\"div\",{id:\"template-overlay\"})]})});});const css=target=>{const isStaticRenderer=target===RenderTarget.canvas||target===RenderTarget.export;if(!isStaticRenderer){return[...rules,...breakpointKeys.map(key=>{const query=mediaQueries[key];return`@media ${query} { ${breakpointRules[key].join(\" \")} }`;})];}return[...rules,...breakpointKeys.flatMap(key=>{const selector=selectors[key];return breakpointRules[key].map(rule=>`${selector} {${rule}}`);})];};/**\n * This is a generated Framer component.\n * @framerIntrinsicHeight 1300\n * @framerIntrinsicWidth 1300\n * @framerCanvasComponentVariantDetails {\"propertyName\":\"variant\",\"data\":{\"default\":{\"layout\":[\"fixed\",\"fixed\"]},\"AsxOrhbRb\":{\"layout\":[\"fixed\",\"fixed\"]},\"H7kz2U8Bz\":{\"layout\":[\"fixed\",\"fixed\"]}}}\n * @framerImmutableVariables true\n * @framerDisplayContentsDiv false\n * @framerAutoSizeImages true\n * @framerComponentViewportWidth true\n * @framerColorSyntax true\n * @framerHitTargets {\"zX55Yfv8l\":[\".framer-leli1m-container\",\".framer-18svx11-container\"],\"AsxOrhbRb\":[\".framer-leli1m-container\",\".framer-18svx11-container\"],\"H7kz2U8Bz\":[\".framer-leli1m-container\",\".framer-18svx11-container\"]}\n * @framerBreakpoints {\"zX55Yfv8l\":{\"min\":1300,\"canvasClassName\":\"framer-a76y4f-override\",\"minHeight\":1300,\"name\":\"Desktop\",\"width\":1300,\"rootFontSize\":16},\"AsxOrhbRb\":{\"min\":750,\"max\":1299,\"canvasClassName\":\"framer-1g0itah-override\",\"minHeight\":1739,\"viewportHeight\":1080,\"name\":\"Tablet\",\"width\":750,\"rootFontSize\":16},\"H7kz2U8Bz\":{\"max\":749,\"canvasClassName\":\"framer-ci0gsn-override\",\"minHeight\":1739,\"viewportHeight\":844,\"name\":\"Phone\",\"width\":390,\"rootFontSize\":16}}\n * @framerDefaultVariant zX55Yfv8l\n * @framerLayoutTemplate true\n */const FramerlOqVnEz02=withCSS(Component,css,\"framer-i4OpE\");export default FramerlOqVnEz02;FramerlOqVnEz02.displayName=\"Default\";FramerlOqVnEz02.defaultProps={height:1300,width:1300};addFonts(FramerlOqVnEz02,[{explicitInter:true,fonts:[]},...ScanbrixChromeFonts,...ScanbrixSiteFooterFonts,...CursorFonts],{supportsExplicitInterCodegen:true});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"FramerlOqVnEz02\",\"slots\":[],\"annotations\":{\"framerCanvasComponentVariantDetails\":\"{\\\"propertyName\\\":\\\"variant\\\",\\\"data\\\":{\\\"default\\\":{\\\"layout\\\":[\\\"fixed\\\",\\\"fixed\\\"]},\\\"AsxOrhbRb\\\":{\\\"layout\\\":[\\\"fixed\\\",\\\"fixed\\\"]},\\\"H7kz2U8Bz\\\":{\\\"layout\\\":[\\\"fixed\\\",\\\"fixed\\\"]}}}\",\"framerDisplayContentsDiv\":\"false\",\"framerColorSyntax\":\"true\",\"framerImmutableVariables\":\"true\",\"framerIntrinsicWidth\":\"1300\",\"framerAutoSizeImages\":\"true\",\"framerLayoutTemplate\":\"true\",\"framerContractVersion\":\"1\",\"framerBreakpoints\":\"{\\\"zX55Yfv8l\\\":{\\\"min\\\":1300,\\\"canvasClassName\\\":\\\"framer-a76y4f-override\\\",\\\"minHeight\\\":1300,\\\"name\\\":\\\"Desktop\\\",\\\"width\\\":1300,\\\"rootFontSize\\\":16},\\\"AsxOrhbRb\\\":{\\\"min\\\":750,\\\"max\\\":1299,\\\"canvasClassName\\\":\\\"framer-1g0itah-override\\\",\\\"minHeight\\\":1739,\\\"viewportHeight\\\":1080,\\\"name\\\":\\\"Tablet\\\",\\\"width\\\":750,\\\"rootFontSize\\\":16},\\\"H7kz2U8Bz\\\":{\\\"max\\\":749,\\\"canvasClassName\\\":\\\"framer-ci0gsn-override\\\",\\\"minHeight\\\":1739,\\\"viewportHeight\\\":844,\\\"name\\\":\\\"Phone\\\",\\\"width\\\":390,\\\"rootFontSize\\\":16}}\",\"framerDefaultVariant\":\"zX55Yfv8l\",\"framerIntrinsicHeight\":\"1300\",\"framerHitTargets\":\"{\\\"zX55Yfv8l\\\":[\\\".framer-leli1m-container\\\",\\\".framer-18svx11-container\\\"],\\\"AsxOrhbRb\\\":[\\\".framer-leli1m-container\\\",\\\".framer-18svx11-container\\\"],\\\"H7kz2U8Bz\\\":[\\\".framer-leli1m-container\\\",\\\".framer-18svx11-container\\\"]}\",\"framerComponentViewportWidth\":\"true\"}},\"Props\":{\"type\":\"tsType\",\"annotations\":{\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}","\r\n\t\timport * as Framer from \"framer\";\r\nimport * as React from \"react\";\r\nimport { createPortal } from \"react-dom\";\r\nimport * as ReactDOM from \"react-dom/client\";\r\nimport Default from \"https://framerusercontent.com/modules/fZU8AlZfdY4TcnzlrdfC/WQFa19iWBhK9a71YWLM5/lOqVnEz02.js\";\r\n\r\n\t\tconst routes = {augiA20Il: {elements: {aNhrYQAUd: \"deliverables\", c4T_fajnv: \"features\", Cds0hnuNg: \"whocard\", DSsAS1UqA: \"scroll\", F_DIQdDJq: \"testimonials\", G5FiEQLeR: \"pricing\", pN0FJm1mp: \"who\", qdMgjzacB: \"faq\", rAKoVb_q1: \"1st-feature\", s5Smr04Jt: \"3rd-feature\", ShUqGyos9: \"how\", Ve3A0I24m: \"why\", Xkm7_7XOX: \"hero\", XWloZplXF: \"2nd-feature\", YhVeppZea: \"top\", zCnxyawu3: \"phoneui\", zHKXY4bgM: \"blog\"}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/lcvMOmZiSzolor2UJFzW/ZWeGaKgiuQ003trqK3nE/augiA20Il.js\")), path: \"/\"}, N2BfaAgBP: {elements: {iiW5YbAZN: \"features\"}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/u949A4lEAz4a6V6n1Y4H/HTsLSvomOFtyh0nPyQb4/N2BfaAgBP.js\")), path: \"/faqs\"}, wB2tJhBMg: {elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/9ypRzD5C9MnlqAnbWjRY/h3UriqI7sN0Kx1bl8h7l/wB2tJhBMg.js\")), path: \"/blog\"}, Z2sSGjPf7: {elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/edJGJ3FUIMdvSCD8vj1Z/1xcwKv0GPS43oO4Hu0xs/Z2sSGjPf7.js\")), path: \"/contact\"}, Qc8hO7wz5: {elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/hCU0PxjOr6yuuQaJjIh6/ODYmWJg0qC1Z5nQDNm1Q/Qc8hO7wz5.js\")), path: \"/404\"}, GZ63vNIX4: {elements: {MgKa6XYCW: \"why-us\", oyK6gipB5: \"how\"}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/32QFVSS0mXyd8b8XaQLg/vREBV9IpRjI1TNZWXnjf/GZ63vNIX4.js\")), path: \"/resource\"}, npLCoxtnp: {collectionId: \"uqb13jOmJ\", elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/2fJxvaPVKeYYApbGTeYI/BtnjykKwVoLZRmUoMTZb/npLCoxtnp.js\")), path: \"/blog/:A96Q6Lyrb\"}, dJ2Dh9wMu: {collectionId: \"D6Jv8eHMW\", elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/yGDOqbeiQHXZZKKVLkSH/A84n9wWhYiU93KK3AHVP/dJ2Dh9wMu.js\")), path: \"/blog/author/:Vj69P8Tfp\"}, wNyk5UC94: {collectionId: \"lGl2ckGPd\", elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/xTgJJ8gcvg93uSH1pKGx/z29supYPoXcb0J0hTXwb/wNyk5UC94.js\")), path: \"/blog/categories/:KKhi0f4p9\"}, RLpx6cNlW: {collectionId: \"HO_a4fmPS\", elements: {}, page: Framer.lazy(() => import(\"https://framerusercontent.com/modules/v0z9IGoXtMTnc3xziehk/uC93vgnPQi4JSPuGMlEm/RLpx6cNlW.js\")), path: \"/legal/:s4BGRi0Ij\"}}\r\n\r\n\t\tconst locales = [{code: \"en-US\", id: \"default\", name: \"English\", slug: \"\", textDirection: \"ltr\"}]\r\n\t\tconst collectionUtils = {D6Jv8eHMW: async () => (await import(\"https://framerusercontent.com/modules/aX7QCvOzbKTEJhlfMCYj/VT1CdKdrpAk4YGS5Hb9h/D6Jv8eHMW.js\"))?.[\"utils\"], HO_a4fmPS: async () => (await import(\"https://framerusercontent.com/modules/kdkvMufYqW81iGAtCfsG/qHPkX6pWutOkLDADAley/HO_a4fmPS.js\"))?.[\"utils\"], lGl2ckGPd: async () => (await import(\"https://framerusercontent.com/modules/5twZPt7aftxpm006XAkX/TbGtDsHA3B3TU0pVx3QB/lGl2ckGPd.js\"))?.[\"utils\"], uqb13jOmJ: async () => (await import(\"https://framerusercontent.com/modules/xUMSWFWLcwc0Kzao5l5U/p3b7jghrSXbcMDOtaJbe/uqb13jOmJ.js\"))?.[\"utils\"]}\r\n\t\tconst framerSiteId = \"58260d1f2edd124a7de0b698d37b4dffc86061ecf361828bb4b3b76fffda9662\"\r\n\t\tfunction Template({webPageId, children, style, ...rest}) {const templateProps = {}\r\nconst props = templateProps[webPageId] ?? {}\r\nswitch (webPageId) {case \"augiA20Il\":\r\ncase \"N2BfaAgBP\":\r\ncase \"wB2tJhBMg\":\r\ncase \"Z2sSGjPf7\":\r\ncase \"Qc8hO7wz5\":\r\ncase \"H_JJGui2h\":\r\ncase \"GZ63vNIX4\":\r\ncase \"npLCoxtnp\":\r\ncase \"dJ2Dh9wMu\":\r\ncase \"wNyk5UC94\":\r\ncase \"RLpx6cNlW\":\r\nreturn React.createElement(Default, {...props, key: \"Default\", style}, children(true));\r\ndefault: { return children(false) }}}\r\nexport function getLayoutTemplateBreakpoints(routeId) {switch (routeId) {case \"augiA20Il\":\r\ncase \"N2BfaAgBP\":\r\ncase \"wB2tJhBMg\":\r\ncase \"Z2sSGjPf7\":\r\ncase \"Qc8hO7wz5\":\r\ncase \"H_JJGui2h\":\r\ncase \"GZ63vNIX4\":\r\ncase \"npLCoxtnp\":\r\ncase \"dJ2Dh9wMu\":\r\ncase \"wNyk5UC94\":\r\ncase \"RLpx6cNlW\":\r\nreturn [{hash: \"a76y4f\", mediaQuery: \"(min-width: 1300px)\"}, {hash: \"1g0itah\", mediaQuery: \"(min-width: 750px) and (max-width: 1299.98px)\"}, {hash: \"ci0gsn\", mediaQuery: \"(max-width: 749.98px)\"}]\r\ndefault: { return undefined }}}\r\n\r\n\t\tconst isBrowser = typeof document !== \"undefined\"\r\n\t\tconst isBot = isBrowser && /bot|-google|google-|yandex|ia_archiver|crawl|spider/iu.test(navigator.userAgent)\r\n\r\n\t\texport async function getPageRoot({ routeId, pathVariables, localeId, collectionItemId }) {\r\n\t\t\tconst rootPreload = routes[routeId].page.preload()\r\n\r\n\t\t\tFramer.setLibraryFeatures({disableCustomCode: false, editorBarDisableFrameAncestorsSecurity: false, motionDivToDiv: false, onPageLocalizationSupport: true, onPageMoveTool: true, onPageRichTextBlockSelection: true, privateRouterReplaceState: true, scrollRestoration: true, synchronousNavigationOnDesktop: false, yieldOnTap: false})\r\n\r\n\t\t\tconst content = React.createElement(\r\n\t\t\t\tFramer.PageRoot,\r\n\t\t\t\t{\r\n\t\t\t\t\tisWebsite: true,\r\n\t\t\t\t\tenvironment: \"site\",\r\n\t\t\t\t\trouteId,\r\n\t\t\t\t\tpathVariables,\r\n\t\t\t\t\troutes,\r\n\t\t\t\t\tcollectionUtils,\r\n\t\t\t\t\tframerSiteId,\r\n\t\t\t\t\tnotFoundPage: Framer.lazy(() => import(\"https://framerusercontent.com/modules/hCU0PxjOr6yuuQaJjIh6/ODYmWJg0qC1Z5nQDNm1Q/Qc8hO7wz5.js\")),\r\n\t\t\t\t\tisReducedMotion: undefined,\r\n\t\t\t\t\tlocaleId,\r\n\t\t\t\t\tlocales,\r\n\t\t\t\t\tpreserveQueryParams: true,\r\n\t\t\t\t\tsiteCanonicalURL: \"https://www.scanbrix.com\",\r\n\t\t\t\t\tEditorBar: \r\n\t\t\ttypeof window !== \"undefined\" ? (() => {\r\n\t\t\t\tif (isBot) {\r\n\t\t\t\t\tconsole.log(\"[Framer On-Page Editing] Unavailable because navigator is bot\")\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Framer.lazy(async () => {\r\n\t\t\t\t\tconst dependencies = {\r\n\t\t\t\t\t\t__version: 3,\r\n\t\t\t\t\t\tframer: {\r\n\t\t\t\t\t\t\tuseCurrentRoute: Framer.useCurrentRoute,\r\n\t\t\t\t\t\t\tuseLocaleInfo: Framer.useLocaleInfo,\r\n\t\t\t\t\t\t\tuseRouter: Framer.useRouter,\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\treact: {\r\n\t\t\t\t\t\t\tcreateElement: React.createElement,\r\n\t\t\t\t\t\t\tFragment: React.Fragment,\r\n\t\t\t\t\t\t\tmemo: React.memo,\r\n\t\t\t\t\t\t\tuseCallback: React.useCallback,\r\n\t\t\t\t\t\t\tuseEffect: React.useEffect,\r\n\t\t\t\t\t\t\tuseRef: React.useRef,\r\n\t\t\t\t\t\t\tuseState: React.useState,\r\n\t\t\t\t\t\t\tuseLayoutEffect: React.useLayoutEffect,\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"react-dom\": { createPortal },\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\twindow.__framer_editorBarDependencies = dependencies\r\n\r\n\t\t\t\t\tconst { createEditorBar } = await import(\"https://framer.com/edit/init.mjs\")\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tdefault: createEditorBar(),\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t})() : undefined\r\n\t\t,\r\n\t\t\t\t\tadaptLayoutToTextDirection: false,\r\n\t\t\t\t\tLayoutTemplate: Template,\r\n\t\t\t\t\tloadSnippetsModule: new Framer.LazyValue(() => import(\"https://framerusercontent.com/modules/LukJ1TWuwW5T5wggdHIX/7s4YazDdx6zQUUqbdGKw/snippets.js\")),\r\n\t\t\t\t\tinitialCollectionItemId: collectionItemId,\r\n\t\t\t\t}\r\n\t\t\t)\r\n\r\n\t\t\tconst contentWithGracefullyDegradingErrorBoundary = React.createElement(Framer.GracefullyDegradingErrorBoundary, {\r\n\t\t\t\tchildren: content\r\n\t\t\t})\r\n\r\n\t\t\t\r\n\t\t\tconst page = React.createElement(Framer.PageEffectsProvider, {\r\n\t\t\t\tchildren: contentWithGracefullyDegradingErrorBoundary,\r\n\t\t\t\tvalue: {global: {enter: {mask: {angle: 90, type: \"wipe\", width: \"100%\"}, opacity: 1, rotate: 0, rotate3d: false, rotateX: 0, rotateY: 0, scale: 1, transition: {damping: 30, delay: 0, duration: 0.4, ease: [0.27, 0, 0.51, 1], mass: 1, stiffness: 400, type: \"tween\"}, x: \"0px\", y: \"0px\"}}, routes: {}}\r\n\t\t\t})\r\n\r\n\t\t\t// We don't want the initial render to immediately have to suspend.\r\n\t\t\tawait rootPreload\r\n\t\t\treturn page\r\n\t\t}\r\n\r\n\t\tif (isBrowser) {\r\n\t\t\t// Note: HTTPArchive also uses this function to detect Framer sites; see https://github.com/HTTPArchive/wappalyzer/blob/371a17583f74fd9171b9077f59a5619b24062891/src/technologies/f.json#L1722-L1748.\r\n\t\t\twindow.__framer_importFromPackage = (packageAndFilename, exportIdentifier) => () => {\r\n\t\t\t\treturn React.createElement(Framer.ErrorPlaceholder, { error: 'Package component not supported: \"' + exportIdentifier + '\" in \"' + packageAndFilename + '\"' })\r\n\t\t\t}\r\n\r\n\t\t\t\r\n\t\t\t\r\n\t\t\twindow.__framer_events = window.__framer_events || []\r\n\r\n\t\t\t// Initialize lazy modules cache for hydration\r\n\t\t\tFramer.initLazyModulesCache()\r\n\r\n\t\t\tconst container = document.getElementById(\"main\")\r\n\t\t\t// We know that #main is parsed before this script, so we don't need to wait for DOMContentLoaded or similar events.\r\n\t\t\tif (\"framerHydrateV2\" in container.dataset) main(true, container)\r\n\t\t\telse main(false, container)\r\n\t\t}\r\n\r\n\t\tfunction track() {\r\n\t\t\tif (!isBrowser) return\r\n\t\t\twindow.__framer_events.push(arguments)\r\n\t\t}\r\n\r\n\t\tasync function main(shouldHydrate, container) {\r\n\t\t\tfunction handleError(error, errorInfo, recoverable = true) {\r\n\t\t\t\tif (error.caught || window.__framer_hadFatalError) return // we already logged it\r\n\r\n\t\t\t\tconst componentStack = errorInfo?.componentStack\r\n\t\t\t\tif (recoverable) {\r\n\t\t\t\t\tconsole.warn(\"Caught a recoverable error. The site is still functional, but might have some UI flickering or degraded page load performance. If you are the author of this website, update external components and check recently added custom code or code overrides to fix the following server/client mismatches:\\n\", error, componentStack)\r\n\t\t\t\t\t// we only want to collect 1%, because this can be quite noisy (floods the data pipeline)\r\n\t\t\t\t\tif (Math.random() > 0.01) return\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconsole.error(\"Caught a fatal error. Please report the following to the Framer team via https://www.framer.com/contact/:\\n\", error, componentStack)\r\n\t\t\t\t}\r\n\t\t\t\ttrack(recoverable ? \"published_site_load_recoverable_error\" : \"published_site_load_error\", {\r\n\t\t\t\t\tmessage: String(error),\r\n\t\t\t\t\tcomponentStack, // componentStack is more useful\r\n\t\t\t\t\tstack: componentStack ? undefined : error instanceof Error && typeof error.stack === \"string\" ? error.stack : null,\r\n\t\t\t\t})\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\tlet routeId, localeId, pathVariables, breakpoints, routeData\r\n\t\t\t\tif (shouldHydrate) {\r\n\t\t\t\t\trouteData = JSON.parse(container.dataset[\"framerHydrateV2\"])\r\n\t\t\t\t\trouteId = routeData.routeId\r\n\t\t\t\t\tlocaleId = routeData.localeId\r\n\t\t\t\t\tpathVariables = routeData.pathVariables\r\n\t\t\t\t\tbreakpoints = routeData.breakpoints\r\n\r\n\t\t\t\t\trouteId = Framer.patchRoutesForABTesting(routes, routeId) // Prioritize optimized route id to avoid flickering in browsers not supporting the server-timing header (Safari older than 16.4)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tFramer.patchRoutesForABTesting(routes, undefined) // This must happen before inferInitialRouteFromPath\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t\tconst serverRouteExperimentEnabled = true\r\n\t\t\t\t\tconst serverRoute = serverRouteExperimentEnabled && performance.getEntriesByType(\"navigation\")[0]?.serverTiming?.find(e => e.name === \"route\")?.description\r\n\t\t\t\t\tif (serverRoute) {\r\n\t\t\t\t\t\tconst routeData = new URLSearchParams(serverRoute)\r\n\t\t\t\t\t\trouteId = routeData.get(\"id\")\r\n\t\t\t\t\t\tlocaleId = routeData.get(\"locale\")\r\n\t\t\t\t\t\tfor (const [key, value] of routeData.entries()) {\r\n\t\t\t\t\t\t\tif (!key.startsWith(\"var.\")) continue\r\n\t\t\t\t\t\t\tpathVariables ??= {}\r\n\t\t\t\t\t\t\tpathVariables[key.slice(4)] = value\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!routeId || !localeId) {\r\n\t\t\t\t\t\tconst routeData = Framer.inferInitialRouteFromPath(routes, decodeURIComponent(location.pathname), true, locales)\r\n\t\t\t\t\t\trouteId = routeData.routeId\r\n\t\t\t\t\t\tlocaleId = routeData.localeId\r\n\t\t\t\t\t\tpathVariables = routeData.pathVariables\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst pagePromise = getPageRoot({\r\n\t\t\t\t\trouteId,\r\n\t\t\t\t\tlocaleId,\r\n\t\t\t\t\tpathVariables,\r\n\t\t\t\t\tcollectionItemId: routeData?.collectionItemId,\r\n\t\t\t\t})\r\n\r\n\t\t\t\t\r\nif (typeof window !== \"undefined\") {\r\n\tvoid (async () => {\r\n\t\tconst route = routes[routeId]\r\n\r\n\t\tconst defaultLocaleId = \"default\"\r\n\t\tconst framerLocale = locales.find(({ id }) => !localeId ? id === defaultLocaleId : id === localeId).code\r\n\r\n\t\tlet collectionItemId = routeData?.collectionItemId ?? null\r\n\t\tif (collectionItemId === null && route?.collectionId && collectionUtils) {\r\n\t\t\t  const utils = await collectionUtils[route.collectionId]?.()\r\n\t\t\t  const [slug] = Object.values(pathVariables)\r\n\t\t\t  if (utils && typeof slug === \"string\") {\r\n\t\t\t\t  collectionItemId = (await utils.getRecordIdBySlug(slug, framerLocale || undefined)) ?? null\r\n\t\t\t  }\r\n\t\t}\r\n\r\n\t\tconst resolvedDateTimeOptions = Intl.DateTimeFormat().resolvedOptions()\r\n\t\tconst timezone = resolvedDateTimeOptions.timeZone\r\n\t\tconst locale = resolvedDateTimeOptions.locale\r\n\r\n\t\t// wait for the page to be activated before sending the pageview event\r\n\t\t// https://developer.chrome.com/docs/web-platform/prerender-pages#impact-on-analytics\r\n\t\tawait new Promise((resolve) => {\r\n\t\t\tif (document.prerendering) {\r\n\t\t\t\tdocument.addEventListener(\"prerenderingchange\", resolve, { once: true })\r\n\t\t\t} else {\r\n\t\t\t\tresolve()\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\twindow.__framer_events.push([\r\n\t\t\t\"published_site_pageview\",\r\n\t\t\t{\r\n\t\t\t\tframerSiteId,\r\n\t\t\t\tversion: 2,\r\n\t\t\t\troutePath: route?.path || \"/\",\r\n\t\t\t\tcollectionItemId,\r\n\t\t\t\tframerLocale: framerLocale || null,\r\n\t\t\t\twebPageId: route?.abTestingVariantId ?? routeId,\r\n\t\t\t\tabTestId: route?.abTestId,\r\n\t\t\t\treferrer: document.referrer || null,\r\n\t\t\t\turl: window.location.href,\r\n\t\t\t\thostname: window.location.hostname || null,\r\n\t\t\t\tpathname: window.location.pathname || null,\r\n\t\t\t\thash: window.location.hash || null,\r\n\t\t\t\tsearch: window.location.search || null,\r\n\t\t\t\ttimezone,\r\n\t\t\t\tlocale,\r\n\t\t\t},\r\n\t\t\t\"eager\"\r\n\t\t])\r\n\r\n\t\t// Yield to avoid blocking the main thread with the user code\r\n\t\tawait Framer.yieldToMain({ priority: \"background\", ensureContinueBeforeUnload: true, continueAfter: \"paint\" })\r\n\r\n\t\tdocument.dispatchEvent(new CustomEvent(\"framer:pageview\", {\r\n\t\t\tdetail: { framerLocale: framerLocale || null }\r\n\t\t}))\r\n\t})()\r\n}\r\n\r\n\r\n\t\t\t\tconst page = await pagePromise\r\n\t\t\t\tif (shouldHydrate) {\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t\tFramer.withPerformanceMarks(\"framer-rewrite-breakpoints\", () => {\r\n\t\t\t\t\t\tFramer.removeHiddenBreakpointLayersV2(breakpoints)\r\n\t\t\t\t\t\twindow.__framer_onRewriteBreakpoints?.(breakpoints)\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t\tconst startTransition = isBot ? cb => cb() : React.startTransition\r\n\t\t\t\t\tstartTransition(() => {\r\n\t\t\t\t\t\tFramer.markHydrationStart()\r\n\t\t\t\t\t\tFramer.turnOffReactEventHandling()\r\n\t\t\t\t\t\tReactDOM.hydrateRoot(container, page, { onRecoverableError: handleError })\r\n\t\t\t\t\t})\r\n\t\t\t\t} else {\r\n\t\t\t\t\t\r\n\t\t\t\t\tReactDOM.createRoot(container, { onRecoverableError: handleError }).render(page)\r\n\t\t\t\t}\r\n\t\t\t} catch (error) {\r\n\t\t\t\thandleError(error, undefined, false)\r\n\t\t\t\tthrow error\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t"],"mappings":"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"}