var __gh = require("react").createElement, __gf = require("react").Fragment; var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var stdin_exports={};__export(stdin_exports,{default:()=>stdin_default});module.exports=__toCommonJS(stdin_exports);var import_react38=__toESM(require("react")),import_lucide_react30=require("lucide-react"),import_sdk8=require("@/sdk"),import_framer_motion4=require("framer-motion");var NEWSLETTER_KEY="strong_newsletter_v3",AUTH_KEY="strong_store_auth",ORDERS_KEY="strong_store_orders",CART_KEY="strong_store_cart",PHONE_PREFIXES=[{value:"+34",es:"Espa\xF1a +34",en:"Spain +34"},{value:"+351",es:"Portugal +351",en:"Portugal +351"},{value:"+33",es:"Francia +33",en:"France +33"},{value:"+39",es:"Italia +39",en:"Italy +39"},{value:"+49",es:"Alemania +49",en:"Germany +49"},{value:"+44",es:"Reino Unido +44",en:"UK +44"},{value:"+1",es:"EE.UU. +1",en:"USA +1"},{value:"+52",es:"M\xE9xico +52",en:"Mexico +52"},{value:"+54",es:"Argentina +54",en:"Argentina +54"},{value:"+56",es:"Chile +56",en:"Chile +56"},{value:"+57",es:"Colombia +57",en:"Colombia +57"},{value:"+55",es:"Brasil +55",en:"Brazil +55"},{value:"+41",es:"Suiza +41",en:"Switzerland +41"},{value:"+31",es:"Pa\xEDses Bajos +31",en:"Netherlands +31"},{value:"+32",es:"B\xE9lgica +32",en:"Belgium +32"},{value:"+43",es:"Austria +43",en:"Austria +43"},{value:"+46",es:"Suecia +46",en:"Sweden +46"},{value:"+47",es:"Noruega +47",en:"Norway +47"},{value:"+48",es:"Polonia +48",en:"Poland +48"},{value:"+353",es:"Irlanda +353",en:"Ireland +353"}],BRAND_ASSETS={logoFooter:"company_768/d3f68604-ed41-4c35-a93c-85089f361c05_30679330-3076-42aa-827f-c7b97e465bed_Strong2-07__1_.png",heroDesktop:"company_768/a576ce59-8c7e-42e8-aed8-050543b77a99_995dd3ac-284d-450d-952d-aa35ebfbeacb_hero_strong_final.jpeg",synergym:"company_768/acbdeda8-dd7e-414e-95a3-f062fdad9f71_80ef1aa9-21c3-4b38-a0d7-4c0e9a295271_diseno-synergym-strong.png",login:"company_768/577780ca-c5df-4dcf-b146-83b0ad2e9d7c_Imagen_Pop_Up.png"};var BLOCKED_ZONES=["canarias","ceuta_melilla","extranjero"];function isValidSpanishPostalCode(cp){if(!cp||cp.length!==5||!/^\d{5}$/.test(cp))return!1;let prefix=parseInt(cp.substring(0,2),10);return prefix>=1&&prefix<=52}function getZoneFromPostalCode(cp){if(!isValidSpanishPostalCode(cp))return"extranjero";let prefix=cp.substring(0,2);return prefix==="28"?"provincial":prefix==="07"?"baleares":prefix==="35"||prefix==="38"?"canarias":prefix==="51"||prefix==="52"?"ceuta_melilla":"peninsula"}function isZoneBlocked(zone){return BLOCKED_ZONES.includes(zone)}function getBlockedZoneName(zone){switch(zone){case"canarias":return"Islas Canarias";case"ceuta_melilla":return"Ceuta y Melilla";case"extranjero":return"fuera de Espa\xF1a";default:return zone}}function computeShipping({cart,subtotalAfterDiscount,postalCode,tarifas,config,couponType,envioGratisInterno}){let zone=postalCode?getZoneFromPostalCode(postalCode):"peninsula",totalWeight=cart.reduce((sum,item)=>sum+(item.product.peso||0)*item.quantity,0);if(postalCode&&isZoneBlocked(zone))return{cost:0,zone,totalWeight,isFree:!1,freeReason:null,noTarifa:!1,blocked:!0,blockedReason:`No realizamos env\xEDos a ${getBlockedZoneName(zone)}`};if(envioGratisInterno===!0)return{cost:0,zone,totalWeight,isFree:!0,freeReason:"interno",noTarifa:!1,blocked:!1};if(couponType==="envio_gratis")return{cost:0,zone,totalWeight,isFree:!0,freeReason:"coupon",noTarifa:!1,blocked:!1};if(subtotalAfterDiscount<=0)return{cost:0,zone,totalWeight,isFree:!0,freeReason:"coupon",noTarifa:!1,blocked:!1};if(!config.dinamico){let isFree2=subtotalAfterDiscount>=config.freeThreshold;return{cost:isFree2?0:Math.max(config.costeFijo,3.99),zone,totalWeight,isFree:isFree2,freeReason:isFree2?"threshold":null,noTarifa:!1,blocked:!1}}let activeTarifas=tarifas.filter(t=>t.activo!==!1&&t.zona===zone);if(activeTarifas.length===0)return{cost:0,zone,totalWeight,isFree:!1,freeReason:null,noTarifa:!0,blocked:!1};let matchedTarifa=activeTarifas.find(t=>totalWeight>=t.peso_min&&totalWeightt.peso_max>max.peso_max?t:max,activeTarifas[0]),isFree=subtotalAfterDiscount>=config.freeThreshold;return{cost:isFree?0:Math.max(matchedTarifa.precio,3.99),zone,totalWeight,isFree,freeReason:isFree?"threshold":null,noTarifa:!1,blocked:!1}}function parseShippingConfig(configRows){let get=key=>configRows.find(c=>c.clave===key)?.valor;return{dinamico:get("envio_dinamico")==="true",freeThreshold:parseFloat(get("envio_gratis_desde")||"60"),costeFijo:parseFloat(get("envio_coste_fijo")||"4.99")}}var getMockOrders=()=>[{id:"ORD-001",date:new Date(Date.now()-10080*60*1e3).toISOString(),total:89.9,status:"delivered",items:[{name:"Prote\xEDna Whey Premium",qty:1,price:49.9},{name:"Creatina Monohidrato",qty:2,price:20}]},{id:"ORD-002",date:new Date(Date.now()-2880*60*1e3).toISOString(),total:156.5,status:"shipped",items:[{name:"Pack Pre-Workout Elite",qty:1,price:156.5}]}];var publicCompanyId=()=>{let w=window,site=w.__GUFI_SITE__?.siteInfo,id=Number(site?.company_id??site?.config?.company_id??w.location?.pathname?.match(/\/(\d+)\/apps?\//)?.[1]);if(!Number.isFinite(id)||id<=0)throw new Error("La tienda no sabe de qu\xE9 empresa es: falta siteInfo.company_id");return id},automationUrl=name=>`/api/public/${publicCompanyId()}/automation/${name}`;async function postAutomacion(nombre,cuerpo,opciones){let escribe=opciones?.escribe===!0,limiteMs=opciones?.limiteMs??(escribe?25e3:15e3),ctrl=new AbortController,reloj=setTimeout(()=>ctrl.abort(),limiteMs);try{return await fetch(automationUrl(nombre),{method:"POST",headers:{"Content-Type":"application/json",...opciones?.cabeceras||{}},body:JSON.stringify(cuerpo),...opciones?.keepalive?{keepalive:!0}:{},signal:ctrl.signal})}catch(e){throw e?.name==="AbortError"?new Error(escribe?"No hemos podido confirmar la operaci\xF3n ("+nombre+"). Puede que s\xED se haya completado: compru\xE9balo antes de volver a intentarlo.":"El servidor no ha contestado a tiempo ("+nombre+"). Int\xE9ntalo otra vez en un momento."):e}finally{clearTimeout(reloj)}}var MAGIC_LINK_LOGIN_KEY="strong_magic_link_login",MAGIC_LINK_TOKEN_KEY="strong_magic_link_token",PASSWORD_CHANGE_REQUESTED_KEY="strong_password_change_requested",getLoginToken=()=>{try{let guardado=localStorage.getItem(MAGIC_LINK_TOKEN_KEY);if(guardado)return guardado}catch{}try{let enUrl=new URLSearchParams(window.location.search).get("synergym_token");if(enUrl)return enUrl}catch{}},mensajeErrorClave=(codigo,t,club)=>{let suApp=club?`la app de ${club}`:"la app de tu gimnasio",itsApp=club?`the ${club} app`:"your gym app";switch(codigo){case"SIN_PRUEBA":return t(`Tu sesi\xF3n ha caducado. Vuelve a abrir la tienda desde ${suApp} e int\xE9ntalo de nuevo.`,`Your session expired. Open the store again from ${itsApp} and try again.`);case"NO_AUTORIZADO":return t(`No hemos podido verificar tu identidad. Vuelve a entrar desde ${suApp} e int\xE9ntalo de nuevo.`,`We couldn't verify your identity. Log in again from ${itsApp} and try again.`);case"PASSWORD_TOO_SHORT":return t("La contrase\xF1a debe tener al menos 8 caracteres","Password must be at least 8 characters");case"MISSING_FIELDS":return t("Faltan datos por rellenar","Some fields are missing");default:return t("No se ha podido guardar. Int\xE9ntalo de nuevo.","Couldn't save. Please try again.")}};var clearReadableCookies=()=>{let doc=globalThis.document;doc&&(doc.cookie="strong_store_auth=; Path=/; Max-Age=0",doc.cookie="strong_magic_link_login=; Path=/; Max-Age=0")},SF_CTOKEN_KEY="gufi_sf_ctoken",canjearTokenPorSesion=async(siteSlug,loginToken)=>{if(!siteSlug||!loginToken)return null;try{let res=await fetch(`/s/auth/${encodeURIComponent(siteSlug)}/token-session`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:loginToken})});if(!res.ok)return console.warn("[Auth] token-session rechaz\xF3 el token:",res.status),null;let data=await res.json();if(!data?.ctoken||!data?.clienteId)return null;try{localStorage.setItem(SF_CTOKEN_KEY,data.ctoken)}catch(e){console.warn("[Auth] localStorage no disponible; la sesi\xF3n queda en la cookie:",e)}return{clienteId:Number(data.clienteId),ctoken:data.ctoken}}catch(e){return console.warn("[Auth] token-session no respondi\xF3:",e),null}},clienteNecesitaClave=async email=>{try{let resp=await postAutomacion("cliente_tiene_clave",{email:String(email||"").toLowerCase().trim()});if(!resp.ok)return!1;let raw=await resp.json(),r=raw&&raw.result!==void 0?raw.result:raw;return r?.exists===!0&&r?.hasPassword===!1}catch{return!1}},getClienteEmail=cliente=>Array.isArray(cliente.email)?cliente.email[0]||"":String(cliente.email||""),createAuthService=(dataProvider,tables,CB,siteSlug="")=>({loginWithSynergymToken:async token=>{if(!token||!dataProvider||!tables?.ecommerce__clientes)return null;let sesion=await canjearTokenPorSesion(siteSlug,token);if(!sesion)return null;let clienteId=sesion.clienteId;try{localStorage.setItem(MAGIC_LINK_TOKEN_KEY,token)}catch{}let cliente=(await dataProvider.query(tables.ecommerce__clientes,{pageSize:1,filters:[{field:"id",operator:"eq",value:clienteId}]}))?.data?.[0];if(!cliente)return null;let clienteEmail=getClienteEmail(cliente),needsPassword=await clienteNecesitaClave(clienteEmail),fullName=[cliente.nombre,cliente.apellidos].filter(Boolean).join(" "),user={id:String(cliente.id),email:clienteEmail,name:fullName||clienteEmail,origen:cliente.origen||"synergym",memberSince:cliente.created_at,acepta_marketing:!!cliente.acepta_marketing,cupon_id:cliente.cupon_id?.id||cliente.cupon_id||null,partner_id:cliente.partner_id?.id||cliente.partner_id||null,needsPassword,fromSynergym:!0};try{localStorage.setItem(AUTH_KEY,JSON.stringify(user))}catch(e){console.warn("[Auth] localStorage no disponible al guardar la ficha:",e)}if(dataProvider.update({resource:tables.ecommerce__clientes,id:cliente.id,variables:{last_login:CB.date(new Date)}}).catch(()=>{}),needsPassword)try{localStorage.setItem(MAGIC_LINK_LOGIN_KEY,"true")}catch{console.warn("[Auth] no se pudo recordar que el login vino de Synergym")}return user},checkUserHasPassword:async email=>{if(!email)return{exists:!1,hasPassword:!1};try{let resp=await postAutomacion("cliente_tiene_clave",{email:email.toLowerCase().trim()});if(!resp.ok)throw new Error("cliente_tiene_clave: HTTP "+resp.status);let raw=await resp.json(),r=raw&&raw.result!==void 0?raw.result:raw;return{exists:!!r?.exists,hasPassword:!!r?.hasPassword,clienteId:r?.clienteId}}catch(e){throw console.error("[Auth] checkUserHasPassword failed:",e),e}},loginWithMagicLink:async token=>{if(console.log("[Auth.loginWithMagicLink] Starting with token:",token?.slice(0,8)),!token||!dataProvider||!tables?.ecommerce__clientes)return console.log("[Auth.loginWithMagicLink] Missing deps:",{token:!!token,dp:!!dataProvider}),null;let sesion=await canjearTokenPorSesion(siteSlug,token);if(!sesion)return console.log("[Auth.loginWithMagicLink] Token inv\xE1lido o caducado"),null;let clienteId=sesion.clienteId;try{localStorage.setItem(MAGIC_LINK_TOKEN_KEY,token)}catch{}let cliente=(await dataProvider.query(tables.ecommerce__clientes,{pageSize:1,filters:[{field:"id",operator:"eq",value:clienteId}]}))?.data?.[0];if(console.log("[Auth.loginWithMagicLink] Cliente found:",cliente?{id:cliente.id,email:cliente.email,nombre:cliente.nombre}:"NOT FOUND"),!cliente)return null;let clienteEmail=getClienteEmail(cliente),needsPassword=await clienteNecesitaClave(clienteEmail),fullName=[cliente.nombre,cliente.apellidos].filter(Boolean).join(" "),user={id:String(cliente.id),email:clienteEmail,name:fullName||clienteEmail,origen:cliente.origen,memberSince:cliente.created_at,acepta_marketing:!!cliente.acepta_marketing,cupon_id:cliente.cupon_id?.id||cliente.cupon_id||null,partner_id:cliente.partner_id?.id||cliente.partner_id||null,needsPassword,fromMagicLink:!0};return console.log("[Auth.loginWithMagicLink] User created:",user),localStorage.setItem(AUTH_KEY,JSON.stringify(user)),dataProvider.update({resource:tables.ecommerce__clientes,id:cliente.id,variables:{last_login:CB.date(new Date)}}).catch(()=>{}),needsPassword&&localStorage.setItem(MAGIC_LINK_LOGIN_KEY,"true"),user},setPassword:async(userId,password,phoneData,prueba)=>{if(!userId||!password)throw console.error("[Auth.setPassword] falta userId o password"),new Error("MISSING_FIELDS");if(!prueba?.email||!prueba.passwordActual&&!prueba.loginToken)throw console.error("[Auth.setPassword] hace falta la contrasena actual o un login token"),new Error("SIN_PRUEBA");try{let raw=await(await postAutomacion("cambiar_password",{email:prueba.email,passwordActual:prueba.passwordActual,loginToken:prueba.loginToken,nuevaPassword:password})).json(),res=raw&&raw.result!==void 0?raw.result:raw;if(!res?.ok)throw console.error("[Auth.setPassword] rechazado:",res?.reason||res),new Error(res?.reason||"ERROR");if(phoneData?.telefono&&dataProvider&&tables?.ecommerce__clientes&&CB)try{await dataProvider.update({resource:tables.ecommerce__clientes,id:Number(userId),variables:{telefono:CB.phone(phoneData.telefono,phoneData.telefonoPrefix||"+34")}})}catch(e){console.warn("[Auth.setPassword] la contrasena se guardo, el telefono no:",e?.message||e)}try{localStorage.removeItem(MAGIC_LINK_LOGIN_KEY),localStorage.removeItem(MAGIC_LINK_TOKEN_KEY)}catch{}return!0}catch(e){throw console.error("[Auth.setPassword] ha fallado:",e?.message||e),e instanceof Error?e:new Error(String(e||"ERROR"))}},updatePhone:async(userId,telefono,prefix="+34")=>{if(!userId||!telefono||!dataProvider||!tables?.ecommerce__clientes||!CB)return!1;try{return await dataProvider.update({resource:tables.ecommerce__clientes,id:Number(userId),variables:{telefono:CB.phone(telefono,prefix)}}),!0}catch(e){return console.error("[Auth.updatePhone] Failed:",e?.message||e),!1}},shouldShowSetPasswordModal:()=>localStorage.getItem(MAGIC_LINK_LOGIN_KEY)==="true",dismissSetPasswordModal:()=>{localStorage.removeItem(MAGIC_LINK_LOGIN_KEY)},setPasswordChangeRequest:()=>{localStorage.setItem(PASSWORD_CHANGE_REQUESTED_KEY,"true")},hasPasswordChangeRequest:()=>localStorage.getItem(PASSWORD_CHANGE_REQUESTED_KEY)==="true",clearPasswordChangeRequest:()=>{localStorage.removeItem(PASSWORD_CHANGE_REQUESTED_KEY)},login:async(email,password)=>{if(!email||!password||!dataProvider||!tables)return null;let raw=await(await postAutomacion("ecommerce_login",{email:email.toLowerCase().trim(),password})).json(),result=raw&&raw.result!==void 0?raw.result:raw;if(!result?.valid)throw result?.reason==="NO_PASSWORD"?new Error("NO_PASSWORD_USE_MAGIC_LINK"):new Error("WRONG_PASSWORD");let sesion=await canjearTokenPorSesion(siteSlug,result.sessionToken);if(!sesion)throw new Error("SESSION_EXCHANGE_FAILED");let cliente=(await dataProvider.query(tables.ecommerce__clientes,{pageSize:1,filters:[{field:"id",operator:"eq",value:sesion.clienteId}]}))?.data?.[0];if(!cliente)return null;let clienteEmail=getClienteEmail(cliente),fullName=[cliente.nombre,cliente.apellidos].filter(Boolean).join(" "),user={id:String(cliente.id),email:clienteEmail,name:fullName||clienteEmail,origen:cliente.origen,memberSince:cliente.created_at,acepta_marketing:!!cliente.acepta_marketing,cupon_id:cliente.cupon_id?.id||cliente.cupon_id||null,partner_id:cliente.partner_id?.id||cliente.partner_id||null};return localStorage.setItem(AUTH_KEY,JSON.stringify(user)),dataProvider.update({resource:tables.ecommerce__clientes,id:cliente.id,variables:{last_login:CB.date(new Date)}}).catch(()=>{}),user},register:async(email,password,data)=>{if(!email||!password||!dataProvider||!tables)return null;let existe=await postAutomacion("cliente_tiene_clave",{email:email.toLowerCase().trim()}).then(r=>r.ok?r.json():null).then(raw=>{let r=raw&&raw.result!==void 0?raw.result:raw;return{exists:r?.exists===!0,hasPassword:r?.hasPassword===!0}}).catch(()=>{throw new Error("REGISTER_CHECK_UNAVAILABLE")});if(existe.exists)throw new Error(existe.hasPassword?"EMAIL_EXISTS":"EMAIL_EXISTS_SIN_CLAVE");let nombre=data?.nombre?.trim()||"",apellidos=data?.apellidos?.trim()||"",telefono=data?.telefono?.trim()||"",emailNormalized=email.toLowerCase().trim(),aresp=await postAutomacion("ecommerce_register",{email:emailNormalized,password,nombre,acepta_marketing:data?.acepta_marketing??!1}),araw=await aresp.json(),alta=araw&&araw.result!==void 0?araw.result:araw;if(!aresp.ok||!alta?.ok)throw new Error(alta?.error||araw?.error||"REGISTER_FAILED");let newId=alta.clienteId;if(!await canjearTokenPorSesion(siteSlug,String(alta.sessionToken||"")))throw console.error("[Registro] cuenta "+newId+" creada pero no se ha podido abrir la sesion de tienda"),new Error("SESSION_EXCHANGE_FAILED");try{await dataProvider.update({resource:tables.ecommerce__clientes,id:Number(newId),variables:{...apellidos&&{apellidos:CB.text(apellidos)},...telefono&&{telefono:CB.phone(telefono,data?.telefonoPrefix||"+34")},activo:CB.bool(!0),origen:"web"}})}catch(e){console.error("[Registro] cuenta "+newId+" creada, pero no se guardaron apellidos/telefono",e)}let fullName=[nombre,apellidos].filter(Boolean).join(" "),user={id:String(newId),email:emailNormalized,name:fullName||emailNormalized,origen:"web",memberSince:new Date().toISOString(),acepta_marketing:data?.acepta_marketing??!1};return localStorage.setItem(AUTH_KEY,JSON.stringify(user)),localStorage.setItem(ORDERS_KEY,JSON.stringify(getMockOrders())),user},logout:()=>{localStorage.removeItem(AUTH_KEY),localStorage.removeItem(SF_CTOKEN_KEY),localStorage.removeItem(MAGIC_LINK_TOKEN_KEY),clearReadableCookies(),dataProvider.custom({url:"/logout",method:"post",payload:{}}).catch(()=>{})},deleteAccount:async userId=>{if(console.log("[Auth.deleteAccount] Starting...",{userId,table:tables?.ecommerce__clientes}),!userId||!tables?.ecommerce__clientes)return console.error("[Auth.deleteAccount] Missing required params"),!1;try{let url=`/api/tables/${tables.ecommerce__clientes}/${userId}`;console.log("[Auth.deleteAccount] DELETE URL:",url);let response=await fetch(url,{method:"DELETE",credentials:"include"});if(console.log("[Auth.deleteAccount] Response status:",response.status),!response.ok){let text=await response.text();return console.error("[Auth.deleteAccount] Error response:",text),!1}return localStorage.removeItem(AUTH_KEY),localStorage.removeItem(ORDERS_KEY),localStorage.removeItem(MAGIC_LINK_LOGIN_KEY),clearReadableCookies(),dataProvider.custom({url:"/logout",method:"post",payload:{}}).catch(()=>{}),console.log("[Auth.deleteAccount] Account deleted successfully"),!0}catch(e){return console.error("[Auth.deleteAccount] Failed:",e?.message||e),!1}},getStoredUser:()=>{try{let stored=localStorage.getItem(AUTH_KEY);return stored?JSON.parse(stored):null}catch{return null}},validateStoredUser:async()=>{let stored=localStorage.getItem(AUTH_KEY);if(!stored)return null;try{let user=JSON.parse(stored);if(!user.id||!dataProvider||!tables?.ecommerce__clientes)return user;let result=await dataProvider.query(tables.ecommerce__clientes,{pageSize:1,filters:[{field:"id",operator:"eq",value:Number(user.id)}]});if(!result?.data?.[0])return console.log("[Auth.validateStoredUser] User not found in DB, clearing session"),localStorage.removeItem(AUTH_KEY),localStorage.removeItem(ORDERS_KEY),localStorage.removeItem(MAGIC_LINK_LOGIN_KEY),clearReadableCookies(),dataProvider.custom({url:"/logout",method:"post",payload:{}}).catch(()=>{}),null;let dbCliente=result.data[0];return dbCliente.origen&&dbCliente.origen!==user.origen&&(user.origen=dbCliente.origen,localStorage.setItem(AUTH_KEY,JSON.stringify(user))),user}catch(e){return console.error("[Auth.validateStoredUser] Error:",e),null}}});var formatPrice=price=>price==null?"\u2014":new Intl.NumberFormat("es-ES",{style:"currency",currency:"EUR"}).format(price),fileUrl=path=>path?path.startsWith("http")?path:`/api/files/serve?path=${encodeURIComponent(path)}`:null,getImageUrl=file=>fileUrl(getAllImagePaths(file)[0]),sized=(url,w)=>url?url+(url.includes("?")?"&":"?")+"w="+w:null,ANCHO_ZOOM=3200,srcSetFull=path=>{let url=fileUrl(path);if(!(!url||!url.startsWith("/api/files/serve")))return`${url}&w=${ANCHO_ZOOM} ${ANCHO_ZOOM}w`},getAllImageUrls=file=>getAllImagePaths(file).map(fileUrl).filter(u=>!!u),getAllImagePaths=file=>file?(Array.isArray(file)?file:[file]).map(img=>img&&img.zara&&typeof img.zara.url=="string"&&img.zara.url?img.zara.url:img?.url).filter(u=>typeof u=="string"&&!!u):[],variantSlug=v=>v==null?"":String(v).toLowerCase().replace(/\s+/g,"-"),alPulsarEnlace=(e,ir)=>{let dentro=e.target;if(dentro&&typeof dentro.closest=="function"&&dentro.closest("button:disabled")){e.preventDefault();return}e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0||(e.preventDefault(),ir())},sinNavegar=e=>{e.preventDefault(),e.stopPropagation()},gramosDeTexto=v=>{let m=String(v??"").trim().toLowerCase().replace(",",".").match(/^(\d+(?:\.\d+)?)\s*(kg|g)\b/);if(!m)return null;let n=parseFloat(m[1])*(m[2]==="kg"?1e3:1);return n>0?n:null},racionesDeProducto=p=>{let r=gramosDeTexto(p&&p.info_nutricional&&p.info_nutricional.serving),e=gramosDeTexto(p&&p.tamano),n=r&&e?Math.floor(e/r):0;return n>=2?n:null},altProducto=p=>p?[p.nombre,p.sabor,p.tamano].filter(v=>v!=null&&String(v).trim()!=="").map(String).join(" \xB7 "):"",getDiscount=product=>{let antes=Number(product?.precio),ahora=Number(product?.precio_oferta);if(!Number.isFinite(antes)||!Number.isFinite(ahora)||antes<=0||ahora<=0||ahora>=antes)return null;let pct=Math.round((antes-ahora)/antes*100);return pct>0?pct:null};var getTimeLeft=()=>{let now=new Date,midnight=new Date(now);midnight.setHours(23,59,59,999);let diff=midnight.getTime()-now.getTime();return{hours:Math.floor(diff/(1e3*60*60)),minutes:Math.floor(diff%(1e3*60*60)/(1e3*60)),seconds:Math.floor(diff%(1e3*60)/1e3)}},calculateCartTotal=cart=>cart.reduce((sum,item)=>{let price=item.product.precio_oferta||item.product.precio||0;return sum+price*item.quantity},0),calculateCartCount=cart=>cart.reduce((sum,item)=>sum+item.quantity,0);var packSinServir=(packProds,products,outOfStockIds)=>packProds.filter(pp=>!pp.isGift).some(pp=>{let prod=products.find(p=>p.id===pp.productId);return!prod||prod.activo===!1||outOfStockIds.has(pp.productId)}),packsVisibles=(packs,packProductosMap,products,outOfStockIds)=>products.length===0?[]:packs.filter(p=>p.activo!==!1).map(p=>{let prods=packProductosMap.get(p.id)||[];return p.tipo==="caja"?{...p,agotado:p.caja_agotada===!0}:{...p,agotado:prods.length===0||packSinServir(prods,products,outOfStockIds)}}).sort((a,b)=>{if(a.agotado!==b.agotado)return a.agotado?1:-1;let oa=a.orden==null?9999:Number(a.orden),ob=b.orden==null?9999:Number(b.orden);return oa!==ob?oa-ob:a.id-b.id}),COLLAGE_MAX=3,packMedia=(pack,packProds,allProducts)=>{if(pack.usar_foto_propia===!0){let todas=(Array.isArray(pack.imagen_principal)?pack.imagen_principal:[]).map(f=>f&&f.url?String(f.url):null).filter(u=>!!u);if(todas.length>0)return{tipo:"foto",url:todas[0],urls:todas}}let fotos=packProds.filter(pp=>!pp.isGift).map(pp=>allProducts.find(p=>p.id===pp.productId)).map(p=>({url:getImageUrl(p?.imagen_principal),alt:altProducto(p)})).filter(f=>!!f.url).slice(0,COLLAGE_MAX);return fotos.length>0?{tipo:"collage",urls:fotos.map(f=>f.url),alts:fotos.map(f=>f.alt)}:{tipo:"sin-imagen"}},packImagenField=(pack,packProds,allProducts)=>pack.usar_foto_propia===!0&&getImageUrl(pack.imagen_principal)?pack.imagen_principal:packProds.filter(pp=>!pp.isGift).map(pp=>allProducts.find(p=>p.id===pp.productId)).find(prod=>getImageUrl(prod?.imagen_principal))?.imagen_principal,redondeoStrong=euros2=>{let c=Math.round(euros2*100),u=c%10;if(u===0||u===5||u===9)return c/100;if(u<=2)return(c-u)/100;if(u<=4)return(c-u+5)/100;let arriba=c-u+10;return(arriba%100===0&&u>=7?arriba-1:arriba)/100},precioPackConDescuento=(suelto,pct)=>{let p=Math.min(100,Math.max(0,Number(pct)||0));return redondeoStrong(suelto*(1-p/100))},grupoDeCategorias=(catId,alcance,categorias)=>{if(alcance!=="categoria")return new Set([catId]);let padreDe=new Map((categorias||[]).map(c=>[Number(c.id),c.categoria_padre_id==null?null:Number(c.categoria_padre_id)])),base=padreDe.get(catId)??catId,grupo=new Set([base]),crece=!0;for(;crece;){crece=!1;for(let[id,padre]of padreDe)padre!=null&&grupo.has(padre)&&!grupo.has(id)&&(grupo.add(id),crece=!0)}return grupo},elegirSustituto=(original,cantidad,alcance,productos,disponible,categorias,excluir)=>{if(!original||alcance==="nada")return null;let catId=Number(original.categoria_id);if(!catId)return null;let grupo=grupoDeCategorias(catId,alcance,categorias),familia=p=>Number(p.producto_padre_id||p.id),suFamilia=familia(original),precioO=Number(original.precio)||0,candidatos=(productos||[]).filter(p=>Number(p.id)!==Number(original.id)&&p.activo!==!1&&Number(p.precio)>0&&grupo.has(Number(p.categoria_id))&&!(Number(p.consume_unidades)>=2)&&!excluir.has(Number(p.id))&&disponible(Number(p.id))>=cantidad);return candidatos.sort((a,b)=>+(familia(b)===suFamilia)-+(familia(a)===suFamilia)||+(!!original.marca&&b.marca===original.marca)-+(!!original.marca&&a.marca===original.marca)||Math.abs(Number(a.precio)-precioO)-Math.abs(Number(b.precio)-precioO)||Number(a.id)-Number(b.id)),candidatos[0]||null},resolverPacks=(packs,mapa,productos,outOfStockIds,disponible,categorias)=>{if(productos.length===0)return{packs,mapa};let porId=new Map(productos.map(p=>[Number(p.id),p])),hay=id=>outOfStockIds.has(id)?0:disponible(id),mapaOut=new Map;return{packs:packs.map(pack=>{let lineas=mapa.get(pack.id)||[];if(pack.tipo==="caja")return mapaOut.set(pack.id,lineas),pack;if(pack.autoajustar===!0){let usados=new Set(lineas.map(l=>Number(l.productId))),nuevas=[];for(let l of lineas){let cant=Number(l.cantidad)||1,prod=porId.get(Number(l.productId));if(prod&&prod.activo!==!1&&hay(Number(l.productId))>=cant){nuevas.push(l);continue}let sust=elegirSustituto(prod,cant,l.sustituir||"subcategoria",productos,hay,categorias,usados);sust?(usados.add(Number(sust.id)),nuevas.push({...l,productId:Number(sust.id),displayName:sust.nombre,sustituyeA:Number(l.productId)})):l.isGift||nuevas.push(l)}lineas=nuevas}mapaOut.set(pack.id,lineas);let cortaDe=pr=>{let propia=String(pr?.descripcion_corta||"").trim();if(propia)return propia;let padre=pr?.producto_padre_id?porId.get(Number(pr.producto_padre_id)):null;return String(padre?.descripcion_corta||"").trim()},partes=[];for(let l of lineas){if(l.isGift)continue;let pr=porId.get(Number(l.productId));if(!pr)continue;let n=Number(l.cantidad)||1,nombre=(n>1?`${n} \xD7 `:"")+String(pr.nombre||""),txt2=cortaDe(pr);partes.push(txt2?`\u2022 ${nombre}: ${txt2}`:`\u2022 ${nombre}`)}let regalos=lineas.filter(l=>l.isGift).map(l=>porId.get(Number(l.productId))?.nombre).filter(Boolean);regalos.length&&partes.push(`De regalo: ${regalos.join(" + ")}.`);let conTexto=partes.length?{...pack,descripcion:partes.join(` `)}:pack;if(pack.descuento_pct==null||pack.descuento_pct==="")return conTexto;let suelto=lineas.filter(l=>!l.isGift).reduce((s,l)=>s+(Number(porId.get(Number(l.productId))?.precio)||0)*(Number(l.cantidad)||1),0);if(!(suelto>0))return conTexto;let base=Math.round(suelto*100)/100,final=precioPackConDescuento(base,Number(pack.descuento_pct));return final{if(!valor)return null;let obj=valor;if(typeof valor=="string"){let txt2=valor.trim();if(!txt2)return null;try{obj=JSON.parse(txt2)}catch{return null}}if(!obj||!Array.isArray(obj.reglas))return null;let reglas=obj.reglas.filter(r=>r&&typeof r.criterio=="string");return reglas.length===0&&!obj.resto?null:{reglas,resto:obj.resto||"ventas"}},barajar=lista=>{let c=lista.slice();for(let i=c.length-1;i>0;i--){let j=Math.floor(Math.random()*(i+1)),t=c[i];c[i]=c[j],c[j]=t}return c},pasaFiltros=(p,r,d)=>{if(r.categorias&&r.categorias.length>0&&!r.categorias.includes(d.categoria(p))||r.marcas&&r.marcas.length>0&&!r.marcas.includes(d.marca(p)))return!1;let precio=d.precio(p);if(r.precio_min!=null&&precio0&&precio>r.precio_max||r.criterio==="rebajados"&&!d.rebajado(p))return!1;if(r.criterio==="stock_sobre"){let s=d.stock(p);if(s==null||s<(Number(r.umbral)||0))return!1}return!0},ordenarPorCriterio=(lista,r,d)=>{let porStock=(a,b)=>(d.stock(b)??-1)-(d.stock(a)??-1),ultimo=porPuesto(d);switch(r.criterio){case"aleatorio":return barajar(lista);case"a_mano":{let pos=new Map;return(r.ids||[]).forEach((id,i)=>pos.set(Number(id),i)),lista.filter(p=>pos.has(d.id(p))).sort((a,b)=>(pos.get(d.id(a))??0)-(pos.get(d.id(b))??0))}case"mas_stock":return lista.slice().sort((a,b)=>porStock(a,b)||ultimo(a,b));case"stock_sobre":return lista.slice().sort((a,b)=>d.ventas(b)-d.ventas(a)||porStock(a,b)||ultimo(a,b));case"mas_nuevos":return lista.slice().sort((a,b)=>d.nuevo(b)-d.nuevo(a)||ultimo(a,b));case"mas_caro":return lista.slice().sort((a,b)=>d.precio(b)-d.precio(a)||ultimo(a,b));case"mas_barato":return lista.slice().sort((a,b)=>d.precio(a)-d.precio(b)||ultimo(a,b));case"rebajados":return lista.slice().sort((a,b)=>d.ventas(b)-d.ventas(a)||ultimo(a,b));default:return lista.slice().sort((a,b)=>d.ventas(b)-d.ventas(a)||d.precio(b)-d.precio(a)||ultimo(a,b))}},porPuesto=d=>(a,b)=>{if(d.puesto){let pa=d.puesto(a),pb=d.puesto(b);if(pa!=null&&pb!=null&&pa!==pb)return pa-pb;if(pa!=null&&pb==null)return-1;if(pa==null&&pb!=null)return 1}return String(a?.nombre||"").localeCompare(String(b?.nombre||""))},ordenarResto=(lista,modo,d)=>{let ultimo=porPuesto(d);switch(modo){case"stock":return lista.slice().sort((a,b)=>(d.stock(b)??-1)-(d.stock(a)??-1)||ultimo(a,b));case"nuevos":return lista.slice().sort((a,b)=>d.nuevo(b)-d.nuevo(a)||ultimo(a,b));case"precio_asc":return lista.slice().sort((a,b)=>d.precio(a)-d.precio(b)||ultimo(a,b));case"precio_desc":return lista.slice().sort((a,b)=>d.precio(b)-d.precio(a)||ultimo(a,b));case"aleatorio":return barajar(lista);case"a_mano":return d.puesto?lista.slice().sort(ultimo):lista.slice().sort((a,b)=>d.ventas(b)-d.ventas(a));default:return lista.slice().sort((a,b)=>d.ventas(b)-d.ventas(a)||ultimo(a,b))}},aplicarReglas=(productos,cfg,d)=>{let usados=new Set,salida=[];for(let r of cfg.reglas||[]){let candidatos=productos.filter(p=>!usados.has(d.id(p))&&pasaFiltros(p,r,d)),ordenados=ordenarPorCriterio(candidatos,r,d),cuantos=Number(r.cuantos)>0?Number(r.cuantos):ordenados.length;for(let p of ordenados.slice(0,cuantos))usados.add(d.id(p)),salida.push(p)}if(cfg.resto!=="nada"){let sobran=productos.filter(p=>!usados.has(d.id(p)));salida.push(...ordenarResto(sobran,cfg.resto,d))}let vivos=salida.filter(p=>!d.agotado(p)),agotados=salida.filter(p=>d.agotado(p));return vivos.concat(agotados)};var variantData={105:{flavors:[{id:"cookies-cream",label:"Cookies & Cream",color:"#F5E6C8",color2:"#3A2A1A"},{id:"salty-peanut",label:"Salty Peanut",color:"#D4A060"},{id:"caramel-cashew",label:"Caramel Cashew",color:"#C8963C"},{id:"white-choc-almond",label:"White Choco Almond",color:"#F5E6C8"},{id:"white-salty-peanut",label:"White Salty Peanut",color:"#F5E6C8"},{id:"peanut-caramel",label:"Peanut Caramel (Soft)",color:"#D4A060"},{id:"caramel-choco",label:"Caramel Choco (Soft)",color:"#8B5A2B"},{id:"coco-choco",label:"Coco Choco (Soft)",color:"#F5E6C8",color2:"#5C3A1E"},{id:"cookies-caramel",label:"Cookies & Caramel",color:"#C8963C"}]},102:{flavors:[{id:"avellana-turron",label:"Avellana-Turr\xF3n",color:"#C8963C"},{id:"choc-blanco-coco",label:"Chocolate Blanco & Coco",color:"#F5E6C8"}]},73:{flavors:[{id:"pistacho",label:"Pistacho",color:"#93C572"},{id:"cacahuete",label:"Cacahuete",color:"#D4A060"}]},71:{flavors:[{id:"hazelnut-spread",label:"Hazelnut Spread",color:"#8B5A2B"},{id:"chocolate",label:"Chocolate",color:"#5C3A1E"}]},78:{flavors:[{id:"tropical",label:"Tropical",color:"#F5A623"},{id:"pink-lemonade",label:"Pink Lemonade",color:"#FF69B4"}]},94:{flavorsPending:!0},90:{flavorsPending:!0},82:{flavorsPending:!0},74:{flavorsPending:!0},70:{flavorsPending:!0},51:{flavorsPending:!0},48:{flavorsPending:!0},68:{flavorsPending:!0},85:{flavorsPending:!0},64:{flavorsPending:!0},91:{flavorsPending:!0},65:{sizes:[{id:"40",label:"40 gummies"},{id:"140",label:"140 gummies"}]}},FLAVOR_COLORS={chocolate:"#5C3A1E",choco:"#5C3A1E",vainilla:"#F5E6C8",vanilla:"#F5E6C8","vainilla ice cream":"#E8D5B7",fresa:"#E84B6A",strawberry:"#E84B6A","strawberry cheesecake":"#F28BA8",caramelo:"#C8963C",caramel:"#C8963C",cacahuete:"#D4A060",peanut:"#D4A060",pistacho:"#93C572",pistachio:"#93C572",tropical:"#F5A623",limon:"#FFF44F",lemon:"#FFF44F",naranja:"#FF8C00",orange:"#FF8C00",mango:"#FFB347",coco:"#F5F5DC",coconut:"#F5F5DC",avellana:"#8B5A2B",hazelnut:"#8B5A2B",cafe:"#6F4E37",coffee:"#6F4E37",menta:"#98FF98",mint:"#98FF98","frutas del bosque":"#8B008B",berry:"#8B008B",platano:"#FFE135",banana:"#FFE135",neutro:"#B8B8B8",neutral:"#B8B8B8","sin sabor":"#B8B8B8",neutra:"#B8B8B8","salty peanut":"#C9A45C","cookies & cream":"#F0E0C6","cookies & caramel":"#D4A860","caramel cashew":"#C8963C","white chocolate almond":"#F5EDE0","white salty peanut":"#EDE5D5","peanut caramel":"#D4A060","caramel choco":"#7B4A2A",cocochoco:"#6B4226","fruit punch":"#E8453C","blue raspberry":"#4A90D9",blueraspberry:"#4A90D9","cherry blast":"#C41E3A",cereza:"#C41E3A",cherry:"#C41E3A","fresh lemonade":"#FFF44F",sandia:"#FF6B6B",sand\u00EDa:"#FF6B6B","water melon":"#FF6B6B",cookies:"#C9A978",brownie:"#5C3A1E","iced cappuccino":"#9B7E5A","chocolate brownie":"#5C3A1E","chocolate cookies":"#6B4226","citrus punch":"#FFD700",frambuesa:"#D81B60","naranja dulce":"#FFA726"};function getFlavorColor(sabor){let lower=sabor.toLowerCase();if(FLAVOR_COLORS[lower])return FLAVOR_COLORS[lower];for(let[key,color]of Object.entries(FLAVOR_COLORS))if(lower.includes(key)||key.includes(lower))return color;return"#B8B8B8"}var extractImageUrl=file=>getImageUrl(file)||void 0;function buildVariantDataFromProducts(products){let grouped=new Map;for(let p of products){let key=p.producto_padre_id||p.id;grouped.has(key)||grouped.set(key,[]),grouped.get(key).push(p)}for(let[parentId,siblings]of grouped){if(siblings.length<=1)continue;let config={},sabores=[...new Set(siblings.map(s=>s.sabor).filter(Boolean))];sabores.length>1&&(config.flavors=sabores.map(s=>{let matchingProduct=siblings.find(p=>p.sabor===s),flavorSizeIds=siblings.filter(p=>p.sabor===s&&p.tamano).map(p=>variantSlug(p.tamano));return{id:variantSlug(s),label:s,color:getFlavorColor(s),image:matchingProduct?extractImageUrl(matchingProduct.imagen_principal):void 0,productId:matchingProduct?.id,sizeIds:flavorSizeIds.length>0?flavorSizeIds:void 0}}));let tamanos=[...new Set(siblings.map(s=>s.tamano).filter(Boolean))];if(tamanos.length>1&&(config.sizes=tamanos.map(t=>({id:variantSlug(t),label:t}))),config.flavors||config.sizes)for(let p of siblings)variantData[p.id]=config}}function getVariantConfig(productId){return variantData[productId]||null}var import_sdk=require("@/sdk");function FlavorDots({flavors,selected,onSelect,size="sm",maxVisible=6,bloqueados}){if(!flavors||flavors.length<=1)return null;let visible2=flavors.slice(0,maxVisible),overflow=flavors.length-maxVisible,isLight=hex=>{let r=parseInt(hex.slice(1,3),16),g=parseInt(hex.slice(3,5),16),b=parseInt(hex.slice(5,7),16);return(r*299+g*587+b*114)/1e3>200};return __gh("div",{className:(0,import_sdk.cn)("sj-flavor-dots",`sj-flavor-dots--${size}`),onClick:sinNavegar,"data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:33"},visible2.map(f=>{let bg=f.color2?`linear-gradient(135deg, ${f.color} 50%, ${f.color2} 50%)`:f.color,light=isLight(f.color)&&(!f.color2||isLight(f.color2)),fuera=!!bloqueados&&bloqueados.indexOf(f.id)>=0;return __gh("div",{key:f.id,className:(0,import_sdk.cn)("sj-flavor-dot",selected===f.id&&"sj-flavor-dot--active",light&&"sj-flavor-dot--light"),style:fuera?{background:bg,opacity:.3,cursor:"not-allowed",filter:"grayscale(0.7)"}:{background:bg},title:fuera?`${f.label} \u2014 sin stock ahora mismo`:f.label,onClick:e=>{sinNavegar(e),fuera||onSelect(f.id)},"data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:45"})}),overflow>0&&__gh("div",{className:"sj-flavor-dot--overflow","data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:61"},"+",overflow))}function SizePills({sizes,selected,onSelect,bloqueados}){return!sizes||sizes.length<=1?null:__gh("div",{className:"sj-size-pills",onClick:sinNavegar,"data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:120"},sizes.map(s=>{let fuera=!!bloqueados&&bloqueados.indexOf(s.id)>=0;return __gh("button",{key:s.id,className:(0,import_sdk.cn)("sj-size-pill",selected===s.id&&"sj-size-pill--active"),title:fuera?`${s.label} \u2014 sin stock ahora mismo`:void 0,style:fuera?{opacity:.35,cursor:"not-allowed",textDecoration:"line-through"}:void 0,onClick:e=>{sinNavegar(e),fuera||onSelect(s.id)},"data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:124"},s.label)}))}function CartVariantLine({flavor,size,productId}){let config=getVariantConfig(productId);if(!config||!flavor&&!size)return null;let flavorObj=flavor&&config.flavors?.find(f=>f.id===flavor),sizeObj=size&&config.sizes?.find(s=>s.id===size),parts=[];return flavorObj&&parts.push(flavorObj.label),sizeObj&&parts.push(sizeObj.label),parts.length===0?null:__gh("div",{className:"sj-cart-variant","data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:171"},flavorObj&&__gh("div",{className:(0,import_sdk.cn)("sj-cart-variant-dot",(hex=>{let r=parseInt(hex.slice(1,3),16),g=parseInt(hex.slice(3,5),16),b=parseInt(hex.slice(5,7),16);return(r*299+g*587+b*114)/1e3>200})(flavorObj.color)&&"sj-cart-variant-dot--light"),style:{background:flavorObj.color2?`linear-gradient(135deg, ${flavorObj.color} 50%, ${flavorObj.color2} 50%)`:flavorObj.color},"data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:173"}),__gh("span",{className:"sj-cart-variant-text","data-gufi-src":"styles/fitness/components/VariantSelectors.tsx:182"},parts.join(" / ")))}var headerStyles=` /* \u2500\u2500 Top Bar \u2500\u2500 */ .sj-topbar { background: var(--t-tienda-oscuro, #0a0a0b); height: 36px; display: flex; align-items: center; justify-content: center; overflow: hidden; transition: height 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.35s ease, background 0.4s ease; /* STICKY, no relative. En el flujo normal la barra se quedaba "arriba del todo" de la pagina: al bajar se iba de la pantalla y la cabecera se pegaba sola al borde, asi que las dos piezas viajaban por separado. Y no tenia sentido, porque el temporizador de claims sigue rotando y la logica de topBarVisible ya decide cuando esconderla. Siendo sticky, barra y cabecera se mueven como UNA sola pieza. */ position: sticky; z-index: 49; } /* La copia de arriba del header no se pinta: se quedo ahi para no tener que mover el temporizador de claims y sus condiciones. */ .sj-topbar--oculta-aqui { display: none; } /* La buena: pegada JUSTO DEBAJO de la cabecera. El offset es la altura real del header, que se mide con un ResizeObserver y se publica en --sj-header-h; no vale un numero fijo porque la cabecera cambia de alto entre la home, el catalogo y el movil. */ .sj-topbar--bajo-header { top: var(--sj-header-h, 104px); } .sj-topbar--hidden { height: 0; opacity: 0; pointer-events: none; } .sj-topbar-inner { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } .sj-topbar-item { position: absolute; display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: rgba(255,255,255,0.4); opacity: 0; transform: translateY(12px); transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.16, 1, 0.3, 1); white-space: nowrap; } .sj-topbar-item--active { opacity: 1; transform: translateY(0); color: rgba(255,255,255,0.65); } @media (min-width: 640px) { .sj-topbar-item { font-size: 11.5px; gap: 6px; } } /* \u2500\u2500 Header \u2500\u2500 */ .sj-header { position: sticky; top: 0; z-index: 50; background: rgba(255,255,255,0.6); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-bottom: 1px solid transparent; transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease; } .sj-header--scrolled { background: rgba(255,255,255,0.97); border-bottom-color: rgba(0,0,0,0.06); box-shadow: 0 1px 20px rgba(0,0,0,0.04); } @media (min-width: 769px) { .sj-header--catmode { background: var(--t-tienda-fondo, #fff) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } .sj-header--catmode.sj-header--scrolled { background: var(--t-tienda-fondo, #fff) !important; box-shadow: 0 2px 20px rgba(0,0,0,0.06); } } /* Desktop: con el header navy (tema 13-ago) el logo va SIEMPRE en blanco en scrolled y catmode \u2014 antes el header scrolled era claro y el logo iba en negro, y quedaba invisible sobre el navy (queja 14-ago). */ @media (min-width: 769px) { .sj-header--scrolled .sj-logo-link img { filter: brightness(0) invert(1) !important; } .sj-header:not(.sj-header--hero) .sj-logo-link img { filter: brightness(0) invert(1); } } /* \u2500\u2500 Hero mode \u2500\u2500 La barra va en NEGRO, no transparente. Con fondo transparente todo lo que pasa por detras al hacer scroll (la foto del producto del hero, sobre todo) se mezcla con las letras y no hay quien lea el menu. */ .sj-topbar--hero { background: var(--t-tienda-oscuro, #000) !important; background-color: var(--t-tienda-oscuro, #000) !important; } .sj-header--hero { background: var(--t-tienda-oscuro, #0a0a0a) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; border-bottom-color: rgba(255,255,255,0.08) !important; box-shadow: none !important; } .sj-header--hero .sj-hamburger-line { background: var(--t-tienda-fondo, #fff); } .sj-header--hero .sj-hamburger:hover { background: rgba(255,255,255,0.1); } .sj-header--hero .sj-logo-link img { filter: brightness(0) invert(1); transition: filter 0.4s ease; } .sj-header--hero .sj-logo-link span { color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-nav-pill { color: rgba(255,255,255,0.7); } .sj-header--hero .sj-nav-pill:hover { background: rgba(255,255,255,0.1); color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-nav-pill--active { background: rgba(255,255,255,0.15) !important; color: var(--t-tienda-texto-claro, #fff) !important; } .sj-header--hero .sj-nav-item { color: rgba(255,255,255,0.6); } .sj-header--hero .sj-nav-item:hover { color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-nav-item--active { color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-nav-underline { background: var(--t-tienda-fondo, #fff); } .sj-header--hero .sj-action-btn { color: rgba(255,255,255,0.8); } .sj-header--hero .sj-action-btn:hover { background: rgba(255,255,255,0.1); color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-avatar-mini { background: rgba(255,255,255,0.2); } .sj-header--hero .sj-badge--dark { background: var(--t-tienda-fondo, #fff); color: var(--t-tienda-texto, #000); } .sj-header--hero .sj-subcats { border-top-color: rgba(255,255,255,0.1); } .sj-header--hero .sj-subcat-chip { color: rgba(255,255,255,0.6); border-color: rgba(255,255,255,0.15); } .sj-header--hero .sj-subcat-chip:hover { background: rgba(255,255,255,0.1); color: var(--t-tienda-texto-claro, #fff); } .sj-header--hero .sj-subcat-chip--active { background: rgba(255,255,255,0.2) !important; color: var(--t-tienda-texto-claro, #fff) !important; border-color: rgba(255,255,255,0.3) !important; } .sj-header--hero .sj-partner { background: var(--t-tienda-oscuro, #0a0a0a) !important; background-image: none !important; } .sj-header--hero .sj-partner-border { opacity: 0.35; } .sj-header-inner { max-width: 1400px; margin: 0 auto; padding: 0 16px; } @media (min-width: 640px) { .sj-header-inner { padding: 0 24px; } } @media (min-width: 1024px) { .sj-header-inner { padding: 0 32px; } } /* La altura de la fila del logo, como variable: la necesita el recentrado de mas abajo y no puede quedarse escrita en dos sitios. */ :root { --sj-row-h: 60px; } .sj-header-row { height: var(--sj-row-h); display: flex; align-items: center; justify-content: space-between; gap: 16px; } /* 84, no 68. El logo mide 190px de alto y la fila 68: desbordaba 61px por arriba y por abajo, y aunque el flex lo centra, lo que se ve es un logo que se sale de su caja. Subiendo la fila el aire sobrante baja a 53 y el conjunto respira. No se sube mas porque la cabecera es sticky: cada pixel de alto es pantalla que el visitante pierde en todas las paginas. Ojo: esta altura la mide el ResizeObserver y alimenta --sj-header-h, de donde cuelga la barra de claims de debajo. Se recoloca sola. */ @media (min-width: 640px) { :root { --sj-row-h: 84px; } } /* \u2500\u2500 Logo \u2500\u2500 */ .sj-header-left { display: flex; align-items: center; gap: 10px; position: relative; z-index: 1; } .sj-logo-link { flex-shrink: 0; /* Centrado vertical EXPLICITO. Antes dependia solo del align-items del padre, y con un logo mas alto que la fila eso deja el resultado a merced del line-height del enlace: la imagen quedaba unos pixeles baja. Con el flex propio, la imagen se centra respecto al enlace y el enlace respecto a la fila. */ display: flex; align-items: center; line-height: 0; /* RECENTRADO CUANDO LA CABECERA CRECE. En la home la cabecera es una sola fila y el logo queda centrado. Al abrir el catalogo aparece la fila de filtros: la cabecera se hace mas alta, pero el logo vive en la fila de arriba y se quedaba pegado al techo, descentrado respecto al bloque que se ve. --sj-header-h es la altura REAL de la cabecera (la mide un ResizeObserver sobre el header, filtros incluidos). El centro de la cabecera esta en la mitad de eso; el de la fila del logo, en la mitad de --sj-row-h. La diferencia es lo que hay que bajar el logo, y sale sola con cualquier numero de filas: no hay que enumerar los casos (home, catalogo, subcategorias...). Va en transform y no en margin para no mover a nadie mas: el logo se desplaza sin empujar la navegacion ni cambiar la altura de la fila. */ transform: translateY(calc((var(--sj-header-h, 60px) - var(--sj-row-h)) / 2)); transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); } .sj-logo-img { height: 180px; } /* En movil el logo mide 180px de ancho dentro de un hueco de 144, asi que se metia 70px por DEBAJO de la fila de acciones; y como esa fila lleva z-index 2, el primer boton \u2014el idioma, "ES"\u2014 se pintaba ENCIMA del logo. No es un problema de z-index: es que en 390px no caben un logo de 180 y cinco botones de 38. Medido en iPhone (390px): acciones desde x=176, logo desde x=66. Con el boton a 34 la fila arranca en 196 y un logo de 120 termina en 186 \u2014 diez pixeles de aire. */ @media (max-width: 768px) { /* 100px, no 120: con 120 el borde derecho del logo cae en x=186 y la fila de acciones empieza en x=176 \u2014 se seguian solapando diez pixeles. Con 100 termina en 166 y quedan diez de aire. (El intento de encoger .sj-action-btn aqui no servia: su regla base esta declarada MAS ABAJO en esta misma hoja, asi que ganaba ella por orden.) */ .sj-logo-img { height: 124px; } /* SIN RECENTRADO EN MOVIL (17-sep-2026, aviso de Juan desde el movil). El recentrado de .sj-logo-link baja el logo (--sj-header-h - --sj-row-h) / 2. Esa cuenta esta pensada para ESCRITORIO, donde la cabecera crece al abrir la fila de filtros y el logo tiene que bajar con ella. En movil no hay fila de filtros, pero --sj-header-h SI es mucho mayor que --sj-row-h (60): la mide un ResizeObserver sobre el header entero, y el logo de 124px ya lo hace crecer el solo. Resultado: el logo se desplazaba decenas de pixeles hacia abajo, se salia de la banda oscura y se montaba encima de la barra \xABPartner oficial de Synergym\xBB. Aqui la cabecera es UNA fila: no hay nada que recentrar. */ .sj-header .sj-logo-link, .sj-header .sj-logo-link:hover { transform: none; } /* El logo sube de 100 a 124 y eso solo cabe si la fila de acciones se estrecha: con el boton a 38 arrancaba en x=176 y un logo de 124 termina en x=190 \u2014 se solapaban. A 34 la fila empieza en 196 y quedan seis pixeles de aire. OJO a la especificidad: la regla base de .sj-action-btn se declara MAS ABAJO en esta misma hoja, asi que una regla con la misma fuerza pierde por orden (ya paso una vez). Por eso lleva .sj-header delante. */ .sj-header .sj-action-btn { width: 34px; height: 34px; } /* BUSCADOR A LO ANCHO (19-oct-2026, Santi; maqueta de Bel\xE9n p. 12): en m\xF3vil la lupa se cambia por una barra debajo del logo que ocupa toda la fila. Es el MISMO bot\xF3n que el buscador de escritorio: abre el buscador de siempre. La fila se parte en dos como la de escritorio con men\xFA: arriba hamburguesa, logo e iconos; abajo, la barra. */ .sj-header .sj-header-row { flex-wrap: wrap; height: auto; row-gap: 0; } .sj-header .sj-header-row > .sj-header-left, .sj-header .sj-header-row > .sj-header-actions { height: var(--sj-row-h); } .sj-header .sj-header-row > .sj-busca-cab { display: flex; order: 3; flex: 0 0 100%; max-width: none; margin: 2px 0 10px; height: 42px; padding: 0 14px; font-size: 14px; } .sj-header .sj-lupa-cab { display: none; } } @media (min-width: 769px) { /* EL PNG DEL LOGO LLEVA UN MARCO TRANSPARENTE ENORME. Subir la altura a secas no agranda las letras: agranda el hueco vacio que las rodea. Con 190px de imagen, el texto STRONG med\xEDa unos 45 y la caja seguia ocupando 190, asi que se veia peque\xF1o Y descolocado dentro de su propio sitio. La cuenta sale del precedente de AuthModal (280px con -100 arriba y abajo, o sea 80px de caja util): el contenido visible es ~28% del alto total. Para unas letras de ~64px hacen falta 224 de imagen y -80 de margen a cada lado; la caja resultante mide 64 y ESO es lo que centra el flex de la fila. Lo correcto de verdad seria subir un logo recortado y quitar este apa\xF1o; mientras el asset tenga el marco, esto es lo que hay. */ .sj-logo-img { height: 224px; margin: -80px 0; display: block; } } .sj-logo-link img { transition: filter 0.4s ease; } /* El hover REPITE el desplazamiento: transform es una sola propiedad, y dejar aqui solo el scale borraria el recentrado \u2014 el logo daria un salto al pasar el raton por encima. */ .sj-logo-link:hover { transform: translateY(calc((var(--sj-header-h, 60px) - var(--sj-row-h)) / 2)) scale(1.06); } .sj-logo-link:active { transform: scale(0.97); } /* \u2500\u2500 Hamburger \u2192 X morph \u2500\u2500 */ .sj-hamburger { width: 40px; height: 40px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; border: none; background: transparent; cursor: pointer; padding: 0; border-radius: 50%; transition: background 0.2s ease; } .sj-hamburger:hover { background: rgba(0,0,0,0.05); } @media (min-width: 1280px) { .sj-hamburger { display: none !important; } } .sj-hamburger-line { display: block; width: 18px; height: 1.5px; background: var(--t-tienda-oscuro, #1a1a1a); transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease, background 0.4s ease; border-radius: 2px; transform-origin: center; } .sj-hamburger-line--open:nth-child(1) { transform: translateY(6.5px) rotate(45deg); } .sj-hamburger-line--open:nth-child(2) { opacity: 0; transform: scaleX(0); } .sj-hamburger-line--open:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); } /* \u2500\u2500 Nav (Desktop categories) \u2500\u2500 */ .sj-nav { display: none; align-items: center; justify-content: center; flex: 1; gap: 2px; position: relative; z-index: 2; overflow: hidden; flex-wrap: nowrap; } @media (min-width: 1280px) { .sj-nav { display: flex; } } .sj-nav-pill { padding: 5px 10px; font-size: 11px; font-weight: 600; letter-spacing: 0.01em; border-radius: 100px; white-space: nowrap; border: none; cursor: pointer; color: var(--t-tienda-texto2, #555); background: transparent; transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); } .sj-nav-pill:hover { background: rgba(0,0,0,0.05); color: var(--t-tienda-texto, #111); } .sj-nav-pill--active { background: var(--t-tienda-oscuro, #1a1a1a) !important; color: var(--t-tienda-texto-claro, #fff) !important; } .sj-nav-item { position: relative; padding: 5px 8px; font-size: 11px; font-weight: 500; letter-spacing: 0.01em; white-space: nowrap; border: none; cursor: pointer; color: var(--t-tienda-texto2, #666); background: transparent; transition: color 0.25s ease; } .sj-nav-item:hover { color: var(--t-tienda-texto, #111); } .sj-nav-item--active { color: var(--t-tienda-texto, #111); font-weight: 600; } .sj-nav-underline { position: absolute; bottom: -2px; left: 50%; width: 0; height: 1.5px; background: var(--t-tienda-oscuro, #1a1a1a); border-radius: 2px; transition: width 0.35s cubic-bezier(0.16, 1, 0.3, 1), left 0.35s cubic-bezier(0.16, 1, 0.3, 1); } .sj-nav-item:hover .sj-nav-underline { width: 60%; left: 20%; } .sj-nav-item--active .sj-nav-underline { width: 80%; left: 10%; } /* NOVEDADES: la unica entrada del nav con la letra en color. Sin marco ni fondo \u2014 basta el color y la mayuscula para que sea lo primero que se ve. Las mayusculas van aqui y no en el dato, para que el H1 de la pagina y el titulo de la pestana se queden legibles. \u26A0\uFE0F EL LIMA DE LA CASA NO SE LEE SOBRE BLANCO. Es un verde claro (#BAF455): como fondo va perfecto, pero de letra a 11 px sobre blanco se queda en nada. Por eso aqui se usa el MISMO color mezclado con el gris del texto: sigue siendo el verde de la marca \u2014y se tine solo si un gimnasio colaborador cambia la variable de acento\u2014 pero con contraste de verdad. La linea de antes es el color para navegadores que no entiendan color-mix. */ .sj-nav-item--nuevo { color: #5f8f14; color: color-mix(in srgb, var(--t-tienda-acento, var(--acento, #BAF455)) 58%, var(--t-tienda-texto, #1f252d)); font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; } .sj-nav-item--nuevo:hover { color: #4d7410; color: color-mix(in srgb, var(--t-tienda-acento, var(--acento, #BAF455)) 45%, var(--t-tienda-texto, #1f252d)); } .sj-nav-item--nuevo .sj-nav-underline { background: var(--t-tienda-acento, var(--acento, #BAF455)); height: 2px; } /* Sobre la cabecera del hero y la de categoria el fondo ya es oscuro: ahi el lima va a pelo, que es donde mejor luce. */ .sj-header--hero .sj-nav-item--nuevo, .sj-header--catmode .sj-nav-item--nuevo { color: var(--t-tienda-acento, var(--acento, #BAF455)); } .sj-header--hero .sj-nav-item--nuevo:hover, .sj-header--catmode .sj-nav-item--nuevo:hover { color: var(--t-tienda-acento, var(--acento, #BAF455)); filter: brightness(1.1); } /* \u2500\u2500 Action buttons \u2500\u2500 */ .sj-header-actions { display: flex; align-items: center; gap: 2px; position: relative; z-index: 2; } .sj-action-btn { position: relative; width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: none; background: transparent; color: var(--t-tienda-texto2, #555); cursor: pointer; transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1); } .sj-action-btn:hover { background: rgba(0,0,0,0.05); color: var(--t-tienda-texto, #111); transform: scale(1.08); } .sj-action-btn:active { transform: scale(0.93); } .sj-avatar-mini { width: 26px; height: 26px; border-radius: 50%; background: var(--t-tienda-oscuro, #1a1a1a); color: var(--t-tienda-texto-claro, #fff); display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; } .sj-avatar-mini--synergym { background: #059669; box-shadow: 0 0 0 2px rgba(5,150,105,0.3); } /* Badges */ .sj-badge { position: absolute; top: -2px; right: -2px; min-width: 17px; height: 17px; padding: 0 5px; border-radius: 100px; font-size: 9.5px; font-weight: 600; display: flex; align-items: center; justify-content: center; line-height: 1; pointer-events: none; } .sj-badge--dark { background: var(--t-tienda-oscuro, #1a1a1a); color: var(--t-tienda-texto-claro, #fff); } .sj-badge--red { background: var(--t-tienda-oferta, #ef4444); color: var(--t-tienda-texto-claro, #fff); } .sj-badge--pop { animation: sjBadgePop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); } @keyframes sjBadgePop { 0% { transform: scale(1); } 40% { transform: scale(1.5); } 100% { transform: scale(1); } } /* Cart spring bounce */ .sj-cart-btn--bounce { animation: sjCartBounce 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); } @keyframes sjCartBounce { 0% { transform: scale(1); } 20% { transform: scale(0.85); } 50% { transform: scale(1.2); } 70% { transform: scale(0.95); } 100% { transform: scale(1); } } /* \u2500\u2500 Subcategor\xEDas + filtros: una sola fila (.sj-catrow, 14-ago) \u2500\u2500 */ .sj-catrow { display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap; padding: 2px 16px 12px; } @media (max-width: 640px) { .sj-catrow { display: none; } } .sj-subcats { display: none; align-items: center; justify-content: center; gap: 6px; overflow-x: auto; scrollbar-width: none; } .sj-subcats::-webkit-scrollbar { display: none; } @media (min-width: 1280px) { .sj-subcats { display: flex; } } /* Filter bar \u2014 hidden on mobile, flex on desktop */ .sj-filter-bar-desktop { display: none; align-items: center; gap: 8px; } @media (min-width: 641px) { .sj-filter-bar-desktop { display: flex; } } /* Red de seguridad para cualquier