{"version":3,"file":"TaglineWrite.CDHH8B0_.mjs","names":["useRef","useState","useId"],"sources":["https:/framerusercontent.com/modules/xC1zBZEEyhzHyUHDrdFS/KscvWxBYjmvySkjAUldN/TaglineWrite.js"],"sourcesContent":["import{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useEffect,useId,useRef,useState}from\"react\";import{addPropertyControls,ControlType,useIsStaticRenderer}from\"framer\";import{useReducedMotion}from\"framer-motion\";/**\n * Tagline Write\n *\n * The footer tagline, \"Building forward /\". The slash is a cobalt \"/\" in the line's own font and acts as a caret:\n * when the line comes into view it sweeps left to right and the words appear behind it, then it rests at the end of\n * the line and (optionally) keeps blinking like a text cursor. The text is real text with the full tagline as its\n * accessible name. Reduced motion and the static render show it finished, with a solid slash.\n *\n * The line always fits its box: words, slash and a little space after the slash span the given share of the width\n * (Fit scale), at every breakpoint. The slash sits inside the line's own box, so a parent that clips never cuts it.\n * After layout the line checks its real width and shrinks if it came out wider than its share (a phone's own text\n * size setting, or a fallback font while Gotham isn't available, can make it wider than calculated).\n * The last word can be set in italics and/or in the accent colour, so \"forward\" and the slash read together.\n *\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight auto\n * @framerIntrinsicWidth 260\n */export default function TaglineWrite(props){const{text=\"Building forward\",lineHeight=1.3,tracking=-.02,color=\"#0A0A0A\",accent=\"#1F3FBF\",duration=1.1,fitScale=1,trail=.15,blink=false,blinks=0,lastItalic=false,lastAccent=false}=props;const isStatic=useIsStaticRenderer();const reduce=!!useReducedMotion();const still=isStatic||reduce;// in em of the line's size\nconst GAP=lastItalic?.1:.06// from the last letter to the slash\n;const SLASH=.34// the slash itself\n;// room around the words for an italic overhang, as padding cancelled by a negative margin, so the reveal's clip\n// stays inside the box (Safari ignores a clip-path inset that reaches outside it)\nconst OH=.3,OV=.2;const cut=text.lastIndexOf(\" \");const head=cut>=0?text.slice(0,cut+1):\"\",last=cut>=0?text.slice(cut+1):text;const box=useRef(null);const root=useRef(null);const words=useRef(null);const[w,setW]=useState(0)// the words' width in px: where the slash rests\n;const[ratio,setRatio]=useState(0)// the words' width per px of font size: sets the size that fits\n;const[on,setOn]=useState(false);const[k,setK]=useState(1)// shrink factor, below 1 only when the rendered line came out too wide\n;// measure the words: their width on every layout (where the slash rests), and their width per px of font size on\n// first layout and once the fonts have loaded (the size that fits). The ratio is not re-measured on resize: it\n// would feed back into the size it sets and keep nudging it by a rounding error\nuseEffect(()=>{const el=words.current;if(!el)return;const size=()=>parseFloat(getComputedStyle(el).fontSize)||0;const width=()=>{const fs=size();if(fs&&el.offsetWidth)setW(el.offsetWidth-OH*fs);};const fit=()=>{const fs=size();if(fs&&el.offsetWidth)setRatio(r=>{const next=el.offsetWidth/fs-OH;return Math.abs(next-r)>.01?next:r;});};width();fit();const ro=new ResizeObserver(width);ro.observe(el);document.fonts?.ready.then(()=>{fit();width();});return()=>ro.disconnect();},[text,tracking]);// check the rendered line against its share of the box and shrink it if it overflows; grow back (never past the\n// calculated size) if the box widens. 1% tolerance, so rounding never sets it hunting\nuseEffect(()=>{const b=box.current,p=root.current;if(!b||!p)return;const check=()=>{const room=b.clientWidth*fitScale,used=p.offsetWidth;if(!room||!used)return;setK(prev=>{const next=Math.min(1,prev*room/used);return Math.abs(next-prev)>.01*prev?next:prev;});};check();const ro=new ResizeObserver(check);ro.observe(b);ro.observe(p);document.fonts?.ready.then(check);return()=>ro.disconnect();},[fitScale,ratio]);// write the line once, when it comes into view\nuseEffect(()=>{const el=root.current;if(!el||still||typeof IntersectionObserver===\"undefined\")return;const io=new IntersectionObserver(e=>{if(e[0]?.isIntersecting){requestAnimationFrame(()=>requestAnimationFrame(()=>setOn(true)));io.disconnect();}},{threshold:.6});io.observe(el);return()=>io.disconnect();},[still]);const done=still||on;const ease=\"cubic-bezier(.45,0,.2,1)\";const cls=\"tw\"+useId().replace(/[^a-zA-Z0-9]/g,\"\");const em=(ratio||text.length*.6)+GAP+SLASH+trail// the whole line, in em\n;const css=`.${cls}{font-size:calc(100cqi * ${(fitScale*k).toFixed(4)} / ${em.toFixed(4)})}`+(blink&&!still&&on?`@keyframes ${cls}b{0%,55%{opacity:1}60%,95%{opacity:0}100%{opacity:1}}.${cls} .${cls}s{animation:${cls}b 1.1s step-end ${blinks>0?Math.round(blinks):\"infinite\"};animation-delay:${duration}s}`:\"\");return /*#__PURE__*/_jsx(\"div\",{ref:box,style:{...props.style,width:\"100%\",containerType:\"inline-size\"},children:/*#__PURE__*/_jsxs(\"p\",{ref:root,className:cls,\"aria-label\":`${text} /`,style:{margin:0,position:\"relative\",display:\"inline-block\",whiteSpace:\"nowrap\",paddingRight:`${GAP+SLASH+trail}em`,fontFamily:`\"Gotham Medium\", \"Gotham\", \"Inter Display\", sans-serif`,fontWeight:500,lineHeight,letterSpacing:`${tracking}em`,color},children:[/*#__PURE__*/_jsx(\"style\",{children:css}),/*#__PURE__*/_jsxs(\"span\",{ref:words,\"aria-hidden\":\"true\",style:{display:\"inline-block\",padding:`${OV}em ${OH}em ${OV}em 0`,margin:`-${OV}em -${OH}em -${OV}em 0`,clipPath:done?\"inset(0 0 0 0)\":\"inset(0 100% 0 0)\",transition:still?\"none\":`clip-path ${duration}s ${ease}`},children:[head,/*#__PURE__*/_jsx(\"span\",{style:{fontStyle:lastItalic?\"italic\":undefined,color:lastAccent?accent:undefined},children:last})]}),/*#__PURE__*/_jsx(\"span\",{className:`${cls}s`,\"aria-hidden\":\"true\",// the slash's box gets the same room as the words (padding, offset back by top/left), so the slanted glyph\n// sits inside it: Safari trims a moving element's paint to its box, which cut the slash's top flat\nstyle:{position:\"absolute\",left:\"-0.1em\",top:`-${OV}em`,padding:`${OV}em ${OH}em ${OV}em 0.1em`,color:accent,fontStyle:lastItalic?\"italic\":undefined,transform:`translateX(${done?`calc(${w}px + ${GAP}em)`:\"-0.2em\"})`,transition:still?\"none\":`transform ${duration}s ${ease}`},children:\"/\"})]})});}addPropertyControls(TaglineWrite,{text:{type:ControlType.String,title:\"Text\",defaultValue:\"Building forward\"},lineHeight:{type:ControlType.Number,title:\"Line height\",defaultValue:1.3,min:.8,max:2,step:.05},tracking:{type:ControlType.Number,title:\"Tracking\",defaultValue:-.02,min:-.1,max:.1,step:.005,unit:\"em\"},color:{type:ControlType.Color,title:\"Color\",defaultValue:\"#0A0A0A\"},accent:{type:ControlType.Color,title:\"Slash\",defaultValue:\"#1F3FBF\"},duration:{type:ControlType.Number,title:\"Duration\",defaultValue:1.1,min:.3,max:3,step:.05,unit:\"s\"},fitScale:{type:ControlType.Number,title:\"Fit scale\",defaultValue:1,min:.5,max:1,step:.01,description:\"Share of the box's width the line fills\"},trail:{type:ControlType.Number,title:\"Space after slash\",defaultValue:.15,min:0,max:.5,step:.01,unit:\"em\",description:\"Room after the slash, inside the line, so it is never clipped\"},lastItalic:{type:ControlType.Boolean,title:\"Last word italic\",defaultValue:false,enabledTitle:\"On\",disabledTitle:\"Off\"},lastAccent:{type:ControlType.Boolean,title:\"Last word accent\",defaultValue:false,enabledTitle:\"On\",disabledTitle:\"Off\"},blink:{type:ControlType.Boolean,title:\"Blink\",defaultValue:false,enabledTitle:\"On\",disabledTitle:\"Off\"},blinks:{type:ControlType.Number,title:\"Blinks\",defaultValue:0,min:0,max:10,step:1,displayStepper:true,description:\"How many times the slash blinks, then it stays. 0: keeps blinking\",hidden:p=>!p.blink}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"TaglineWrite\",\"slots\":[],\"annotations\":{\"framerSupportedLayoutWidth\":\"any\",\"framerSupportedLayoutHeight\":\"auto\",\"framerIntrinsicWidth\":\"260\",\"framerContractVersion\":\"1\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./TaglineWrite.map"],"mappings":"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"}