{"version":3,"file":"FeaturedPicks.zHMMS7bf.mjs","names":["useRef","__esmMin","init_npm_react_18_3_1","init_ssg_sandbox_shims","window","le","p","de","init_framer_BL70qLPA","RenderTarget","addPropertyControls","ControlType","climb","cur","el","i","levels","hash","h","str","getSeed","fresh","mode","key","storageKey","existing","pathOf","href","FeaturedPicks","props","ref","isCanvas","self","log","a","debug","selector","cardLayerName","attempts","timer","findCards","level","scopeAncestorLevels","scope","found","run","cards","grid","c","display","items","here","seed","shuffleMode","ranked","link","item","id","r","b","limit","showCount","init_FeaturedPicks","init_jsx_runtime"],"sources":["https:/framerusercontent.com/modules/STTJejpFsZ8cgLMKcL0z/08ZQNsOsayMwXghsixyX/FeaturedPicks.js"],"sourcesContent":["// ---------------------------------------------------------------------------\n// FeaturedPicks — v2\n// ---------------------------------------------------------------------------\n// Shows N random cards out of whatever a Collection List loads. Used on:\n//  - \"You may also like\" (list filtered to Featured + Available)\n//  - Homepage category sections (list filtered to that category +\n//    Available, no limit) — one instance per section, unique Storage Key.\n//\n// v2 CHANGES\n//  - Finds cards by climbing one level at a time and stopping at the first\n//    level that has any, so it can't reach into neighbouring sections.\n//  - Retries for ~3s if the Collection List hasn't rendered yet when this\n//    component mounts (previously it gave up and left every card showing).\n//\n// WHAT IT DOES\n//  - The Collection List in \"You may also like\" is filtered in Framer to\n//    only load products with Featured = ON (and Available = ON).\n//  - This component then picks a random handful of those (default 4),\n//    hides the rest, and never shows the product the customer is\n//    currently looking at.\n//  - \"Once per visit\" (default): the picks stay the same while someone\n//    browses in one visit, and change the next time they come back.\n//    \"Every page view\": new picks on every product page.\n//\n// WHY IT'S SAFE FOR THE REST OF THE SITE\n//  - It's a separate component from RandomizeOrder, so Shop All and the\n//    homepage sections keep running exactly as they do now.\n//  - It only touches cards inside its own section (it climbs a set number\n//    of layers up from where it's placed, same as RandomizeOrder).\n//  - It never moves cards in the page structure — it only sets CSS\n//    `order` and hides extras with `display: none`, so the scroll-reveal\n//    animations aren't disturbed (same lesson as RandomizeOrder v2).\n//  - It does nothing on the Framer editing canvas.\n//\n// PLACEMENT: one instance, as a sibling of the \"You may also like\"\n// Collection List (the same spot the RandomizeOrder instance sits now —\n// replace that instance with this one).\n// ---------------------------------------------------------------------------\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useLayoutEffect,useRef}from\"react\";import{addPropertyControls,ControlType,RenderTarget}from\"framer\";function climb(el,levels){let cur=el;for(let i=0;i<levels;i++){if(!cur.parentElement)break;cur=cur.parentElement;}return cur;}// Small, stable string hash (FNV-1a) — turns \"seed + product\" into a number\n// so the same product gets the same rank for the whole visit.\nfunction hash(str){let h=2166136261;for(let i=0;i<str.length;i++){h^=str.charCodeAt(i);h=Math.imul(h,16777619);}return h>>>0;}function getSeed(storageKey,mode){const fresh=String(Math.random()).slice(2);if(mode!==\"visit\")return fresh;const key=`herb:featuredPicks:${storageKey}:seed`;try{const existing=window.sessionStorage.getItem(key);if(existing)return existing;window.sessionStorage.setItem(key,fresh);}catch(e){// storage blocked (private mode etc.) — just use a fresh shuffle\n}return fresh;}function pathOf(href){try{return new URL(href,window.location.href).pathname.replace(/\\/$/,\"\");}catch(e){return\"\";}}/**\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight any\n */export default function FeaturedPicks(props){const{showCount,shuffleMode,storageKey,scopeAncestorLevels,cardLayerName,debug}=props;const ref=useRef(null);const isCanvas=RenderTarget.current()===RenderTarget.canvas;useLayoutEffect(()=>{if(isCanvas||typeof window===\"undefined\")return;const self=ref.current;if(!self)return;const log=(...a)=>{if(debug)console.log(\"[FeaturedPicks]\",...a);};const selector=`[data-framer-name=\"${cardLayerName}\"]`;let attempts=0;let timer=null;// Climb ONE level at a time and stop at the first ancestor that\n// contains any cards — so this can never reach past its own section\n// into another section's cards. Scope Levels is only the maximum.\nconst findCards=()=>{for(let level=1;level<=scopeAncestorLevels;level++){const scope=climb(self,level);const found=Array.from(scope.querySelectorAll(selector));if(found.length>0){log(`found ${found.length} card(s) at level ${level}`);return found;}}return[];};const run=()=>{const cards=findCards();if(cards.length===0){// The Collection List can finish rendering a moment after this\n// component mounts — retry for ~3 seconds before giving up.\nif(attempts++<20){timer=setTimeout(run,150);}else{log(`no cards named \"${cardLayerName}\" within ${scopeAncestorLevels} level(s) — check Card Layer Name or raise Scope Levels`);}return;}// The grid = the closest ancestor that contains every card.\nlet grid=cards[0].parentElement;while(grid&&!cards.every(c=>grid.contains(c))){grid=grid.parentElement;}if(!grid)return;const display=window.getComputedStyle(grid).display;if(!/(flex|grid)/.test(display)){log(`grid display is \"${display}\", not flex/grid — skipping`);return;}// Each card's slot = its ancestor that sits directly in the grid.\nconst items=[];cards.forEach(c=>{let el=c;while(el.parentElement&&el.parentElement!==grid){el=el.parentElement;}if(!items.includes(el))items.push(el);});const here=pathOf(window.location.href);const seed=getSeed(storageKey,shuffleMode);const ranked=items.map(item=>{const link=item.querySelector(\"a[href]\");const href=link?link.getAttribute(\"href\")||\"\":\"\";const id=href||(item.textContent||\"\").trim();const isCurrent=!!href&&pathOf(href)===here;return{item,id,isCurrent,rank:hash(seed+\"|\"+id)};}).filter(r=>{if(r.isCurrent)r.item.style.display=\"none\";return!r.isCurrent;}).sort((a,b)=>a.rank-b.rank);const limit=showCount>0?showCount:ranked.length;ranked.forEach((r,i)=>{if(i<limit){r.item.style.display=\"\";r.item.style.order=String(i);}else{r.item.style.display=\"none\";}});log(`seed ${seed} (${shuffleMode}) — showing ${Math.min(limit,ranked.length)} of ${ranked.length}:`,ranked.slice(0,limit).map(r=>r.id));};run();return()=>{if(timer)clearTimeout(timer);};},[]);if(isCanvas){return /*#__PURE__*/_jsxs(\"div\",{style:{padding:\"6px 10px\",fontSize:11,fontFamily:\"sans-serif\",background:\"rgba(199,243,74,0.25)\",border:\"1px dashed #C7F34A\",borderRadius:6,color:\"#888\",whiteSpace:\"nowrap\"},children:[\"FeaturedPicks \\xb7 shows \",showCount||\"all\",' random \\xb7 key \"',storageKey,'\"']});}return /*#__PURE__*/_jsx(\"div\",{ref:ref,\"aria-hidden\":true,style:{position:\"absolute\",width:0,height:0,overflow:\"hidden\",pointerEvents:\"none\"}});}FeaturedPicks.defaultProps={showCount:4,shuffleMode:\"visit\",storageKey:\"related\",scopeAncestorLevels:2,cardLayerName:\"Product Card\",debug:false};addPropertyControls(FeaturedPicks,{showCount:{type:ControlType.Number,title:\"Show Count\",defaultValue:4,min:0,max:24,step:1,displayStepper:true,description:\"0 = show all featured\"},shuffleMode:{type:ControlType.Enum,title:\"Shuffle\",options:[\"visit\",\"load\"],optionTitles:[\"Once per visit\",\"Every page view\"],defaultValue:\"visit\"},storageKey:{type:ControlType.String,title:\"Storage Key\",defaultValue:\"related\"},scopeAncestorLevels:{type:ControlType.Number,title:\"Scope Levels\",defaultValue:2,min:1,max:8,step:1,displayStepper:true},cardLayerName:{type:ControlType.String,title:\"Card Layer Name\",defaultValue:\"Product Card\"},debug:{type:ControlType.Boolean,title:\"Debug\",defaultValue:false}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"FeaturedPicks\",\"slots\":[],\"annotations\":{\"framerSupportedLayoutHeight\":\"any\",\"framerContractVersion\":\"1\",\"framerSupportedLayoutWidth\":\"any\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./FeaturedPicks.map"],"mappings":"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"}