1<!doctype html> 2<html lang="es"> 3<head prefix="og: http://ogp.me/ns# category: http://ogp.me/ns/category#"> 4 <meta charset="utf-8"/> 5<meta name="title" content="Comprar Salones Modernos y de Diseño | Muebles Bonitos"/> 6<meta name="description" content="Muebles de salón modernos: aparadores, muebles TV, vitrinas, armarios y más. +365 modelos con envÃo gratuito y 3 años de garantÃa."/> 7<meta name="robots" content="INDEX,FOLLOW"/> 8<meta name="viewport" content="width=device-width, initial-scale=1"/> 9<title>Comprar Salones Modernos y de Diseño | Muebles Bonitos</title> 10 <link rel="stylesheet" type="text/css" media="all" href="https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/css/styles.css" /> 11<link rel="stylesheet" type="text/css" media="all" href="https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/css/custom_overrides.css" /> 12<link rel="stylesheet" type="text/css" media="all" href="https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/Amasty_ShopbyBase/css/chosen/chosen.css" />
13<script type="text/javascript" src="https://s.kk-resources.com/leadtag.js"></script>
13 14<link rel="canonical" href="https://www.mueblesbonitos.com/salon" /> 15<link rel="icon" type="image/x-icon" href="https://www.mueblesbonitos.com/media/favicon/stores/2/favicon.png" /> 16<link rel="shortcut icon" type="image/x-icon" href="https://www.mueblesbonitos.com/media/favicon/stores/2/favicon.png" /> 17
18<script> 19 // 1. Definimos el flag en el objeto window para que sea persistente a re-inyecciones de Hyvä 20 window.gtmIsInitialized = window.gtmIsInitialized || false; 21 22 (function() { 23 // 2. Si ya se marcó como inicializado, abortamos ejecución de este bloque inmediatamente 24 if (window.gtmIsInitialized) { 25 return; 26 } 27 28 var gtmLoaded = false; 29 30 var loadGTM = function() { 31 if (gtmLoaded) return; 32 gtmLoaded = true; 33 window.gtmIsInitialized = true; // Marcamos el flag global 34 35 (function(w,d,s,l,i){ 36 w[l]=w[l]||[]; 37 w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'}); 38 var f=d.getElementsByTagName(s)[0], 39 j=d.createElement(s), 40 dl=l!='dataLayer'?'&l='+l:''; 41 var script=d.createElement(s); 42 script.async=true; 43 script.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; 44 f.parentNode.insertBefore(script,f); 45 })(window,document,'script','dataLayer','GTM-TR9K4DK'); 46 47 // 3. Limpiamos todos los listeners para liberar memoria 48 ['scroll', 'mousemove', 'touchstart', 'click'].forEach(function(evt) { 49 window.removeEventListener(evt, loadGTM); 50 }); 51 }; 52 53 // 4. Escuchamos interacciones reales del usuario 54 ['scroll', 'mousemove', 'touchstart', 'click'].forEach(function(evt) { 55 window.addEventListener(evt, loadGTM, {passive: true}); 56 }); 57 58 // 5. Carga de seguridad: si no hay interacción, cargamos a los 6 segundos para no perder analÃtica 59 setTimeout(loadGTM, 3000); 60 })(); 61</script>
61 62 63
63<script> 64 window.motive = {"initParams":{"xEngineId":"9a837fe9-f00c-4c01-baff-02f7b44d45f9","lang":"es-ES","currency":"EUR","triggerSelector":"#site-search,#search_mini_form","isolated":true,"cartUrl":"https:\/\/www.mueblesbonitos.com\/checkout\/cart\/"},"options":{"shopperPrices":true,"priceRates":{"min":1,"max":1,"static":1}},"endpoints":{"shopperPrices":"https:\/\/www.mueblesbonitos.com\/motive\/results\/resultsenrichment\/?___store=mueblesbonitos_com_es"},"motive_x_url":"https:\/\/assets.motive.co\/motive-x\/v2\/app.js"}; 65 </script>
65 66
66<script id="motive-front-loader" async src="https://assets.motive.co/front-loader/magento/v1.js"></script>
vendor: 1 bytes, line 66
66
67<script> 68 var BASE_URL = 'https://www.mueblesbonitos.com/'; 69 var THEME_PATH = 'https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES'; 70 var COOKIE_CONFIG = { 71 "expires": null, 72 "path": "\u002F", 73 "domain": ".www.mueblesbonitos.com", 74 "secure": true, 75 "lifetime": "3600", 76 "cookie_restriction_enabled": false }; 77 var CURRENT_STORE_CODE = 'mueblesbonitos_com_es'; 78 var CURRENT_WEBSITE_ID = '2'; 79 80 window.hyva = window.hyva || {} 81 82 window.cookie_consent_groups = window.cookie_consent_groups || {} 83 window.cookie_consent_groups['necessary'] = true; 84 85 window.cookie_consent_config = window.cookie_consent_config || {}; 86 window.cookie_consent_config['necessary'] = [].concat( 87 window.cookie_consent_config['necessary'] || [], 88 [ 89 'user_allowed_save_cookie', 90 'form_key', 91 'mage-messages', 92 'private_content_version', 93 'mage-cache-sessid', 94 'last_visited_store', 95 'section_data_ids' 96 ] 97 ); 98 //# sourceURL=hyva-variables.js 99</script>
vendor: 1 bytes, line 99
99
100<script> 101 (function( hyva, undefined ) { 102 103 function lifetimeToExpires(options, defaults) { 104 105 const lifetime = options.lifetime || defaults.lifetime; 106 107 if (lifetime) { 108 const date = new Date; 109 date.setTime(date.getTime() + lifetime * 1000); 110 return date; 111 } 112 113 return null; 114 } 115 116 function generateRandomString() { 117 118 const allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 119 length = 16; 120 121 let formKey = '', 122 charactersLength = allowedCharacters.length; 123 124 for (let i = 0; i < length; i++) { 125 formKey += allowedCharacters[Math.round(Math.random() * (charactersLength - 1))] 126 } 127 128 return formKey; 129 } 130 131 const sessionCookieMarker = {noLifetime: true} 132 133 const cookieTempStorage = {}; 134 135 const internalCookie = { 136 get(name) { 137 const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); 138 return v ? v[2] : null; 139 }, 140 set(name, value, days, skipSetDomain) { 141 let expires, 142 path, 143 domain, 144 secure, 145 samesite; 146 147 const defaultCookieConfig = { 148 expires: null, 149 path: '/', 150 domain: null, 151 secure: false, 152 lifetime: null, 153 samesite: 'lax' 154 }; 155 156 const cookieConfig = window.COOKIE_CONFIG || {}; 157 158 expires = days && days !== sessionCookieMarker 159 ? lifetimeToExpires({lifetime: 24 * 60 * 60 * days, expires: null}, defaultCookieConfig) 160 : lifetimeToExpires(window.COOKIE_CONFIG, defaultCookieConfig) || defaultCookieConfig.expires; 161 162 path = cookieConfig.path || defaultCookieConfig.path; 163 domain = !skipSetDomain && (cookieConfig.domain || defaultCookieConfig.domain); 164 secure = cookieConfig.secure || defaultCookieConfig.secure; 165 samesite = cookieConfig.samesite || defaultCookieConfig.samesite; 166 167 document.cookie = name + "=" + encodeURIComponent(value) + 168 (expires && days !== sessionCookieMarker ? '; expires=' + expires.toGMTString() : '') + 169 (path ? '; path=' + path : '') + 170 (domain ? '; domain=' + domain : '') + 171 (secure ? '; secure' : '') + 172 (samesite ? '; samesite=' + samesite : 'lax'); 173 }, 174 isWebsiteAllowedToSaveCookie() { 175 const allowedCookies = this.get('user_allowed_save_cookie'); 176 if (allowedCookies) { 177 const allowedWebsites = JSON.parse(unescape(allowedCookies)); 178 179 return allowedWebsites[CURRENT_WEBSITE_ID] === 1; 180 } 181 return false; 182 }, 183 getGroupByCookieName(name) { 184 const cookieConsentConfig = window.cookie_consent_config || {}; 185 let group = null; 186 for (let prop in cookieConsentConfig) { 187 if (!cookieConsentConfig.hasOwnProperty(prop)) continue; 188 if (cookieConsentConfig[prop].includes(name)) { 189 group = prop; 190 break; 191 } 192 } 193 return group; 194 }, 195 isCookieAllowed(name) { 196 const cookieGroup = this.getGroupByCookieName(name); 197 return cookieGroup 198 ? window.cookie_consent_groups[cookieGroup] 199 : this.isWebsiteAllowedToSaveCookie(); 200 }, 201 saveTempStorageCookies() { 202 for (const [name, data] of Object.entries(cookieTempStorage)) { 203 if (this.isCookieAllowed(name)) { 204 this.set(name, data['value'], data['days'], data['skipSetDomain']); 205 delete cookieTempStorage[name]; 206 } 207 } 208 } 209 }; 210 211 hyva.getCookie = (name) => { 212 const cookieConfig = window.COOKIE_CONFIG || {}; 213 214 if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) { 215 return cookieTempStorage[name] ? cookieTempStorage[name]['value'] : null; 216 } 217 218 return internalCookie.get(name); 219 } 220 221 hyva.setCookie = (name, value, days, skipSetDomain) => { 222 const cookieConfig = window.COOKIE_CONFIG || {}; 223 224 if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) { 225 cookieTempStorage[name] = {value, days, skipSetDomain}; 226 return; 227 } 228 return internalCookie.set(name, value, days, skipSetDomain); 229 } 230 231 232 hyva.setSessionCookie = (name, value, skipSetDomain) => { 233 return hyva.setCookie(name, value, sessionCookieMarker, skipSetDomain) 234 } 235 236 hyva.getBrowserStorage = () => { 237 const browserStorage = window.localStorage || window.sessionStorage; 238 if (!browserStorage) { 239 console.warn('Browser Storage is unavailable'); 240 return false;
241 } 242 try { 243 browserStorage.setItem('storage_test', '1'); 244 browserStorage.removeItem('storage_test'); 245 } catch (error) { 246 console.warn('Browser Storage is not accessible', error); 247 return false; 248 } 249 return browserStorage; 250 } 251 252 hyva.postForm = (postParams) => { 253 const form = document.createElement("form"); 254 255 let data = postParams.data; 256 257 if (! postParams.skipUenc && ! data.uenc) { 258 data.uenc = btoa(window.location.href); 259 } 260 form.method = "POST"; 261 form.action = postParams.action; 262 263 Object.keys(postParams.data).map(key => { 264 const field = document.createElement("input"); 265 field.type = 'hidden' 266 field.value = postParams.data[key]; 267 field.name = key; 268 form.appendChild(field); 269 }); 270 271 const form_key = document.createElement("input"); 272 form_key.type = 'hidden'; 273 form_key.value = hyva.getFormKey(); 274 form_key.name="form_key"; 275 form.appendChild(form_key); 276 277 document.body.appendChild(form); 278 279 form.submit(); 280 } 281 282 hyva.getFormKey = function () { 283 let formKey = hyva.getCookie('form_key'); 284 285 if (!formKey) { 286 formKey = generateRandomString(); 287 hyva.setCookie('form_key', formKey); 288 } 289 290 return formKey; 291 } 292 293 hyva.formatPrice = (value, showSign, options = {}) => { 294 const groupSeparator = options.groupSeparator; 295 const decimalSeparator = options.decimalSeparator 296 delete options.groupSeparator; 297 delete options.decimalSeparator; 298 const formatter = new Intl.NumberFormat( 299 'es\u002DES', 300 Object.assign({ 301 style: 'currency', 302 currency: 'EUR', 303 signDisplay: showSign ? 'always' : 'auto' 304 }, options) 305 ); 306 return (typeof Intl.NumberFormat.prototype.formatToParts === 'function') ? 307 formatter.formatToParts(value).map(({type, value}) => { 308 switch (type) { 309 case 'currency': 310 return '\u20AC' || value; 311 case 'minusSign': 312 return '- '; 313 case 'plusSign': 314 return '+ '; 315 case 'group': 316 return groupSeparator !== undefined ? groupSeparator : value; 317 case 'decimal': 318 return decimalSeparator !== undefined ? decimalSeparator : value; 319 default : 320 return value; 321 } 322 }).reduce((string, part) => string + part) : 323 formatter.format(value); 324 } 325 326 const formatStr = function (str, nStart) { 327 const args = Array.from(arguments).slice(2); 328 329 return str.replace(/(%+)([0-9]+)/g, (m, p, n) => { 330 const idx = parseInt(n) - nStart; 331 332 if (args[idx] === null || args[idx] === void 0) { 333 return m; 334 } 335 return p.length % 2 336 ? p.slice(0, -1).replace('%%', '%') + args[idx] 337 : p.replace('%%', '%') + n; 338 }) 339 } 340 341 hyva.str = function (string) { 342 const args = Array.from(arguments); 343 args.splice(1, 0, 1); 344 345 return formatStr.apply(undefined, args); 346 } 347 348 hyva.strf = function () { 349 const args = Array.from(arguments); 350 args.splice(1, 0, 0); 351 352 return formatStr.apply(undefined, args); 353 } 354 355 /** 356 * Take a html string as `content` parameter and 357 * extract an element from the DOM to replace in 358 * the current page under the same selector, 359 * defined by `targetSelector` 360 */ 361 hyva.replaceDomElement = (targetSelector, content) => { 362 // Parse the content and extract the DOM node using the `targetSelector` 363 const parser = new DOMParser(); 364 const doc = parser.parseFromString(content, 'text/html');
365 const contentNode = doc.querySelector(targetSelector); 366 367 // Bail if content or target can't be found 368 if (!contentNode || !document.querySelector(targetSelector)) { 369 return; 370 } 371 372 hyva.activateScripts(contentNode); 373 374 // Replace the old DOM node with the new content 375 document.querySelector(targetSelector).replaceWith(contentNode); 376 377 // Reload customerSectionData and display cookie-messages if present 378 window.dispatchEvent(new CustomEvent("reload-customer-section-data")); 379 hyva.initMessages(); 380 } 381 382 hyva.removeScripts = (contentNode) => { 383 const scripts = contentNode.getElementsByTagName('script'); 384 for (let i = 0; i < scripts.length; i++) { 385 scripts[i].parentNode.removeChild(scripts[i]); 386 } 387 const templates = contentNode.getElementsByTagName('template'); 388 for (let i = 0; i < templates.length; i++) { 389 const container = document.createElement('div'); 390 container.innerHTML = templates[i].innerHTML; 391 hyva.removeScripts(container); 392 templates[i].innerHTML = container.innerHTML; 393 } 394 } 395 396 hyva.activateScripts = (contentNode) => { 397 // Create new array from HTMLCollection to avoid mutation of collection while manipulating the DOM. 398 const scripts = Array.from(contentNode.getElementsByTagName('script')); 399 400 // Iterate over all script tags to duplicate+inject each into the head 401 for (const original of scripts) { 402 const script = document.createElement('script'); 403 original.type && (script.type = original.type); 404 script.innerHTML = original.innerHTML; 405 406 // Remove the original (non-executing) script from the contentNode 407 original.parentNode.removeChild(original) 408 409 // Add script to head 410 document.head.appendChild(script); 411 } 412 413 return contentNode; 414 } 415 416 const replace = {['+']: '-', ['/']: '_', ['=']: ','}; 417 hyva.getUenc = () => btoa(window.location.href).replace(/[+/=]/g, match => replace[match]); 418 419 let currentTrap; 420 421 const focusableElements = (rootElement) => { 422 const selector = 'button, [href], input, select, textarea, details, [tabindex]:not([tabindex="-1"]'; 423 return Array.from(rootElement.querySelectorAll(selector)) 424 .filter(el => { 425 return el.style.display !== 'none' 426 && !el.disabled 427 && el.tabIndex !== -1 428 && (el.offsetWidth || el.offsetHeight || el.getClientRects().length) 429 }) 430 } 431 432 const focusTrap = (e) => { 433 const isTabPressed = e.key === 'Tab' || e.keyCode === 9; 434 if (!isTabPressed) return; 435 436 const focusable = focusableElements(currentTrap) 437 const firstFocusableElement = focusable[0] 438 const lastFocusableElement = focusable[focusable.length - 1] 439 440 e.shiftKey 441 ? document.activeElement === firstFocusableElement && (lastFocusableElement.focus(), e.preventDefault()) 442 : document.activeElement === lastFocusableElement && (firstFocusableElement.focus(), e.preventDefault()) 443 }; 444 445 hyva.releaseFocus = (rootElement) => { 446 if (currentTrap && (!rootElement || rootElement === currentTrap)) { 447 currentTrap.removeEventListener('keydown', focusTrap) 448 currentTrap = null 449 } 450 } 451 hyva.trapFocus = (rootElement) => { 452 if (!rootElement) return; 453 hyva.releaseFocus() 454 currentTrap = rootElement 455 rootElement.addEventListener('keydown', focusTrap) 456 const firstElement = focusableElements(rootElement)[0] 457 firstElement && firstElement.focus() 458 } 459 460 hyva.safeParseNumber = (rawValue) => { 461 const number = rawValue ? parseFloat(rawValue) : null; 462 463 return Array.isArray(number) || isNaN(number) ? rawValue : number; 464 } 465 466 const toCamelCase = s => s.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(''); 467 hyva.createBooleanObject = (name, value = false, additionalMethods = {}) => { 468 469 const camelCase = toCamelCase(name);
470 const key = '__hyva_bool_' + name 471 472 return new Proxy(Object.assign( 473 additionalMethods, 474 { 475 [key]: !!value, 476 [name]() {return !!this[key]}, 477 ['!' + name]() {return !this[key]}, // @deprecated This does not work with non-CSP Alpine 478 ['not' + camelCase]() {return !this[key]}, 479 ['toggle' + camelCase]() {this[key] = !this[key]}, 480 [`set${camelCase}True`]() {this[key] = true}, 481 [`set${camelCase}False`]() {this[key] = false}, 482 } 483 ), { 484 set(target, prop, value) { 485 return prop === name 486 ? (target[key] = !!value) 487 : Reflect.set(...arguments); 488 } 489 }) 490 } 491 492 hyva.alpineInitialized = (fn) => window.addEventListener('alpine:initialized', fn, {once: true}) 493 window.addEventListener('alpine:init', () => Alpine.data('{}', () => ({})), {once: true}); 494 window.addEventListener('user-allowed-save-cookie', () => internalCookie.saveTempStorageCookies()) 495 496 }( window.hyva = window.hyva || {} )); 497 //# sourceURL=hyva.js 498</script>
vendor: 1 bytes, line 498
498
499<script type="speculationrules"> 500{ 501 "tag": "Hyva Theme", 502 "prefetch": [{ 503 "source": "document", 504 "where": { 505 "and": [ 506 { "href_matches": "/*" }, 507 { "not": { 508 "href_matches": ["/customer/*","/search/*","/sales/*","/wishlist/*","/checkout/*","/paypal/*","/newsletter/*","/stores/store/redirect/*"] }}, 509 { "not": { 510 "selector_matches": [".no-preload", ".do-not-prerender", "[download]", "[rel~=nofollow]", "[target]"] 511 }} 512 ] 513 }, 514 "eagerness": "moderate" 515 }] 516} 517</script>
517 518 519<meta property="og:type" content="category"/> 520 521 <meta property="og:title" content="Comprar Salones Modernos y de Diseño | Muebles Bonitos"/> 522 523 <meta property="og:description" content="Muebles de salón modernos: aparadores, muebles TV, vitrinas, armarios y más. +365 modelos con envÃo gratuito y 3 años de garantÃa."/> 524 525<meta property="og:url" content="https://www.mueblesbonitos.com/salon"/> 526 527 528<meta property="og:site_name" content="mueblesbonitos.com"/>
529<script> 530 (function () { 531 let amSplideProcessed = false; 532 533 window.addEventListener('load-amsplide', () => { 534 if (amSplideProcessed) { 535 window?.Splide && window.dispatchEvent(new CustomEvent('amsplide-loaded', {})); 536 return; 537 } 538 539 const script = document.createElement('script'); 540 script.src = 'https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/Amasty_LibSplideJs/4.1.3/js/splide/splide.min.js'; 541 script.async = true; 542 document.body.appendChild(script); 543 544 amSplideProcessed = true; 545 546 script.onload = () => { 547 window.dispatchEvent(new CustomEvent('amsplide-loaded', {})); 548 } 549 550 const stylesHref = 'https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/Amasty_LibSplideJs/4.1.3/css/splide/splide.min.css'; 551 552 if (document.querySelector(`link[href="${stylesHref}"]`)) { 553 return; 554 } 555 556 const styles = document.createElement('link'); 557 styles.rel = 'stylesheet'; 558 styles.type = 'text/css'; 559 styles.href = stylesHref; 560 561 document.head.appendChild(styles); 562 }); 563 }()); 564</script>
564 565<link rel="next" href="https://www.mueblesbonitos.com/salon?p=2" /> 566</head> 567<body id="html-body" class="page-with-filter page-products categorypath-salon category-salon catalog-category-view page-layout-1column"> 568 569 570 <!-- RESTO DEL SITIO: versión original con Alpine y carrusel --> 571 <div id="site-notice" class="notice-fixed"> 572 <div class="text-white text-sm leading-5 font-semibold" style="background-color:#34515E;"> 573 <div 574 class="max-w-7xl mx-auto flex justify-center items-center" 575 x-data='{ activeIndex: 0, messages: ["<span class=\"flex items-center space-x-2 font-light\"> <a href=\"https:\/\/www.mueblesbonitos.com\/reviews_mb\" class=\"flex items-center space-x-1 hover:underline\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"h-4 w-4 fill-current text-white\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.62L12 2 9.19 8.62 2 9.24l5.46 4.73L5.82 21z\"\/>\n <\/svg><span>4,6<\/span><span class=\"ml-1 inline-flex items-center gap-1 rounded-full bg-white\/10 px-2 py-0.5 text-[11px] font-medium text-white\/90 ring-1 ring-white\/20\">Google<\/span><\/a><span class=\"ml-2\"><a href=\"tel: +34 965 104 517\"> Tel: +34 965 104 517<a href= \"https:\/\/api.whatsapp.com\/send?phone=34697303158&text=Hola\" target=\"_blank\" rel=\"noindex,nofollow\"> Whatsapp<i class=\"fa fa-whatsapp\" aria-hidden=\"true\" style=\"font-size: 20px;\"><\/i><\/a> <\/span><\/span>","<span class=\"font-light\">Viernes 9 cerrado por festivo<\/span>"] }' 576 x-init="setInterval(() => { activeIndex = (activeIndex + 1) % messages.length }, 5000);"> 577 <div class="transition-opacity duration-500 ease-in-out text-center px-3"> 578 <span x-html="messages[activeIndex]"></span> 579 </div> 580 </div> 581 </div> 582 </div> 583 584<!-- Google Tag Manager (noscript) -->
vendor: 73 bytes, lines 584-586
584 585<noscript> 586 <iframe src="https://www.googletagmanager.com/ns.html?id=
586GTM-TR9K4DK
vendor: 96 bytes, lines 586-588
586" 587 height="0" width="0" style="display:none;visibility:hidden"></iframe> 588</noscript>
589<!-- End Google Tag Manager (noscript) --> 590<input name="form_key" type="hidden" value="GoQ6wnK4Gflfjncs" /> 591 <noscript> 592 <section class="message global noscript border-b-2 border-blue-500 bg-blue-50 shadow-none m-0 px-0 rounded-none font-normal"> 593 <div class="container text-center"> 594 <p> 595 <strong>JavaScript seems to be disabled in your browser.</strong> 596 <span> 597 For the best experience on our site, be sure to turn on Javascript in your browser. </span> 598 </p> 599 </div> 600 </section> 601 </noscript> 602 603
604<script> 605 document.body.addEventListener('touchstart', () => {}, {passive: true}) 606</script>
vendor: 1 bytes, line 606
606
607<script> 608 (function(hyva) { 609 const formValidationRules = { 610 required(value, options, field, context) { 611 const el = field.element.type === 'hidden' ? createTextInputFrom(field.element) : field.element, 612 fieldName = getFieldName(field), 613 msg = fieldName 614 ? hyva.str('El\u0020campo\u0020\u00251\u0020es\u0020obligatorio.', fieldName) 615 : 'Este\u0020es\u0020un\u0020campo\u0020obligatorio.'; 616 617 if (el.type === 'radio' || el.type === 'checkbox') { 618 return (value === undefined || value.length === 0) ? msg : true; 619 } 620 621 el.setAttribute('required', ''); 622 el.checkValidity(); 623 624 return el.validity.valueMissing ? msg : true; 625 }, 626 maxlength(value, options, field, context) { 627 const n = Number(options) 628 if (value.length > n) { 629 const fieldName = getFieldName(field); 630 return fieldName 631 ? n === 1 632 ? hyva.str('El\u0020campo\u0020\u00251\u0020no\u0020puede\u0020tener\u0020m\u00E1s\u0020de\u00201\u0020car\u00E1cter.', fieldName) 633 : hyva.str('El\u0020campo\u0020\u00251\u0020no\u0020puede\u0020tener\u0020m\u00E1s\u0020de\u0020\u00252\u0020caracteres.', fieldName, options) 634 : n === 1 635 ? 'Por\u0020favor,\u0020no\u0020introduzcas\u0020m\u00E1s\u0020de\u00201\u0020car\u00E1cter.' 636 : hyva.strf('Por\u0020favor,\u0020no\u0020introduzcas\u0020m\u00E1s\u0020de\u0020\u00250\u0020caracteres.', options); 637 } 638 return true; 639 }, 640 minlength(value, options, field, context) { 641 const n = Number(options) 642 if (value.length > 0 && value.length < n) { 643 const fieldName = getFieldName(field); 644 return fieldName 645 ? n === 1 646 ? hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020tener\u0020al\u0020menos\u00201\u0020car\u00E1cter.', fieldName) 647 : hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020tener\u0020al\u0020menos\u0020\u00252\u0020caracteres.', fieldName, options) 648 : n === 1 649 ? 'Por\u0020favor,\u0020introduce\u0020al\u0020menos\u00201\u0020car\u00E1cter.' 650 : hyva.strf('Por\u0020favor,\u0020introduce\u0020al\u0020menos\u0020\u00250\u0020caracteres.', options); 651 } 652 return true; 653 }, 654 max(value, options, field, context) { 655 field.element.setAttribute('max', options); 656 field.element.checkValidity(); 657 if (field.element.validity.rangeOverflow) { 658 const fieldName = getFieldName(field); 659 return fieldName 660 ? hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020contener\u0020un\u0020valor\u0020menor\u0020o\u0020igual\u0020a\u0020\u0022\u00252\u0022.', fieldName, options) 661 : hyva.strf('Por\u0020favor,\u0020introduce\u0020un\u0020valor\u0020menor\u0020o\u0020igual\u0020a\u0020\u0022\u00250\u0022.', options); 662 } 663 return true; 664 }, 665 min(value, options, field, context) { 666 field.element.setAttribute('min', options); 667 field.element.checkValidity(); 668 if (field.element.validity.rangeUnderflow) { 669 const fieldName = getFieldName(field); 670 return fieldName 671 ? hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020contener\u0020un\u0020valor\u0020mayor\u0020o\u0020igual\u0020a\u0020\u0022\u00252\u0022.', fieldName, options) 672 : hyva.strf('Por\u0020favor,\u0020introduce\u0020un\u0020valor\u0020mayor\u0020o\u0020igual\u0020a\u0020\u0022\u00250\u0022.', options); 673 } 674 return true; 675 }, 676 step(value, options, field, context) { 677 field.element.setAttribute('step', options); 678 field.element.checkValidity(); 679 if (field.element.validity.stepMismatch) { 680 const val = Number(value), 681 step = Number(options), 682 fieldName = getFieldName(field), 683 nearestLowerValue = Math.floor(val / step) * step,
684 nearestUpperValue = Math.ceil(val / step) * step; 685 return fieldName 686 ? hyva.str('El\u0020campo\u0020\u00251\u0020no\u0020es\u0020v\u00E1lido.\u0020Los\u0020dos\u0020valores\u0020v\u00E1lidos\u0020m\u00E1s\u0020cercanos\u0020son\u0020\u0022\u00252\u0022\u0020y\u0020\u0022\u00253\u0022.', fieldName, nearestLowerValue, nearestUpperValue) 687 : hyva.strf('Por\u0020favor,\u0020introduce\u0020un\u0020valor\u0020v\u00E1lido.\u0020Los\u0020dos\u0020valores\u0020v\u00E1lidos\u0020m\u00E1s\u0020cercanos\u0020son\u0020\u0022\u00250\u0022\u0020y\u0020\u0022\u00251\u0022.', nearestLowerValue, nearestUpperValue); 688 } 689 return true; 690 }, 691 pattern(value, options, field, context) { 692 field.element.setAttribute('pattern', options); 693 field.element.checkValidity(); 694 if (field.element.validity.patternMismatch) { 695 const fieldName = getFieldName(field); 696 return fieldName 697 ? field.element.pattern 698 ? hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020coincidir\u0020con\u0020el\u0020formato\u0020solicitado\u003A\u0020\u00252.', fieldName, field.element.pattern) 699 : hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020coincidir\u0020con\u0020el\u0020formato\u0020solicitado.', fieldName) 700 : field.element.pattern 701 ? hyva.strf('Por\u0020favor,\u0020utiliza\u0020el\u0020formato\u0020solicitado\u003A\u0020\u00250.', field.element.pattern) 702 : 'Por\u0020favor,\u0020utiliza\u0020el\u0020formato\u0020solicitado.'; 703 } 704 return true; 705 }, 706 email(value, options, field, context) { 707 const rule = /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i; 708 if (value.length > 0 && !rule.test(value)) { 709 const fieldName = getFieldName(field); 710 return fieldName 711 ? hyva.str('El\u0020campo\u0020\u00251\u0020debe\u0020contener\u0020una\u0020direcci\u00F3n\u0020de\u0020correo\u0020v\u00E1lida\u0020\u0028Ej\u003A\u0020juandiez\u0040dominio.com\u0029.', fieldName) 712 : 'Por\u0020favor,\u0020introduce\u0020una\u0020direcci\u00F3n\u0020de\u0020correo\u0020v\u00E1lida\u0020\u0028Ej\u003A\u0020juandiez\u0040dominio.com\u0029.'; 713 } 714 return true; 715 }, 716 password(value, options, field, context) { 717 const rule = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; 718 if (value.length > 0 && !rule.test(value)) { 719 const fieldName = getFieldName(field); 720 return fieldName 721 ? hyva.str('\u00251\u0020field\u0020must\u0020contain\u0020at\u0020least\u0020one\u0020upper\u0020case,\u0020one\u0020lower\u0020case,\u0020one\u0020digit\u0020and\u0020one\u0020special\u0020character\u0020\u0028\u0023\u003F\u0021\u0040\u0024\u0025\u005E\u0026\u002A\u002D\u0029', fieldName) 722 : 'Indique\u0020al\u0020menos\u0020una\u0020may\u00FAscula,\u0020una\u0020min\u00FAscula,\u0020un\u0020d\u00EDgito\u0020y\u0020un\u0020car\u00E1cter\u0020especial\u0020\u0028\u0023\u003F\u0021\u0040\u0024\u0025\u005E\u0026amp\u003B\u002A\u002D\u0029'; 723 } 724 return true; 725 }, 726 equalTo(value, options, field, context) { 727 const dependencyField = context.fields[options].element; 728 if (value !== dependencyField.value) { 729 const dependencyFieldName = 730 dependencyField.label || 731 dependencyField.title || 732 (dependencyField.labels && dependencyField.labels[0] && dependencyField.labels[0].innerText) || 733 dependencyField.name, 734 fieldName = getFieldName(field); 735 return fieldName 736 ? hyva.str('El\u0020valor\u0020del\u0020campo\u0020\u00251\u0020debe\u0020ser\u0020igual\u0020a\u0020\u0022\u00252\u0022.', fieldName, dependencyFieldName) 737 : hyva.strf('El\u0020valor\u0020de\u0020este\u0020campo\u0020debe\u0020ser\u0020igual\u0020a\u0020\u0022\u00250\u0022.', dependencyFieldName); 738 } 739 return true; 740 } 741 }; 742 743 function raceSome(promises, pred) { 744 return new Promise((resolve, reject) => { 745 746 if (promises.length === 0) { 747 return resolve(); 748 } 749 750 let settled = false, nDone = 0; 751 752 const resolveIf = v => { 753 if (!settled && (pred(v) || ++nDone === promises.length)) { 754 settled = true; 755 resolve(v); 756 } 757 return v; 758 } 759 760 promises.map(promise => {
761 promise.then(resolveIf).catch(reason => { 762 settled = true; 763 reject(reason) 764 }); 765 return promise; 766 }); 767 }); 768 } 769 770 const INPUT_ATTRIBUTE_RULES = {min: 'min', max: 'max', required: 'required', minlength: 'minlength', maxlength: 'maxlength', step: 'step', pattern: 'pattern'} 771 const INPUT_TYPE_RULES = {email: 'email'} 772 773 function getRules(element) { 774 let rules = {}; 775 Object.keys(INPUT_ATTRIBUTE_RULES).forEach(attrName => { 776 if (element.hasAttribute(attrName)) { 777 rules[INPUT_ATTRIBUTE_RULES[attrName]] = element.getAttribute(attrName); 778 } 779 }) 780 if (INPUT_TYPE_RULES[element.type]) { 781 rules[INPUT_TYPE_RULES[element.type]] = true; 782 } 783 784 if (element.dataset.validate) { 785 try { 786 Object.assign(rules, JSON.parse(element.dataset.validate)); 787 } catch (error) { 788 console.error('Validator error. Cannot parse data-validate attribute of element:\n', element); 789 } 790 } 791 792 return rules; 793 } 794 795 function isInvalidRuleResult(ruleState) { 796 return typeof ruleState === 'string' || !ruleState || (ruleState.type && ruleState.content); 797 } 798 799 async function runValidateFn(rule, options, value, field) { 800 return formValidationRules[rule](value, options, field, this); 801 } 802 803 function generateId() { 804 let id; 805 do { 806 id = `${this.idPrefix}-${++this.idSeq}`; 807 } while (document.getElementById(id)); 808 return id; 809 } 810 811 function isVisible(element) { 812 const el = element.type !== 'hidden' ? element : (element.parentElement || {}); 813 return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length) 814 } 815 816 function elementWillValidate(element) { 817 return (element.willValidate || element.type === 'hidden') 818 && element.tagName !== 'BUTTON' 819 && element.disabled === false 820 && !(element.tagName === 'INPUT' && element.type === 'submit') 821 && (element.hasAttribute('data-validate-hidden') || isVisible(element)) 822 } 823 824 function createMessageContainer(el, fieldWrapperClassName) { 825 if (! el.parentElement) { 826 return; 827 } 828 const refocus = document.activeElement === el; 829 const wrapper = document.createElement('div'); 830 wrapper.classList.add.apply(wrapper.classList, fieldWrapperClassName.split(' ')); 831 el.parentElement.insertBefore(wrapper, el); 832 wrapper.appendChild(el); 833 refocus && document.activeElement !== el && el.focus(); 834 return wrapper; 835 } 836 837 function containerNotFound(selector, el) { 838 const msg = `Cannot find message container element ${selector} of ${el.name}`; 839 console.error(msg, el); 840 throw msg; 841 } 842 843 function createTextInputFrom(el) { 844 const text = document.createElement('INPUT'); 845 text.type = 'text'; 846 text.value = el.value; 847 return text; 848 } 849 850 function classNamesToSelector(classNames) { 851 return classNames.split(' ') 852 .filter(className => className.length > 0) 853 .map(className => `.${className}`) 854 .join('') 855 } 856 857 function hasMessagesWrapper(field, messagesWrapperClassName) { 858 return this.getMessageContainer(field).querySelector(classNamesToSelector(messagesWrapperClassName)); 859 } 860 861 function getMessagesWrapper(field, messagesWrapperClassName) { 862 if (hasMessagesWrapper.call(this, field, messagesWrapperClassName)) { 863 return this.getMessageContainer(field).querySelector(classNamesToSelector(messagesWrapperClassName)); 864 } 865 866 const msgWrapper = document.createElement('ul'); 867 const msgId = generateId.call(this); 868 msgWrapper.id = msgId; 869 field.element.setAttribute('aria-errormessage', msgId); 870 field.element.setAttribute('aria-describedby', msgId); 871 msgWrapper.classList.add.apply(msgWrapper.classList, messagesWrapperClassName.split(' ')); 872 if (field.validateOnChange) { 873 msgWrapper.setAttribute('aria-live', 'polite'); 874 } 875 this.getMessageContainer(field).appendChild(msgWrapper); 876 877 return msgWrapper; 878 } 879 880 function getCheckedValues(field) { 881 const name = field.element.name.replace(/([\\"])/g, '\\$1'); 882 const elements = field.element.form.querySelectorAll('input[name="' + name + '"]:checked'); 883 return Array.from(elements).map(el => el.value); 884 } 885 886 function escapeHtml(s) { 887 const div = document.createElement('div') 888 div.innerText = s; 889 return div.innerHTML; 890 } 891 892 893 function formValidation(form, options = {}) { 894 const formElement = form || this.$el; 895 896 if (formElement.dataset && formElement.dataset.options) { 897 try { 898 options = Object.assign(options, JSON.parse(formElement.dataset.options || '{}')); 899 } catch (e) { 900 throw new Error('Cannot read the form options from the data-options attribute: not val
900id JSON'); 901 } 902 } 903 904 // Disable browser default validation 905 if (formElement.tagName === 'FORM') { 906 formElement.setAttribute('novalidate', ''); 907 } else { 908 console.error('formValidation can be initialized only on FORM element', formElement); 909 return; 910 } 911 912 options = Object.assign({ 913 fieldWrapperClassName: 'field field-reserved', 914 messagesWrapperClassName: 'messages', 915 validClassName: 'field-success', 916 invalidClassName: 'field-error', 917 pageMessagesWrapperSelector: null, 918 scrollToFirstError: true, 919 }, options || {}); 920 921 return { 922 state: { 923 valid: false, 924 }, 925 fields: {}, 926 idSeq: 0, 927 idPrefix: formElement.id || 'vld-msg', 928 setupFields(elements) { 929 this.fields = {}; 930 Array.from(elements).forEach(element => { 931 if (elementWillValidate(element)) { 932 this.setupField(element); 933 } 934 }); 935 }, 936 setupField(element) { 937 if (! element) return; 938 const onChange = !!element.dataset.onChange; 939 if (elementWillValidate(element)) { 940 const rules = getRules(element); 941 if (Object.keys(rules).length > 0) { 942 if (this.fields[element.name]) { 943 Object.assign(this.fields[element.name].rules, rules); 944 } else { 945 this.fields[element.name] = { 946 element, 947 rules: rules, 948 validateOnChange: onChange, 949 state: { 950 valid: null, 951 rules: {} 952 } 953 } 954 } 955 } 956 } else { 957 console.error('Element will not validate', element); 958 } 959 }, 960 onSubmit(event) { 961 if (event.target.tagName === 'FORM') { 962 event.preventDefault(); 963 964 this.validate() 965 .then(() => event.target.submit()) 966 .catch(invalidElements => {}); 967 } 968 }, 969 onChange(event) { 970 event.target.dataset.onChange = 'true'; 971 if (!Object.keys(this.fields).length) { 972 this.setupFields(formElement.elements); 973 } 974 if (!Object.keys(this.fields).includes(event.target.name)) { 975 this.setupField(event.target); 976 } 977 const field = this.fields[event.target.name]; 978 979 this.validateField(field); 980 field && field.element.removeAttribute('data-on-change') 981 }, 982 validateSafe() { 983 return new Promise(resolve => this.validate().then(() => resolve(true)).catch(() => {})) 984 }, 985 validate() { 986 if (!Object.keys(this.fields).length || !Object.keys(this.fields).length !== formElement.elements.length) { 987 this.setupFields(formElement.elements); 988 } 989 return new Promise(async (resolve, reject) => { 990 if (formElement.elements) { 991 await raceSome(this.validateFields(), result => result !== true) 992 const invalidFields = Object.values(this.fields).filter(field => !field.state.valid); 993 this.state.valid = invalidFields.length === 0; 994 if (this.state.valid) { 995 resolve(); 996 } else { 997 if (options.scrollToFirstError && invalidFields.length > 0) { 998 invalidFields[0].element.focus() 999 invalidFields[0].element.select && invalidFields[0].element.select(); 1000 } 1001 reject(invalidFields.map(field => field.element)); 1002 } 1003 } 1004 }); 1005 }, 1006 validateFields() { 1007 const fields = Object.values(this.fields); 1008 1009 fields.forEach(field => { 1010 this.getMessageContainer(field).classList.remove(options.validClassName, options.invalidClassName) 1011 }); 1012 return fields.map(field => this.validateField(field)) 1013 }, 1014 validateField(field) { 1015 if (! field || ! elementWillValidate(field.element)) { 1016 return new Promise(resolve => resolve(true)) 1017 } 1018 1019 let value; 1020 if (field.element.type === 'checkbox') { 1021 value = getCheckedValues(field); 1022 } else if (field.element.type === 'radio') { 1023 value = getCheckedValues(field)[0] || undefined; 1024 } else if (field.element.tagName === 'SELECT' && field.element.multiple) { 1025 value = Array.from(field.element.selectedOptions).map(opt => opt.value); 1026 } else { 1027 value = field.element.value; 1028 } 1029 1030 const rules = field.rules || {}; 1031 1032 field.state.valid = true;
1033 this.showFieldState(field); 1034 1035 1036 const fieldValidations = Object.keys(rules).filter(rule => formValidationRules[rule]).map(async rule => { 1037 return runValidateFn.call(this, rule, rules[rule], value, field).then(result => { 1038 field.state.rules[rule] = result; 1039 return result; 1040 }) 1041 }); 1042 1043 return new Promise(resolve => { 1044 Promise.all(fieldValidations).then(results => { 1045 field.state.valid = !elementWillValidate(field.element) || rules.length === 0 || !results.some(isInvalidRuleResult) 1046 this.showFieldState(field); 1047 resolve(field.state.valid); 1048 }) 1049 }); 1050 }, 1051 getMessagesByField(field) { 1052 const messages = []; 1053 const invalidRules = Object.keys(field.state.rules).filter(rule => isInvalidRuleResult(field.state.rules[rule])); 1054 1055 field.rules && Object.keys(field.rules).forEach((rule) => { 1056 if (invalidRules.includes(rule)) { 1057 const customMessage = field.element.getAttribute('data-msg-' + rule); 1058 const message = customMessage ? customMessage : field.state.rules[rule]; 1059 const ruleOptions = JSON.parse(JSON.stringify(field.rules[rule])); 1060 1061 if (typeof message === 'undefined' || message === null || (typeof message !== 'string' && ! message.type)) { 1062 messages.push(hyva.strf('Validation rule "%0" failed.', rule)); 1063 } else if (Array.isArray(ruleOptions)) { 1064 ruleOptions.unshift(message.type ? message.content : message); 1065 const content = hyva.strf.apply(null, ruleOptions); 1066 messages.push(message.type ? {type: message.type, content} : content); 1067 } else { 1068 const content = hyva.strf(message.type ? message.content : message, ruleOptions) 1069 messages.push(message.type ? {type: message.type, content} : content); 1070 } 1071 } 1072 }); 1073 return messages; 1074 }, 1075 /** @deprecated */ 1076 getFieldWrapper(field) { 1077 return this.getMessageContainer(field) 1078 }, 1079 getMessageContainer(field) { 1080 let container; 1081 const pageSelector = field.element.getAttribute('data-validation-container') || options.pageMessagesContainerSelector; 1082 if (pageSelector) { 1083 container = document.querySelector(pageSelector) 1084 || containerNotFound(pageSelector, field.element) 1085 } else { 1086 const containerSelector = classNamesToSelector(options.fieldWrapperClassName); 1087 container = field.element.closest(containerSelector) 1088 || createMessageContainer(field.element, options.fieldWrapperClassName) 1089 || containerNotFound(containerSelector, field.element); 1090 } 1091 1092 return container; 1093 }, 1094 showFieldState(field) { 1095 const container = this.getMessageContainer(field), 1096 hasErrorMessages = hasMessagesWrapper.call(this, field, options.messagesWrapperClassName), 1097 messages = this.getMessagesByField(field).map(m => { 1098 return m.type !== 'html' ? escapeHtml(m.type ? m.content : m) : m.content; 1099 }); 1100 container.classList.toggle(options.validClassName, field.state.valid && ! hasErrorMessages); 1101 container.classList.toggle(options.invalidClassName, !field.state.valid || hasErrorMessages); 1102 this.createHtmlErrorMessage(field, messages); 1103 1104 if (field.state.valid) { 1105 field.element.removeAttribute('aria-invalid'); 1106 } else { 1107 field.element.setAttribute('aria-invalid', 'true'); 1108 if (! document.activeElement) { 1109 field.element.focus(); 1110 } 1111 } 1112 }, 1113 removeMessages(field, messagesClass) { 1114 if (! hasMessagesWrapper.call(this, field, messagesClass || options.messagesWrapperClassName)) { 1115 return; 1116 } 1117 1118 const msgWrapper = getMessagesWrapper.call(this, field, messagesClass || options.messagesWrapperClassName); 1119 const messages = msgWrapper.querySelectorAll(`[data-msg-field='${field.element.name}']`);
1120 Array.from(messages).forEach(msg => msg.remove()); 1121 if (msgWrapper && msgWrapper.childElementCount === 0) { 1122 field.element.removeAttribute('aria-errormessage'); 1123 field.element.removeAttribute('aria-describedby'); 1124 msgWrapper.remove(); 1125 } 1126 }, 1127 createErrorMessage(field, messages) { 1128 const htmlMessages = (Array.isArray(messages) ? messages : [messages]).map(escapeHtml) 1129 this.createHtmlErrorMessage(field, htmlMessages); 1130 }, 1131 createHtmlErrorMessage(field, messages) { 1132 this.removeMessages(field, options.messagesWrapperClassName); 1133 field.element.removeAttribute('aria-errormessage'); 1134 field.element.removeAttribute('aria-describedby'); 1135 1136 if (!field.state.valid) { 1137 const msgWrapper = this.addHtmlMessages(field, options.messagesWrapperClassName, messages); 1138 field.element.setAttribute('aria-errormessage', msgWrapper.id); 1139 field.element.setAttribute('aria-describedby', msgWrapper.id); 1140 } 1141 }, 1142 /** @deprecated */ 1143 createMessage(field, message) { 1144 return this.addMessages(field, options.messagesWrapperClassName, message); 1145 }, 1146 addMessages(field, messagesClass, messages) { 1147 const htmlMessages = (Array.isArray(messages) ? messages : [messages]).map(escapeHtml) 1148 return this.addHtmlMessages(field, messagesClass, htmlMessages); 1149 }, 1150 addHtmlMessages(field, messagesClass, htmlMessages) { 1151 const msgWrapper = getMessagesWrapper.call(this, field, messagesClass); 1152 1153 (Array.isArray(htmlMessages) ? htmlMessages : [htmlMessages]).forEach((htmlMessage) => { 1154 const li = document.createElement('li'); 1155 li.innerHTML = htmlMessage; 1156 li.setAttribute('data-msg-field', field.element.name); 1157 msgWrapper.appendChild(li); 1158 }); 1159 1160 return msgWrapper; 1161 }, 1162 setField(name, value) { 1163 this.fields[name].element.value = value; 1164 this.fields[name].element.dispatchEvent((new Event('input'))); 1165 this.validateField(this.fields[name]); 1166 } 1167 } 1168 } 1169 1170 function getFieldName(field) { 1171 const fieldName = field.element?.getAttribute('title') 1172 || document.querySelector(`label[for="${field.element?.id}"]`)?.innerText; 1173 1174 return fieldName 1175 ? fieldName.trim() 1176 : ''; 1177 } 1178 1179 hyva.formValidation = formValidation; 1180 hyva.formValidation.rules = formValidationRules; 1181 hyva.formValidation.setInputAttributeRuleName = (attrName, ruleName) => INPUT_ATTRIBUTE_RULES[attrName] = ruleName || attrName; 1182 hyva.formValidation.setInputTypeRuleName = (typeName, ruleName) => INPUT_TYPE_RULES[typeName] = ruleName || typeName; 1183 hyva.formValidation.addRule = (name, validator) => formValidationRules[name] = validator; 1184 hyva.formValidation.getFieldName = getFieldName; 1185 }(window.hyva = window.hyva || {})); 1186 1187 window.addEventListener('alpine:init', () => { 1188 Alpine.data('hyva.formValidation', hyva.formValidation); 1189 Alpine.data('hyva.formValidation($el)', hyva.formValidation); 1190 }, {once: true}); 1191 //# sourceURL=hyva-advanced-form-validation.js 1192</script>
1192 1193<div class="page-wrapper"><header class="page-header"><a class="action skip sr-only focus:not-sr-only focus:absolute focus:z-40 focus:bg-white 1194 contentarea" 1195 href="#contentarea"> 1196 <span> 1197 Skip to Content </span> 1198</a>
1199<script> 1200 function initHeader() { 1201 return { 1202 // estado 1203 searchOpen: false, 1204 cart: {}, 1205 isCartOpen: false, 1206 1207 // scroll behavior 1208 lastScrollY: 0, 1209 showHeader: true, // visible al cargar 1210 overlayOpen: false, // menú/buscador/minicart abiertos 1211 1212 // medidas/posiciones 1213 noticeHeight: 0, 1214 headerHeight: 0, 1215 topValue: '0px', // se bindea al style del header 1216 1217 init() { 1218 this.lastScrollY = window.scrollY || 0; 1219 1220 this.measureBars(); 1221 this.applyBodyPadding(); 1222 this.updateTop(); // coloca el header en su sitio según estado actual 1223 1224 this.setupOverlayWatchers(); 1225 this.setupScrollListener(); 1226 this.setupResizeListener(); 1227 this.observeDomChanges(); 1228 }, 1229 1230 isDesktop() { 1231 return window.matchMedia('(min-width: 1024px)').matches; 1232 }, 1233 1234 setupOverlayWatchers() { 1235 const update = () => { 1236 const html = document.documentElement; 1237 const body = document.body; 1238 const has = (cls) => html.classList.contains(cls) || body.classList.contains(cls); 1239 this.overlayOpen = this.isCartOpen || 1240 has('mobile-menu-open') || has('menu-open') || has('nav-open') || 1241 has('mobile-search-open') || has('drawer-open') || has('offcanvas-open'); 1242 1243 if (this.overlayOpen) { 1244 this.showHeader = true; // nunca ocultes con overlays abiertos 1245 this.updateTop(); 1246 } 1247 }; 1248 const opts = { 1249 attributes: true, 1250 attributeFilter: ['class'] 1251 }; 1252 new MutationObserver(update).observe(document.documentElement, opts); 1253 new MutationObserver(update).observe(document.body, opts); 1254 window.addEventListener('resize', update, { 1255 passive: true 1256 }); 1257 update(); 1258 }, 1259 1260 setupScrollListener() { 1261 const onScroll = () => { 1262 const current = window.scrollY || 0; 1263 1264 if (this.overlayOpen || this.isDesktop()) { 1265 // desktop: sin sticky; overlays: no ocultar 1266 this.showHeader = true; 1267 } else { 1268 // móvil: oculta al bajar (tras 100px), muestra al subir 1269 this.showHeader = !(current > this.lastScrollY && current > 100); 1270 } 1271 1272 this.lastScrollY = current; 1273 this.updateTop(); 1274 }; 1275 1276 // RAF throttling básico 1277 let ticking = false; 1278 const handle = () => { 1279 if (!ticking) { 1280 ticking = true; 1281 requestAnimationFrame(() => { 1282 onScroll(); 1283 ticking = false; 1284 }); 1285 } 1286 }; 1287 1288 onScroll(); // estado correcto al inicio 1289 window.addEventListener('scroll', handle, { 1290 passive: true 1291 }); 1292 }, 1293 1294 setupResizeListener() { 1295 window.addEventListener('resize', () => { 1296 this.measureBars(); 1297 this.applyBodyPadding(); 1298 this.updateTop(); 1299 }, { 1300 passive: true 1301 }); 1302 }, 1303 1304 // Calcula alturas de notice (si existe) y header 1305 measureBars() { 1306 const headerEl = document.getElementById('header'); 1307 const explicitNotice = document.querySelector('#site-notice'); 1308 const prevSibling = headerEl ? headerEl.previousElementSibling : null; 1309 const fallbackNotice = document.querySelector('#notification, .page-notice, .page.messages, .messages'); 1310 const bar = explicitNotice || prevSibling || fallbackNotice; 1311 1312 this.noticeHeight = (bar && getComputedStyle(bar).display !== 'none') ? (bar.offsetHeight || 0) : 0; 1313 this.headerHeight = headerEl ? (headerEl.offsetHeight || 0) : 0; 1314 1315 // variables CSS útiles (por si las usas en otros sitios) 1316 document.documentElement.style.setProperty('--page-header-height', `${this.headerHeight}px`); 1317 const total = this.headerHeight + (!this.isDesktop() ? this.noticeHeight : 0); 1318 document.documentElement.style.setProperty('--page-header-total', `${total}px`); 1319 }, 1320 1321 // En móvil empuja el body por debajo (header + notice). En desktop, sin padding extra (como tenÃas) 1322 applyBodyPadding() { 1323 if (!this.isDesktop()) { 1324 const total = this.headerHeight + this.noticeHeight; 1325 document.body.style.paddingTop = `${total}px`; 1326 } else { 1327 document.body.style.paddingTop = ''; 1328 } 1329 }, 1330
1331 // No usamos transform: solo movemos con top (no rompe position: fixed de los hijos) 1332 updateTop() { 1333 if (this.isDesktop()) { 1334 // desktop: header es relative, 'top' no aplica pero no estorba 1335 this.topValue = '0px'; 1336 return; 1337 } 1338 this.topValue = this.showHeader ? `${this.noticeHeight}px` : `-${this.headerHeight}px`; 1339 }, 1340 1341 // Observa posibles cambios en el DOM que alteren alturas (ej: aparece un mensaje) 1342 observeDomChanges() { 1343 if (!window.MutationObserver) return; 1344 const obs = new MutationObserver(() => { 1345 this.$nextTick(() => { 1346 this.measureBars(); 1347 this.applyBodyPadding(); 1348 this.updateTop(); 1349 }); 1350 }); 1351 obs.observe(document.body, { 1352 childList: true, 1353 subtree: true 1354 }); 1355 }, 1356 1357 // --- Igual que tu header antiguo --- 1358 summaryCount() { 1359 return this.cart.summary_count || 0; 1360 }, 1361 getData() { 1362 const data = this.$event.detail.data; 1363 if (data.cart) this.cart = data.cart; 1364 }, 1365 ariaLabel() { 1366 return 'Toggle\u0020minicart, ' + 1367 (this.isCartEmpty() ? 'El\u0020carrito\u0020est\u00E1\u0020vac\u00EDo' : ( 1368 Math.abs(this.summaryCount()) > 1 ? 1369 hyva.str('\u00251\u0020items', this.summaryCount()) : 1370 hyva.str('\u00251\u0020art\u00EDculo', this.summaryCount()) 1371 )); 1372 }, 1373 isCartEmpty() { 1374 return !this.summaryCount(); 1375 }, 1376 openCart() { 1377 this.$dispatch('toggle-cart', { 1378 isOpen: true 1379 }); 1380 }, 1381 toggleCart() { 1382 const event = this.$event; 1383 if (event.detail && event.detail.isOpen !== undefined) { 1384 this.isCartOpen = event.detail.isOpen; 1385 if (!this.isCartOpen && this.$refs && this.$refs.cartButton) this.$refs.cartButton.focus(); 1386 } else { 1387 this.isCartOpen = true; 1388 } 1389 }, 1390 1391 // -------- BUSCADOR (TOGGLE) -------- 1392 toggleSearch() { 1393 const html = document.documentElement; 1394 const body = document.body; 1395 const site = document.getElementById('site-search'); 1396 if (!site) return; 1397 1398 const isHidden = getComputedStyle(site).display === 'none'; 1399 1400 if (isHidden) { 1401 html.classList.add('mobile-search-open'); 1402 body.classList.add('mobile-search-open'); 1403 html.classList.remove('mobile-search-closed'); 1404 body.classList.remove('mobile-search-closed'); 1405 1406 this.$nextTick(() => { 1407 try { 1408 site.scrollIntoView({ 1409 behavior: 'smooth', 1410 block: 'start' 1411 }); 1412 } catch (e) {} 1413 }); 1414 } else { 1415 html.classList.remove('mobile-search-open'); 1416 body.classList.remove('mobile-search-open'); 1417 html.classList.add('mobile-search-closed'); 1418 body.classList.add('mobile-search-closed'); 1419 1420 const i = site.querySelector('input[type=search]'); 1421 if (i) i.blur(); 1422 } 1423 }, 1424 // ----------------------------------- 1425 1426 searchClosed() { 1427 return !this.searchOpen; 1428 }, 1429 toggleSearchForm() { 1430 this.searchOpen = !this.searchOpen; 1431 this.$dispatch('search-open'); 1432 }, 1433 searchClose() { 1434 this.searchOpen = false; 1435 }, 1436 searchEscape() { 1437 this.searchOpen = false; 1438 this.$refs.searchButton && this.$refs.searchButton.focus(); 1439 }, 1440 } 1441 } 1442 1443 function initCompareHeader() { 1444 return { 1445 compareProducts: null, 1446 itemCount: 0, 1447 hiddenIfEmpty() { 1448 return { 1449 'hidden': this.itemCount < 1 1450 } 1451 }, 1452 linkAriaLabel() { 1453 const countLabel = this.itemCount > 1 ? 1454 hyva.str('\u00251\u0020productos', this.itemCount) : 1455 hyva.str('\u00251\u0020producto', this.itemCount); 1456 return `Comparar\u0020Productos (${countLabel})`; 1457 }, 1458 receiveCompareData() { 1459 const data = this.$event.detail.data; 1460 if (data['compare-products'] && data['compare-products'].count) { 1461 this.compareProducts = data['compare-products']; 1462 this.itemCount = this.compareProducts.count; 1463 } 1464 }, 1465 itemCountLabel() { 1466 return `(${this.itemCount})`; 1467 } 1468 } 1469 } 1470 1471 function initWishlistHeader() { 1472 return { 1473 wishlistProducts: null, 1474 itemCount: 0, 1475 linkAriaLabel() { 1476 const countLabel = this.itemCount > 1 ?
1477 hyva.str('\u00251\u0020productos', this.itemCount) : 1478 hyva.str('\u00251\u0020producto', this.itemCount); 1479 return `Wishlist\u0020Products (${countLabel})`; 1480 }, 1481 receiveWishlistData() { 1482 const data = this.$event.detail.data; 1483 this.itemCount = data.wishlist && data.wishlist.items ? data.wishlist.items.length : 0; 1484 } 1485 } 1486 } 1487 1488 window.addEventListener('alpine:init', () => { 1489 Alpine.data('initHeader', initHeader); 1490 Alpine.data('initCompareHeader', initCompareHeader); 1491 Alpine.data('initWishlistHeader', initWishlistHeader); 1492 }, { 1493 once: true 1494 }); 1495 1496 // Cerrar con ESC (global) 1497 window.addEventListener('keydown', (e) => { 1498 if (e.key === 'Escape') { 1499 document.documentElement.classList.remove('mobile-search-open'); 1500 document.body.classList.remove('mobile-search-open'); 1501 document.documentElement.classList.add('mobile-search-closed'); 1502 document.body.classList.add('mobile-search-closed'); 1503 } 1504 }); 1505</script>
1505 1506 1507<div 1508 id="header" 1509 x-data="initHeader" 1510 class="z-30 bg-white fixed left-0 right-0 lg:relative transition-all duration-300 ease-in-out" 1511 @private-content-loaded.window="getData" 1512 @resize.window="measureBars" 1513 :style="{ top: topValue }"> 1514 1515 <div class="container pt-3.5 mt-4 lg:pb-3.5 grid grid-cols-[auto_minmax(0px,1fr)_auto] 1516 lg:grid-cols-[auto_minmax(0px,1fr)_auto] gap-y-3.5 lg:gap-y-0 gap-x-4 lg:gap-x-10 items-center"> 1517 <nav 1518 x-data="initMenuMobile" 1519 @load.window="setActiveMenu" 1520 @keydown.window.escape="closeMenu" 1521 class="navigation lg:hidden" 1522 aria-label="Navegación" 1523 role="navigation"> 1524 <button 1525 x-ref="mobileMenuTrigger" 1526 @click="openMenu" 1527 type="button" 1528 class="p-2 rounded-md ring-1 ring-black/5 shadow-sm bg-white hover:bg-slate-50 active:scale-95 transition" 1529 aria-label="Abrir menú" 1530 aria-haspopup="menu" 1531 :aria-expanded="open" 1532 :hidden="open"> 1533 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-7 h-7" width="28" height="28" aria-hidden="true"> 1534 <path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16"/> 1535</svg> 1536 </button> 1537 1538 <div 1539 x-ref="mobileMenuNavLinks" 1540 class="fixed inset-x-0 z-40 hidden" 1541 style="top: var(--page-header-height); height: calc(100% - var(--page-header-height));" 1542 :class="{ 'block': open, 'hidden': !open }" 1543 :aria-hidden="closed" 1544 role="dialog" 1545 aria-modal="true"> 1546 1547 <div 1548 class="absolute inset-0 bg-black/55 backdrop-blur-md" 1549 @click="closeMenu" 1550 x-show="open" 1551 x-transition:enter="transition ease-out duration-250" 1552 x-transition:enter-start="opacity-0" 1553 x-transition:enter-end="opacity-100" 1554 x-transition:leave="transition ease-in duration-200" 1555 x-transition:leave-start="opacity-100" 1556 x-transition:leave-end="opacity-0"></div> 1557 1558 <div 1559 class="drawer-panel absolute inset-y-0 left-0 w-full max-w-[92vw] bg-white dark:bg-slate-900 border-r border-slate-200/60 dark:border-slate-700/60 shadow-2xl rounded-r-2xl overflow-hidden flex flex-col" 1560 x-show="open" 1561 x-transition:enter="transition-transform ease-out duration-350" 1562 x-transition:enter-start="-translate-x-full" 1563 x-transition:enter-end="translate-x-0" 1564 x-transition:leave="transition-transform ease-in duration-250" 1565 x-transition:leave-start="translate-x-0" 1566 x-transition:leave-end="-translate-x-full"> 1567 1568 <div class="relative flex items-center justify-between px-4 py-3 border-b border-slate-200/70 bg-white/85 backdrop-blur"> 1569 <span class="text-base font-semibold tracking-tight text-slate-900">Menú</span> 1570 <button 1571 @click="closeMenu" 1572 class="p-2 rounded-md hover:bg-slate-100 transition focus:outline-none focus-visible:ring-2 focus-visible:ring-[#1a798e]" 1573 aria-label="Cerrar menú" 1574 type="button"> 1575 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6 h-6" width="24" height="24" aria-hidden="true"> 1576 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1577</svg> 1578 </button> 1579 </div> 1580 1581 <div class="flex-1 overflow-y-auto"> 1582 <ul class="py-2" aria-label="Enlaces de navegación"> 1583 <li data-child-id="category-node-37-main" class="level-0"> 1584 <button 1585 type="button" 1586 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1587 @click="toggleSubcategory('category-node-37')" 1588 :aria-expanded="isOpen('category-node-37')" 1589 aria-controls="panel-category-node-37">
1590 <span class="text-[15px] font-medium text-slate-900"> 1591 Salones Modernos </span> 1592 1593 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-37') ? 'rotate-180' : ''"> 1594 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1595</svg> 1596 </button> 1597 1598 <div 1599 id="panel-category-node-37" 1600 x-ref="panel-category-node-37" 1601 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1602 style="max-height:0; opacity:0; display:none;"> 1603 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1604 <ul class="py-2" aria-label="Subcategorías"> 1605 <li> 1606 <a 1607 href="https://www.mueblesbonitos.com/salon" 1608 title="Salones Modernos" 1609 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 1610 <span class="ml-1">Ver todos/as</span> 1611 </a> 1612 </li> 1613 1614 <li> 1615 <a 1616 href="https://www.mueblesbonitos.com/salon/mueble-tv" 1617 title="Mueble TV" 1618 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1619 <span class="ml-1">Mueble TV</span> 1620 </a> 1621 </li> 1622 <li> 1623 <a 1624 href="https://www.mueblesbonitos.com/salon/aparadores" 1625 title="Aparador" 1626 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1627 <span class="ml-1">Aparador</span> 1628 </a> 1629 </li> 1630 <li> 1631 <a 1632 href="https://www.mueblesbonitos.com/salon/mesas-de-centro" 1633 title="Mesas de Centro" 1634 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1635 <span class="ml-1">Mesas de Centro</span> 1636 </a> 1637 </li> 1638 <li> 1639 <a 1640 href="https://www.mueblesbonitos.com/salon/mesas-y-sillas-de-comedor" 1641 title="Mesas de Comedor" 1642 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition">
1643 <span class="ml-1">Mesas de Comedor</span> 1644 </a> 1645 </li> 1646 <li> 1647 <a 1648 href="https://www.mueblesbonitos.com/salon/estanterias" 1649 title="Estanterías de Diseño" 1650 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1651 <span class="ml-1">EstanterÃas de Diseño</span> 1652 </a> 1653 </li> 1654 <li> 1655 <a 1656 href="https://www.mueblesbonitos.com/salon/vitrinas" 1657 title="Vitrinas" 1658 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1659 <span class="ml-1">Vitrinas</span> 1660 </a> 1661 </li> 1662 <li> 1663 <a 1664 href="https://www.mueblesbonitos.com/salon/armario" 1665 title="Armarios de Salón" 1666 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1667 <span class="ml-1">Armarios de Salón</span> 1668 </a> 1669 </li> 1670 <li> 1671 <a 1672 href="https://www.mueblesbonitos.com/salon/conjuntos-de-salon" 1673 title="Conjuntos de Salón" 1674 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1675 <span class="ml-1">Conjuntos de Salón</span> 1676 </a> 1677 </li> 1678 <li> 1679 <a 1680 href="https://www.mueblesbonitos.com/salon/muebles-con-chimenea" 1681 title="Muebles con Chimenea" 1682 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1683 <span class="ml-1">Muebles con Chimenea</span> 1684 </a> 1685 </li> 1686 </ul> 1687 </div> 1688 </div> 1689 </li> 1690 <li data-child-id="category-node-110-main" class="level-0"> 1691 <button 1692 type="button" 1693 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1694 @click="toggleSubcategory('category-node-110')" 1695 :aria-expanded="isOpen('category-node-110')" 1696 aria-controls="panel-category-node-110">
1697 <span class="text-[15px] font-medium text-slate-900"> 1698 Recibidores </span> 1699 1700 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-110') ? 'rotate-180' : ''"> 1701 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1702</svg> 1703 </button> 1704 1705 <div 1706 id="panel-category-node-110" 1707 x-ref="panel-category-node-110" 1708 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1709 style="max-height:0; opacity:0; display:none;"> 1710 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1711 <ul class="py-2" aria-label="Subcategorías"> 1712 <li> 1713 <a 1714 href="https://www.mueblesbonitos.com/recibidores" 1715 title="Recibidores" 1716 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 1717 <span class="ml-1">Ver todos/as</span> 1718 </a> 1719 </li> 1720 1721 <li> 1722 <a 1723 href="https://www.mueblesbonitos.com/recibidores/consolas-y-zapateros" 1724 title="Consola Recibidor" 1725 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1726 <span class="ml-1">Consola Recibidor</span> 1727 </a> 1728 </li> 1729 <li> 1730 <a 1731 href="https://www.mueblesbonitos.com/recibidores/conjuntos-con-espejo" 1732 title="Recibidor con Espejo" 1733 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1734 <span class="ml-1">Recibidor con Espejo</span> 1735 </a> 1736 </li> 1737 </ul> 1738 </div> 1739 </div> 1740 </li> 1741 <li data-child-id="category-node-3-main" class="level-0"> 1742 <button 1743 type="button" 1744 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1745 @click="toggleSubcategory('category-node-3')" 1746 :aria-expanded="isOpen('category-node-3')" 1747 aria-controls="panel-category-node-3">
1748 <span class="text-[15px] font-medium text-slate-900"> 1749 Dormitorios </span> 1750 1751 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-3') ? 'rotate-180' : ''"> 1752 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1753</svg> 1754 </button> 1755 1756 <div 1757 id="panel-category-node-3" 1758 x-ref="panel-category-node-3" 1759 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1760 style="max-height:0; opacity:0; display:none;"> 1761 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1762 <ul class="py-2" aria-label="Subcategorías"> 1763 <li> 1764 <a 1765 href="https://www.mueblesbonitos.com/dormitorio" 1766 title="Dormitorios" 1767 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 1768 <span class="ml-1">Ver todos/as</span> 1769 </a> 1770 </li> 1771 1772 <li> 1773 <a 1774 href="https://www.mueblesbonitos.com/dormitorio/camas-de-matrimonio" 1775 title="Camas de Matrimonio" 1776 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1777 <span class="ml-1">Camas de Matrimonio</span> 1778 </a> 1779 </li> 1780 <li> 1781 <a 1782 href="https://www.mueblesbonitos.com/dormitorio/mesitas-de-noche" 1783 title="Mesitas de Noche" 1784 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1785 <span class="ml-1">Mesitas de Noche</span> 1786 </a> 1787 </li> 1788 <li> 1789 <a 1790 href="https://www.mueblesbonitos.com/dormitorio/armarios" 1791 title="Armarios Roperos" 1792 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1793 <span class="ml-1">Armarios Roperos</span> 1794 </a> 1795 </li> 1796 <li> 1797 <a 1798 href="https://www.mueblesbonitos.com/dormitorio/comodas-y-cajoneras" 1799 title="Cómodas" 1800 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition">
1801 <span class="ml-1">Cómodas</span> 1802 </a> 1803 </li> 1804 <li> 1805 <a 1806 href="https://www.mueblesbonitos.com/dormitorio/tocadores" 1807 title="Tocador" 1808 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1809 <span class="ml-1">Tocador</span> 1810 </a> 1811 </li> 1812 </ul> 1813 </div> 1814 </div> 1815 </li> 1816 <li data-child-id="category-node-841-main" class="level-0"> 1817 <button 1818 type="button" 1819 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1820 @click="toggleSubcategory('category-node-841')" 1821 :aria-expanded="isOpen('category-node-841')" 1822 aria-controls="panel-category-node-841"> 1823 <span class="text-[15px] font-medium text-slate-900"> 1824 Muebles de Cocina </span> 1825 1826 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-841') ? 'rotate-180' : ''"> 1827 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1828</svg> 1829 </button> 1830 1831 <div 1832 id="panel-category-node-841" 1833 x-ref="panel-category-node-841" 1834 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1835 style="max-height:0; opacity:0; display:none;"> 1836 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1837 <ul class="py-2" aria-label="Subcategorías"> 1838 <li> 1839 <a 1840 href="https://www.mueblesbonitos.com/cocina" 1841 title="Muebles de Cocina" 1842 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 1843 <span class="ml-1">Ver todos/as</span> 1844 </a> 1845 </li> 1846 1847 <li> 1848 <a 1849 href="https://www.mueblesbonitos.com/cocina/mesas-altas" 1850 title="Mesas Altas de Cocina" 1851 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition">
1852 <span class="ml-1">Mesas Altas de Cocina</span> 1853 </a> 1854 </li> 1855 <li> 1856 <a 1857 href="https://www.mueblesbonitos.com/cocina/taburetes" 1858 title="Taburetes de Cocina" 1859 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1860 <span class="ml-1">Taburetes de Cocina</span> 1861 </a> 1862 </li> 1863 <li> 1864 <a 1865 href="https://www.mueblesbonitos.com/cocina/armarios-de-cocina" 1866 title="Armarios de Cocina" 1867 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1868 <span class="ml-1">Armarios de Cocina</span> 1869 </a> 1870 </li> 1871 </ul> 1872 </div> 1873 </div> 1874 </li> 1875 <li data-child-id="category-node-843-main" class="level-0"> 1876 <button 1877 type="button" 1878 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1879 @click="toggleSubcategory('category-node-843')" 1880 :aria-expanded="isOpen('category-node-843')" 1881 aria-controls="panel-category-node-843"> 1882 <span class="text-[15px] font-medium text-slate-900"> 1883 Muebles de Baño </span> 1884 1885 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-843') ? 'rotate-180' : ''"> 1886 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1887</svg> 1888 </button> 1889 1890 <div 1891 id="panel-category-node-843" 1892 x-ref="panel-category-node-843" 1893 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1894 style="max-height:0; opacity:0; display:none;"> 1895 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1896 <ul class="py-2" aria-label="Subcategorías"> 1897 <li> 1898 <a 1899 href="https://www.mueblesbonitos.com/bano" 1900 title="Muebles de Baño" 1901 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition">
1902 <span class="ml-1">Ver todos/as</span> 1903 </a> 1904 </li> 1905 1906 <li> 1907 <a 1908 href="https://www.mueblesbonitos.com/bano/conjuntos-de-bano" 1909 title="Conjuntos de baño" 1910 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1911 <span class="ml-1">Conjuntos de baño</span> 1912 </a> 1913 </li> 1914 <li> 1915 <a 1916 href="https://www.mueblesbonitos.com/bano/columnas-y-armarios-de-bano" 1917 title="Columna de Baño" 1918 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1919 <span class="ml-1">Columna de Baño</span> 1920 </a> 1921 </li> 1922 </ul> 1923 </div> 1924 </div> 1925 </li> 1926 <li data-child-id="category-node-76-main" class="level-0"> 1927 <button 1928 type="button" 1929 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 1930 @click="toggleSubcategory('category-node-76')" 1931 :aria-expanded="isOpen('category-node-76')" 1932 aria-controls="panel-category-node-76"> 1933 <span class="text-[15px] font-medium text-slate-900"> 1934 Muebles Auxiliares </span> 1935 1936 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-76') ? 'rotate-180' : ''"> 1937 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 1938</svg> 1939 </button> 1940 1941 <div 1942 id="panel-category-node-76" 1943 x-ref="panel-category-node-76" 1944 class="overflow-hidden will-change-[max-height,opacity] mx-3" 1945 style="max-height:0; opacity:0; display:none;"> 1946 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 1947 <ul class="py-2" aria-label="Subcategorías"> 1948 <li> 1949 <a 1950 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares" 1951 title="Muebles Auxiliares" 1952 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition">
1953 <span class="ml-1">Ver todos/as</span> 1954 </a> 1955 </li> 1956 1957 <li> 1958 <a 1959 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/zapateros" 1960 title="Zapateros" 1961 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1962 <span class="ml-1">Zapateros</span> 1963 </a> 1964 </li> 1965 <li> 1966 <a 1967 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/escritorios" 1968 title="Escritorios Modernos" 1969 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1970 <span class="ml-1">Escritorios Modernos</span> 1971 </a> 1972 </li> 1973 <li> 1974 <a 1975 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/baules" 1976 title="Baúles" 1977 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1978 <span class="ml-1">Baúles</span> 1979 </a> 1980 </li> 1981 <li> 1982 <a 1983 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/armarios-multiusos" 1984 title="Armario Multiusos" 1985 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1986 <span class="ml-1">Armario Multiusos</span> 1987 </a> 1988 </li> 1989 <li> 1990 <a 1991 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/plantas-artificiales" 1992 title="Plantas artificiales" 1993 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 1994 <span class="ml-1">Plantas artificiales</span> 1995 </a> 1996 </li> 1997 <li> 1998 <a 1999 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/mesa-altavoz" 2000 title="Mesa altavoz" 2001 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition">
2002 <span class="ml-1">Mesa altavoz</span> 2003 </a> 2004 </li> 2005 <li> 2006 <a 2007 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/mini-huertas" 2008 title="Mini Huerto en Casa" 2009 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 2010 <span class="ml-1">Mini Huerto en Casa</span> 2011 </a> 2012 </li> 2013 </ul> 2014 </div> 2015 </div> 2016 </li> 2017 <li data-child-id="category-node-525-main" class="level-0"> 2018 <button 2019 type="button" 2020 class="w-full text-left flex items-center justify-between px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70" 2021 @click="toggleSubcategory('category-node-525')" 2022 :aria-expanded="isOpen('category-node-525')" 2023 aria-controls="panel-category-node-525"> 2024 <span class="text-[15px] font-medium text-slate-900"> 2025 Ofertas </span> 2026 2027 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-slate-400 transition-transform duration-300" width="20" height="20" aria-hidden="true" :class="isOpen('category-node-525') ? 'rotate-180' : ''"> 2028 <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/> 2029</svg> 2030 </button> 2031 2032 <div 2033 id="panel-category-node-525" 2034 x-ref="panel-category-node-525" 2035 class="overflow-hidden will-change-[max-height,opacity] mx-3" 2036 style="max-height:0; opacity:0; display:none;"> 2037 <div class="my-2 rounded-2xl ring-1 ring-slate-200/80 bg-slate-50/70 shadow-sm overflow-hidden"> 2038 <ul class="py-2" aria-label="Subcategorías"> 2039 <li> 2040 <a 2041 href="https://www.mueblesbonitos.com/ofertas" 2042 title="Ofertas" 2043 class="flex items-center w-full px-4 py-3 text-[#1a798e] font-medium hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 2044 <span class="ml-1">Ver todos/as</span> 2045 </a> 2046 </li> 2047 2048 <li> 2049 <a 2050 href="https://www.mueblesbonitos.com/ofertas/ultimas-unidades" 2051 title="Últimas unidades" 2052 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition">
2053 <span class="ml-1">Ãltimas unidades</span> 2054 </a> 2055 </li> 2056 <li> 2057 <a 2058 href="https://www.mueblesbonitos.com/ofertas/muebles-de-segunda-vida" 2059 title="Muebles de Segunda Vida" 2060 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 2061 <span class="ml-1">Muebles de Segunda Vida</span> 2062 </a> 2063 </li> 2064 <li> 2065 <a 2066 href="https://www.mueblesbonitos.com/ofertas/outlet" 2067 title="Outlet " 2068 class="flex items-center w-full px-4 py-3 text-slate-800 hover:bg-slate-100/80 transition"> 2069 <span class="ml-1">Outlet </span> 2070 </a> 2071 </li> 2072 </ul> 2073 </div> 2074 </div> 2075 </li> 2076 <li data-child-id="category-node-518-main" class="level-0"> 2077 <a 2078 class="flex items-center w-full px-5 py-4 bg-white hover:bg-slate-50 transition border-b border-slate-100/70 level-0 text-[15px] font-medium text-slate-900" 2079 href="https://www.mueblesbonitos.com/novedades" 2080 title="Novedades"> 2081 Novedades </a> 2082 2083 </li> 2084 </ul> 2085 2086 <div class="px-4 pb-6"> 2087 <div class="mobile-help-card rounded-2xl overflow-hidden ring-1 ring-[#8cc4b2] ring-opacity-60 bg-[#8cc4b2] bg-opacity-20"> 2088 <div class="px-3 py-2 text-[13px] uppercase tracking-wide font-semibold text-[#1a798e]"> 2089 Ayuda & Información </div> 2090 <ul class="divide-y divide-[#8cc4b2] divide-opacity-40"> 2091 <li> 2092 <a 2093 href="https://www.mueblesbonitos.com/quienes-somos/" 2094 class="flex items-center justify-between py-3 px-3 text-[15px] font-medium text-[#1a798e] hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 2095 <span>Quiénes somos/Contactar</span> 2096 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4" width="16" height="16" aria-hidden="true"> 2097 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 2098</svg> 2099 </a> 2100 </li> 2101 <li> 2102 <a 2103 href="https://www.mueblesbonitos.com/customers/" 2104 rel="nofollow" 2105 class="flex items-center justify-between py-3 px-3 text-[15px] font-medium text-[#1a798e] hover:bg-[#8cc4b2] hover:bg-opacity-20 transition">
2106 <span>Comunicar una incidencia</span> 2107 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4" width="16" height="16" aria-hidden="true"> 2108 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 2109</svg> 2110 </a> 2111 </li> 2112 <li> 2113 <a 2114 href="https://www.mueblesbonitos.com/mapa-del-sitio/" 2115 class="flex items-center justify-between py-3 px-3 text-[15px] font-medium text-[#1a798e] hover:bg-[#8cc4b2] hover:bg-opacity-20 transition"> 2116 <span>Mapa del sitio</span> 2117 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4" width="16" height="16" aria-hidden="true"> 2118 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 2119</svg> 2120 </a> 2121 </li> 2122 </ul> 2123 </div> 2124 </div> 2125 </div> 2126 </div> 2127 </div> 2128</nav> 2129
2130<script> 2131 const initMenuMobile = () => { 2132 return { 2133 mobilePanelActiveId: null, 2134 open: false, 2135 2136 closed() { return !this.open }, 2137 isOpen(id) { return this.mobilePanelActiveId === id }, 2138 2139 setActiveMenu() { 2140 const menuNode = this.$root; 2141 Array.from(menuNode.querySelectorAll('a')) 2142 .filter(link => link.href === window.location.href.split('?')[0]) 2143 .forEach(item => { 2144 item.classList.add('underline'); 2145 const parent = item.closest('li.level-0'); 2146 if (parent) { 2147 const topBtn = parent.querySelector('button'); 2148 if (topBtn) { topBtn.classList.add('underline'); } 2149 } 2150 }); 2151 }, 2152 2153 openMenu() { 2154 this.open = true; 2155 this.$nextTick(() => hyva.trapFocus(this.$refs['mobileMenuNavLinks'])); 2156 document.body.style.overflow = 'hidden'; 2157 document.documentElement.classList.add('mobile-menu-open'); 2158 }, 2159 2160 closeMenu() { 2161 document.body.style.overflow = ''; 2162 if (this.open) { 2163 this.$nextTick(() => this.$refs['mobileMenuTrigger'].focus() || hyva.releaseFocus()); 2164 } 2165 if (this.mobilePanelActiveId) { this.collapse(this.mobilePanelActiveId); } 2166 this.open = false; 2167 this.mobilePanelActiveId = null; 2168 document.documentElement.classList.remove('mobile-menu-open'); 2169 }, 2170 2171 toggleSubcategory(id) { 2172 if (this.mobilePanelActiveId === id) { 2173 this.collapse(id); 2174 this.mobilePanelActiveId = null; 2175 } else { 2176 if (this.mobilePanelActiveId) this.collapse(this.mobilePanelActiveId); 2177 this.mobilePanelActiveId = id; 2178 this.$nextTick(() => this.expand(id)); 2179 } 2180 }, 2181 2182 expand(id) { 2183 const el = this.$refs['panel-' + id]; 2184 if (!el) return; 2185 el.style.display = 'block'; 2186 el.style.transition = 'none'; 2187 el.style.maxHeight = '0px'; 2188 el.style.opacity = '0'; 2189 requestAnimationFrame(() => { 2190 const h = el.scrollHeight; 2191 el.style.transition = 'max-height 700ms cubic-bezier(.2,.7,0,.995), opacity 500ms ease-out'; 2192 el.style.maxHeight = h + 'px'; 2193 el.style.opacity = '1'; 2194 setTimeout(() => { 2195 el.style.transition = 'opacity 300ms ease-out'; 2196 el.style.maxHeight = '9999px'; 2197 }, 720); 2198 }); 2199 }, 2200 2201 collapse(id) { 2202 const el = this.$refs['panel-' + id]; 2203 if (!el) return; 2204 const h = el.scrollHeight; 2205 el.style.transition = 'none'; 2206 el.style.maxHeight = h + 'px'; 2207 el.style.opacity = '1'; 2208 requestAnimationFrame(() => { 2209 el.style.transition = 'max-height 650ms cubic-bezier(.4,0,.2,1), opacity 400ms ease-in'; 2210 el.style.maxHeight = '0px'; 2211 el.style.opacity = '0'; 2212 setTimeout(() => { 2213 el.style.display = 'none'; 2214 el.style.transition = ''; 2215 el.style.maxHeight = '0px'; 2216 el.style.opacity = ''; 2217 }, 660); 2218 }); 2219 }, 2220 } 2221 } 2222 2223 window.addEventListener('alpine:init', () => Alpine.data('initMenuMobile', initMenuMobile), { 2224 once: true 2225 }) 2226</script>
2226 2227 2228<a 2229 class="inline-block align-middle" 2230 href="https://www.mueblesbonitos.com/" 2231 title="Ir a la página de inicio"> 2232 <picture class="block h-auto w-[180px] sm:w-[286px] lg:w-[189px] max-w-full shrink-0"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/logo/stores/2/Mediano-MueblesBonitos.webp"><img class="block h-auto w-[180px] sm:w-[286px] lg:w-[189px] max-w-full shrink-0" src="https://www.mueblesbonitos.com/media/logo/stores/2/Mediano-MueblesBonitos.png" alt="Muebles Bonitos" width="189" height="64" loading="eager" fetchpriority="high" /></picture> 2233 2234 </a> 2235 <div class="ml-auto flex gap-0.5 items-center lg:order-2 shrink-0"> 2236 2237 <button 2238 id="menu-search-icon" 2239 class="inline-block rounded p-1 hover:bg-primary/10 outline-offset-2 md:hidden" 2240 type="button" 2241 aria-label="Buscar" 2242 @click.prevent="toggleSearch()" 2243 x-ref="searchButton"> 2244 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2245 <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/> 2246</svg> 2247 </button> 2248 2249 2250<a 2251 id="compare-link" 2252 class="relative hidden md:inline-block rounded p-1 hover:bg-primary/10 outline-offset-2 invisible" 2253 :class="hiddenIfEmpty" 2254 href="https://www.mueblesbonitos.com/catalog/product_compare/index/" 2255 rel="nofollow" 2256 title="Comparar Productos" 2257 x-data="initCompareHeader" 2258 @private-content-loaded.window="receiveCompareData" 2259 :aria-label="linkAriaLabel" 2260> 2261 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2262 <path stroke-linecap="round" stroke-linejoin="round" d="M3 6l3 1m0 0l-3 9a5.002 5.002 0 006.001 0M6 7l3 9M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9m-3-9l-6-2m0-2v2m0 16V5m0 16H9m3 0h3"/> 2263</svg> 2264 <span 2265 x-text="itemCount" 2266 class="absolute -top-1.5 -right-1.5 px-2 py-0.5 rounded-full bg-blue-200 text-blue-800 2267 text-xs font-semibold leading-none text-center uppercase tabular-nums" 2268 aria-hidden="true" 2269 ></span> 2270</a> 2271 2272 2273 2274 <!-- BLOCK header.customer --> 2275<div 2276 class="relative inline-block" 2277 x-data="initCustomerMenu" 2278 @keyup.escape="setOpenFalse" 2279 @click.outside="setOpenFalse" 2280> 2281 <button 2282 type="button" 2283 id="customer-menu" 2284 class="block rounded p-1 hover:bg-primary/10 outline-offset-2" 2285 @click="toggleOpen" 2286 :aria-expanded="ariaExpanded" 2287 aria-label="Mi cuenta" 2288 aria-haspopup="true" 2289 > 2290 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2291 <path stroke-linecap="round" stroke-linejoin="round" d="M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> 2292</svg> 2293 </button> 2294 <nav 2295 class="z-30 absolute -right-4 w-48 sm:w-56 mt-2 py-2 px-1 overflow-auto 2296 rounded shadow-lg lg:mt-3 bg-container-lighter" 2297 x-cloak 2298 x-show="open" 2299 x-transition 2300 aria-labelledby="customer-menu" 2301 > 2302 2303<a 2304 id="custom.catalog.compare.link.out" 2305 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100 relative" 2306 href="https://www.mueblesbonitos.com/catalog/product_compare/index/" 2307 rel="nofollow" 2308 title="Comparar Productos" 2309 x-data="initCompareHeader" 2310 @private-content-loaded.window="receiveCompareData" 2311> 2312 Comparar Productos <template x-if="itemCount"> 2313 <span class="tabular-nums" x-text="itemCountLabel"></span> 2314 </template> 2315</a> 2316
2317<script> 2318 document.addEventListener('DOMContentLoaded', () => { 2319 document.getElementById('customer.header.sign.in.link').addEventListener('click', () => { 2320 if (hyva.setCookie) { 2321 hyva.setCookie( 2322 'login_redirect', 2323 window.location.href, 2324 1 2325 ); 2326 } 2327 }); 2328 }); 2329</script>
2329 2330<a id="customer.header.sign.in.link" 2331 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100" 2332 href="https://www.mueblesbonitos.com/customer/account/index/" 2333 title="Iniciar Sesión" 2334> 2335 Iniciar Sesión</a> 2336 2337 <a id="customer.header.register.link" 2338 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100" 2339 href="https://www.mueblesbonitos.com/customer/account/create/" 2340 title="Crear una Cuenta" 2341 > 2342 Crear una Cuenta </a> 2343 </nav> 2344</div>
2345<script> 2346 function initCustomerMenu() { 2347 return hyva.createBooleanObject('open', false, { 2348 ariaExpanded() { 2349 return this.open() ? 'true' : 'false'; 2350 } 2351 }) 2352 } 2353 window.addEventListener('alpine:init', () => Alpine.data('initCustomerMenu', initCustomerMenu), {once: true}) 2354</script>
2354 2355<!-- /BLOCK header.customer --> 2356 2357<a 2358 href="https://www.mueblesbonitos.com/wishlist/" 2359 rel="nofollow" 2360 class="relative hidden md:inline-block rounded p-1 hover:bg-primary/10 outline-offset-2" 2361 x-data="initWishlistHeader" 2362 @private-content-loaded.window="receiveWishlistData" 2363 aria-label="Mis favoritos" 2364 :aria-label="linkAriaLabel" 2365> 2366 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2367 <path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/> 2368</svg> 2369 <template x-if="itemCount"> 2370 <span 2371 x-text="itemCount" 2372 class="absolute -top-1.5 -right-1.5 px-2 py-0.5 rounded-full bg-green-200 text-green-800 text-xs 2373 font-semibold leading-none text-center uppercase tabular-nums" 2374 aria-hidden="true" 2375 ></span> 2376 </template> 2377</a> 2378 2379 <button 2380 id="menu-cart-icon" 2381 class="relative inline-block rounded p-1 hover:bg-primary/10 outline-offset-2" 2382 x-ref="cartButton" 2383 :aria-disabled="isCartEmpty" 2384 :aria-label="ariaLabel" 2385 @click.prevent="openCart" 2386 @toggle-cart.window="toggleCart" 2387 :aria-expanded="isCartOpen" 2388 aria-haspopup="dialog" 2389 > 2390 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2391 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/> 2392</svg> 2393 <span 2394 x-text="summaryCount" 2395 x-show="summaryCount" 2396 x-cloak 2397 class="absolute -top-1.5 -right-1.5 px-2 py-0.5 rounded-full bg-green-200 text-green-800 2398 text-xs font-semibold leading-none text-center uppercase tabular-nums" 2399 aria-hidden="true"></span> 2400 </button> 2401 </div> 2402 2403 <div id="site-search" class="col-span-full py-4 lg:py-0 lg:col-auto lg:order-1"> 2404
2404<script> 2405 'use strict'; 2406 2407 function initMiniSearch() { 2408 return { 2409 minSearchLength: 3, 2410 suggestions: [], 2411 suggest() { 2412 const search = this.$refs.searchInput; 2413 if (search.value.length >= this.minSearchLength) { 2414 search.setCustomValidity(''); 2415 search.reportValidity(); 2416 this.fetchSuggestions(search.value); 2417 } else { 2418 this.suggestions = []; 2419 } 2420 }, 2421 fetchSuggestions(term) { 2422 fetch( 2423 window.BASE_URL + 'search/ajax/suggest?' + new URLSearchParams({q: term}), 2424 { 2425 headers: { 2426 'X-Requested-With': 'XMLHttpRequest' 2427 } 2428 } 2429 ) 2430 .then(response => response.json()) 2431 .then(result => this.suggestions = result); 2432 }, 2433 search(term) { 2434 const search = this.$refs.searchInput; 2435 term = term || search.value; 2436 if (term.length < this.minSearchLength) { 2437 search.setCustomValidity('Minimum\u0020Search\u0020query\u0020length\u0020is\u00203'); 2438 search.reportValidity(); 2439 } else { 2440 search.setCustomValidity(''); 2441 search.value = term; 2442 this.$refs.form.submit(); 2443 } 2444 }, 2445 focusElement(element) { 2446 if (element && element.nodeName === "DIV") { 2447 element.focus(); 2448 return true; 2449 } else { 2450 return false; 2451 } 2452 } 2453 } 2454 } 2455</script>
2455 2456<div class="container py-2 mx-auto text-black" x-data="initMiniSearch()"> 2457 <search title="Tienda" role="search"> 2458 <form 2459 id="search_mini_form" 2460 class="form minisearch flex relative" 2461 action="https://www.mueblesbonitos.com/catalogsearch/result/" 2462 method="get" 2463 @submit.prevent="search()" 2464 x-ref="form" 2465 > 2466 <label class="sr-only" for="search"> 2467 Buscar </label> 2468 <input 2469 id="search" 2470 x-ref="searchInput" 2471 type="search" 2472 autocomplete="off" 2473 name="q" 2474 value="" 2475 placeholder="Buscar en toda la tienda..." 2476 maxlength="128" 2477 class="w-full text-lg lg:text-xl text-grey-800 focus:border-transparent focus:outline-none rounded-3xl" 2478 @search-open.window.debounce.10="$el.focus(); $el.select()" 2479 @focus.once="suggest" 2480 @input.debounce.300="suggest" 2481 @keydown.arrow-down.prevent="focusElement($root.querySelector('[tabindex]'))" 2482 > 2483 <button 2484 type="submit" 2485 class="action search absolute right-0 shrink-0 p-3 shadow-none" 2486 title="Buscar" 2487 aria-label="Buscar" 2488 > 2489 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20" aria-hidden="true"> 2490 <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/> 2491</svg> 2492 </button> 2493 </form> 2494 </search> 2495 <template x-if="suggestions.length > 0"> 2496 <nav 2497 aria-label="Search Suggestions" 2498 class="flex flex-col mt-1 text-grey-800 gap-1" 2499 > 2500 <template x-for="suggestion in suggestions"> 2501 <button 2502 type="button" 2503 class="flex justify-between p-2 bg-container-lighter even:bg-container border border-container hover:bg-container-darker" 2504 @click="search(suggestion.title)" 2505 @keydown.enter="search(suggestion.title)" 2506 @keydown.arrow-up.prevent="focusElement($event.target.previousElementSibling) || $refs.searchInput.focus()" 2507 @keydown.arrow-down.prevent="focusElement($event.target.nextElementSibling)" 2508 > 2509 <span x-text="suggestion.title"></span> 2510 <span x-text="suggestion.num_results"></span> 2511 </button> 2512 </template> 2513 </nav> 2514 </template> 2515 </div> 2516 </div> 2517 </div> 2518 2519 <div class="hidden lg:block"> 2520 <div class="container"> 2521 <!-- <style> 2522 .nav-root { outline: 3px solid magenta !important; } 2523</style> --> 2524<nav class="nav-root"> 2525 <!-- El UL de nivel 0 lo imprime el child --> 2526 2527<nav 2528 class="navigation relative hidden lg:block grow" 2529 aria-label="Menú principal" 2530 data-max-level="4" 2531 x-data="initMenuDesktop" 2532 x-ref="nav-desktop" 2533 @load.window="setActiveMenu"> 2534 <ul class="flex flex-wrap gap-x-8"> 2535 <li 2536 class="level-0" 2537 x-data="initMenuDesktopItem" 2538 @click.outside="close" 2539 @keydown.escape="close" 2540 @mouseenter="open = true" 2541 @mouseleave="open = false"> 2542 <a 2543 href="https://www.mueblesbonitos.com/salon" 2544 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2545 border-b-[3px] border-transparent hover:border-blue-500 transition 2546 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2547 :class="{ 'text-blue-500 border-blue-500': open }" 2548 aria-expanded="false" 2549 :aria-expanded="open" 2550 aria-controls="desktop-menu-category-37"> 2551 Salones Modernos <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2552 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2553</svg> 2554 </a> 2555 <div 2556 id="desktop-menu-category-37" 2557 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2558 overflow-hidden " 2559 x-show="open" 2560 x-transition 2561 x-cloak> 2562 <div class="relative overflow-auto min-h-10"> 2563 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2564 2565 <li class="level-1"> 2566 <a 2567 href="https://www.mueblesbonitos.com/salon/mueble-tv" 2568 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2569 >Mueble TV</a> 2570 </li> 2571 2572 <li class="level-1"> 2573 <a 2574 href="https://www.mueblesbonitos.com/salon/aparadores" 2575 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2576 >Aparador</a> 2577 </li> 2578 2579 <li class="level-1"> 2580 <a 2581 href="https://www.mueblesbonitos.com/salon/mesas-de-centro" 2582 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2583 >Mesas de Centro</a> 2584 </li> 2585 2586 <li class="level-1"> 2587 <a 2588 href="https://www.mueblesbonitos.com/salon/mesas-y-sillas-de-comedor" 2589 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2590 >Mesas de Comedor</a> 2591 </li> 2592 2593 <li class="level-1"> 2594 <a 2595 href="https://www.mueblesbonitos.com/salon/estanterias" 2596 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2597 >EstanterÃas de Diseño</a> 2598 </li> 2599 2600 <li class="level-1"> 2601 <a 2602 href="https://www.mueblesbonitos.com/salon/vitrinas" 2603 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2604 >Vitrinas</a> 2605 </li> 2606 2607 <li class="level-1"> 2608 <a 2609 href="https://www.mueblesbonitos.com/salon/armario" 2610 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2611 >Armarios de Salón</a> 2612 </li> 2613 2614 <li class="level-1"> 2615 <a 2616 href="https://www.mueblesbonitos.com/salon/conjuntos-de-salon" 2617 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2618 >Conjuntos de Salón</a> 2619 </li> 2620 2621 <li class="level-1"> 2622 <a 2623 href="https://www.mueblesbonitos.com/salon/muebles-con-chimenea" 2624 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2625 >Muebles con Chimenea</a> 2626 </li> 2627 </ul> 2628 </div> 2629 </div> 2630 </li> 2631 <li 2632 class="level-0" 2633 x-data="initMenuDesktopItem" 2634 @click.outside="close" 2635 @keydown.escape="close" 2636 @mouseenter="open = true" 2637 @mouseleave="open = false"> 2638 <a 2639 href="https://www.mueblesbonitos.com/recibidores" 2640 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2641 border-b-[3px] border-transparent hover:border-blue-500 transition 2642 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2643 :class="{ 'text-blue-500 border-blue-500': open }" 2644 aria-expanded="false" 2645 :aria-expanded="open" 2646 aria-controls="desktop-menu-category-110"> 2647 Recibidores <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2648 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2649</svg> 2650 </a> 2651 <div 2652 id="desktop-menu-category-110" 2653 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2654 overflow-hidden " 2655 x-show="open" 2656 x-transition 2657 x-cloak> 2658 <div class="relative overflow-auto min-h-10"> 2659 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2660 2661 <li class="level-1"> 2662 <a 2663 href="https://www.mueblesbonitos.com/recibidores/consolas-y-zapateros" 2664 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2665 >Consola Recibidor</a> 2666 </li> 2667 2668 <li class="level-1"> 2669 <a 2670 href="https://www.mueblesbonitos.com/recibidores/conjuntos-con-espejo" 2671 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2672 >Recibidor con Espejo</a> 2673 </li> 2674 </ul> 2675 </div> 2676 </div> 2677 </li> 2678 <li 2679 class="level-0" 2680 x-data="initMenuDesktopItem" 2681 @click.outside="close" 2682 @keydown.escape="close" 2683 @mouseenter="open = true" 2684 @mouseleave="open = false"> 2685 <a 2686 href="https://www.mueblesbonitos.com/dormitorio" 2687 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2688 border-b-[3px] border-transparent hover:border-blue-500 transition 2689 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2690 :class="{ 'text-blue-500 border-blue-500': open }" 2691 aria-expanded="false" 2692 :aria-expanded="open" 2693 aria-controls="desktop-menu-category-3"> 2694 Dormitorios <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2695 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2696</svg> 2697 </a> 2698 <div 2699 id="desktop-menu-category-3" 2700 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2701 overflow-hidden " 2702 x-show="open" 2703 x-transition 2704 x-cloak> 2705 <div class="relative overflow-auto min-h-10"> 2706 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2707 2708 <li class="level-1"> 2709 <a 2710 href="https://www.mueblesbonitos.com/dormitorio/camas-de-matrimonio" 2711 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2712 >Camas de Matrimonio</a> 2713 </li> 2714 2715 <li class="level-1"> 2716 <a 2717 href="https://www.mueblesbonitos.com/dormitorio/mesitas-de-noche" 2718 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2719 >Mesitas de Noche</a> 2720 </li> 2721 2722 <li class="level-1"> 2723 <a 2724 href="https://www.mueblesbonitos.com/dormitorio/armarios" 2725 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2726 >Armarios Roperos</a> 2727 </li> 2728 2729 <li class="level-1"> 2730 <a 2731 href="https://www.mueblesbonitos.com/dormitorio/comodas-y-cajoneras" 2732 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2733 >Cómodas</a> 2734 </li> 2735 2736 <li class="level-1"> 2737 <a 2738 href="https://www.mueblesbonitos.com/dormitorio/tocadores" 2739 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2740 >Tocador</a> 2741 </li> 2742 </ul> 2743 </div> 2744 </div> 2745 </li> 2746 <li 2747 class="level-0" 2748 x-data="initMenuDesktopItem" 2749 @click.outside="close" 2750 @keydown.escape="close" 2751 @mouseenter="open = true" 2752 @mouseleave="open = false"> 2753 <a 2754 href="https://www.mueblesbonitos.com/cocina" 2755 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2756 border-b-[3px] border-transparent hover:border-blue-500 transition 2757 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2758 :class="{ 'text-blue-500 border-blue-500': open }" 2759 aria-expanded="false" 2760 :aria-expanded="open" 2761 aria-controls="desktop-menu-category-841"> 2762 Muebles de Cocina <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2763 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2764</svg> 2765 </a> 2766 <div 2767 id="desktop-menu-category-841" 2768 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounde
2768d-b-md bg-white shadow-md 2769 overflow-hidden " 2770 x-show="open" 2771 x-transition 2772 x-cloak> 2773 <div class="relative overflow-auto min-h-10"> 2774 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2775 2776 <li class="level-1"> 2777 <a 2778 href="https://www.mueblesbonitos.com/cocina/mesas-altas" 2779 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2780 >Mesas Altas de Cocina</a> 2781 </li> 2782 2783 <li class="level-1"> 2784 <a 2785 href="https://www.mueblesbonitos.com/cocina/taburetes" 2786 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2787 >Taburetes de Cocina</a> 2788 </li> 2789 2790 <li class="level-1"> 2791 <a 2792 href="https://www.mueblesbonitos.com/cocina/armarios-de-cocina" 2793 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2794 >Armarios de Cocina</a> 2795 </li> 2796 </ul> 2797 </div> 2798 </div> 2799 </li> 2800 <li 2801 class="level-0" 2802 x-data="initMenuDesktopItem" 2803 @click.outside="close" 2804 @keydown.escape="close" 2805 @mouseenter="open = true" 2806 @mouseleave="open = false"> 2807 <a 2808 href="https://www.mueblesbonitos.com/bano" 2809 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2810 border-b-[3px] border-transparent hover:border-blue-500 transition 2811 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2812 :class="{ 'text-blue-500 border-blue-500': open }" 2813 aria-expanded="false" 2814 :aria-expanded="open" 2815 aria-controls="desktop-menu-category-843"> 2816 Muebles de Baño <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2817 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2818</svg> 2819 </a> 2820 <div 2821 id="desktop-menu-category-843" 2822 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2823 overflow-hidden " 2824 x-show="open" 2825 x-transition 2826 x-cloak> 2827 <div class="relative overflow-auto min-h-10"> 2828 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2829 2830 <li class="level-1"> 2831 <a 2832 href="https://www.mueblesbonitos.com/bano/conjuntos-de-bano" 2833 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2834 >Conjuntos de baño</a> 2835 </li> 2836 2837 <li class="level-1"> 2838 <a 2839 href="https://www.mueblesbonitos.com/bano/columnas-y-armarios-de-bano" 2840 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2841 >Columna de Baño</a> 2842 </li> 2843 </ul> 2844 </div> 2845 </div> 2846 </li> 2847 <li 2848 class="level-0" 2849 x-data="initMenuDesktopItem" 2850 @click.outside="close" 2851 @keydown.escape="close" 2852 @mouseenter="open = true" 2853 @mouseleave="open = false"> 2854 <a 2855 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares" 2856 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2857 border-b-[3px] border-transparent hover:border-blue-500 transition 2858 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2859 :class="{ 'text-blue-500 border-blue-500': open }" 2860 aria-expanded="false" 2861 :aria-expanded="open" 2862 aria-controls="desktop-menu-category-76"> 2863 Muebles Auxiliares <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2864 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2865</svg> 2866 </a> 2867 <div 2868 id="desktop-menu-category-76" 2869 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2870 overflow-hidden " 2871 x-show="open" 2872 x-transition 2873 x-cloak> 2874 <div class="relative overflow-auto min-h-10"> 2875 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2876 2877 <li class="level-1"> 2878 <a 2879 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/zapateros" 2880 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2881 >Zapateros</a> 2882 </li> 2883 2884 <li class="level-1"> 2885 <a 2886 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/escritorios" 2887 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2888 >Escritorios Modernos</a> 2889 </li> 2890 2891 <li class="level-1"> 2892 <a 2893 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/baules" 2894 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2895 >Baúles</a> 2896 </li> 2897 2898 <li class="level-1"> 2899 <a 2900 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/armarios-multiusos" 2901 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2902 >Armario Multiusos</a> 2903 </li> 2904 2905 <li class="level-1"> 2906 <a 2907 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/plantas-artificiales" 2908 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2909 >Plantas artificiales</a> 2910 </li> 2911 2912 <li class="level-1"> 2913 <a 2914 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/mesa-altavoz" 2915 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2916 >Mesa altavoz</a> 2917 </li> 2918 2919 <li class="level-1"> 2920 <a 2921 href="https://www.mueblesbonitos.com/decoracion-y-auxiliares/mini-huertas" 2922 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2923 >Mini Huerto en Casa</a> 2924 </li> 2925 </ul> 2926 </div> 2927 </div> 2928 </li> 2929 <li 2930 class="level-0" 2931 x-data="initMenuDesktopItem" 2932 @click.outside="close" 2933 @keydown.escape="close" 2934 @mouseenter="open = true" 2935 @mouseleave="open = false"> 2936 <a 2937 href="https://www.mueblesbonitos.com/ofertas" 2938 class="level-0 group w-full flex justify-between items-center gap-1 py-4 2939 border-b-[3px] border-transparent hover:border-blue-500 transition 2940 data-[has-current]:border-slate-400 data-[has-current]:hover:border-blue-500" 2941 :class="{ 'text-blue-500 border-blue-500': open }" 2942 aria-expanded="false" 2943 :aria-expanded="open" 2944 aria-controls="desktop-menu-category-525"> 2945 Ofertas <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="transition text-slate-400" width="24" height="24" aria-hidden="true" :class="{ 'rotate-180 text-blue-500': open }"> 2946 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2947</svg> 2948 </a> 2949 <div 2950 id="desktop-menu-category-525" 2951 class="z-30 absolute top-full inset-x-0 border-t border-slate-100 rounded-b-md bg-white shadow-md 2952 overflow-hidden " 2953 x-show="open" 2954 x-transition 2955 x-cloak> 2956 <div class="relative overflow-auto min-h-10"> 2957 <ul class="flex flex-col gap-1 py-2.5 px-2 w-72"> 2958 2959 <li class="level-1"> 2960 <a 2961 href="https://www.mueblesbonitos.com/ofertas/ultimas-unidades" 2962 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2963 >Ãltimas unidades</a> 2964 </li> 2965 2966 <li class="level-1"> 2967 <a 2968 href="https://www.mueblesbonitos.com/ofertas/muebles-de-segunda-vida" 2969 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2970 >Muebles de Segunda Vida</a> 2971 </li> 2972 2973 <li class="level-1"> 2974 <a 2975 href="https://www.mueblesbonitos.com/ofertas/outlet" 2976 class="level-1 flex p-2 rounded-md hover:bg-slate-50 aria-[current=page]:font-medium" 2977 >Outlet </a> 2978 </li> 2979 </ul> 2980 </div> 2981 </div> 2982 </li> 2983 <li> 2984 <a 2985 href="https://www.mueblesbonitos.com/novedades" 2986 title="Novedades" 2987 class="level-0 flex py-4 border-b-[3px] border-transparent hover:border-blue-500 2988 aria-[current=page]:border-slate-400 aria-[current=page]:hover:border-blue-500 2989 " 2990 rel="nofollow" 2991 > 2992 Novedades </a> 2993 </li> 2994 </ul> 2995</nav>
2996<script> 2997 function initMenuDesktop() { 2998 return { 2999 maxLevel: parseInt(this.$root.dataset.maxLevel), 3000 setActiveMenu() { 3001 Array.from(this.$root.querySelectorAll('a')) 3002 .filter(link => link.href === window.location.href.split('?')[0]) 3003 .forEach(item => { 3004 item.setAttribute('aria-current', 'page'); 3005 3006 for (let level = 0; level < maxLevel; level++) { 3007 const closestMenu = item.closest(`.level-${level}`); 3008 3009 if (closestMenu) { 3010 const button = closestMenu.querySelector('button') || closestMenu.querySelector('a.level-0'); 3011 if (button) { 3012 button.setAttribute('data-has-current', ''); 3013 } 3014 } 3015 } 3016 }); 3017 } 3018 } 3019 } 3020 3021 function initMenuDesktopItem() { 3022 return { 3023 open: false, 3024 canHover(func) { 3025 return window.matchMedia('(hover: hover) and (pointer: fine)').matches; 3026 }, 3027 canHoverOpen() { 3028 if (!this.canHover()) return; 3029 this.open = true; 3030 }, 3031 canHoverClose() { 3032 if (!this.canHover()) return; 3033 this.open = false; 3034 }, 3035 toggle() { 3036 this.open = !this.open; 3037 }, 3038 close() { 3039 this.open = false; 3040 } 3041 } 3042 } 3043 3044 function initSubMenuDesktopItem() { 3045 return { 3046 open: false, 3047 toggle() { 3048 this.open = !this.open; 3049 this.$nextTick(() => { 3050 this.$refs.childmenuViewAll.focus(); 3051 this.$refs.childmenuWrapper.scrollIntoView({ 3052 behavior: 'smooth', 3053 block: 'nearest', 3054 inline: 'end' 3055 }); 3056 }); 3057 }, 3058 close() { 3059 this.open = false; 3060 this.$refs.childmenuToggle.focus(); 3061 }, 3062 } 3063 } 3064 3065 window.addEventListener('alpine:init', () => { 3066 Alpine.data('initMenuDesktop', initMenuDesktop); 3067 Alpine.data('initMenuDesktopItem', initMenuDesktopItem); 3068 Alpine.data('initSubMenuDesktopItem', initSubMenuDesktopItem); 3069 }, { 3070 once: true 3071 }) 3072</script>
3072 3073</nav> 3074 3075 </div> 3076 </div> 3077 3078
3079<script> 3080 function initCartDrawer() { 3081 return { 3082 open: false, 3083 isLoading: false, 3084 cart: {}, 3085 maxItemsToDisplay: 10, 3086 itemsCount: 0, 3087 isLoggedIn: false, 3088 isVipCustomer: false, 3089 updateQtyUrl: 'https\u003A\u002F\u002Fwww.mueblesbonitos.com\u002Fcheckout\u002Fsidebar\u002FupdateItemQty\u002F', 3090 removeItemUrl: 'https\u003A\u002F\u002Fwww.mueblesbonitos.com\u002Fcheckout\u002Fsidebar\u002FremoveItem\u002F', 3091 cartItems: [], 3092 3093 getData(data) { 3094 if (data.cart) { 3095 this.cart = data.cart; 3096 this.itemsCount = (data.cart.items && data.cart.items.length) || 0; 3097 this.setCartItems(); 3098 this.isVipCustomer = data.cart.is_vip_customer || false; 3099 } 3100 this.isLoggedIn = !!(data.customer && data.customer.fullname); 3101 this.isLoading = false; 3102 }, 3103 getItemCountTitle() { 3104 return hyva.strf('Mostrando\u0020\u00250\u0020de\u0020\u00251\u0020productos\u0020en\u0020el\u0020carrito', this.maxItemsToDisplay, this.itemsCount) 3105 }, 3106 setCartItems() { 3107 this.cartItems = (this.cart.items && this.cart.items.sort((a, b) => b.item_id - a.item_id)) || []; 3108 if (this.maxItemsToDisplay > 0) { 3109 this.cartItems = this.cartItems.slice(0, parseInt(this.maxItemsToDisplay, 10)); 3110 } 3111 }, 3112 updateItemQty(itemId, currentQty, operation) { 3113 this.isLoading = true; 3114 const qty = Number(String(currentQty).replace(',', '.')); 3115 const safeQty = Number.isFinite(qty) ? qty : 1; 3116 let newQty = operation === 'add' ? safeQty + 1 : safeQty - 1; 3117 newQty = Math.round(newQty); 3118 if (newQty <= 0) { 3119 this.deleteItemFromCart(itemId); 3120 return; 3121 } 3122 3123 fetch(this.updateQtyUrl, { 3124 method: 'POST', 3125 credentials: 'include', 3126 headers: { 3127 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 3128 'X-Requested-With': 'XMLHttpRequest', 3129 'Accept': 'application/json' 3130 }, 3131 body: new URLSearchParams({ 3132 form_key: hyva.getFormKey(), 3133 item_id: String(Math.round(Number(itemId))), 3134 item_qty: String(newQty), 3135 qty: String(newQty) 3136 }) 3137 }) 3138 .then(async (response) => { 3139 if (response.redirected) { 3140 this.isLoading = false; 3141 return null; 3142 } 3143 const data = await response.json().catch(() => null); 3144 if (!response.ok) throw new Error(data?.error_message || 'Error'); 3145 return data; 3146 }) 3147 .then((result) => { 3148 this.isLoading = false; 3149 if (result && !result.error_message) window.dispatchEvent(new CustomEvent('reload-customer-section-data')); 3150 }).catch(() => { 3151 this.isLoading = false; 3152 }); 3153 }, 3154 deleteItemFromCart(itemId) { 3155 this.isLoading = true; 3156 fetch(this.removeItemUrl, { 3157 method: 'POST', 3158 credentials: 'include', 3159 headers: { 3160 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 3161 'X-Requested-With': 'XMLHttpRequest', 3162 'Accept': 'application/json' 3163 }, 3164 body: new URLSearchParams({ 3165 form_key: hyva.getFormKey(), 3166 item_id: String(Math.round(Number(itemId))) 3167 }) 3168 }).then(() => { 3169 this.isLoading = false;
3170 window.dispatchEvent(new CustomEvent('reload-customer-section-data')); 3171 }); 3172 }, 3173 scrollLock(use = true) { 3174 document.body.style.overflow = use ? "hidden" : ""; 3175 }, 3176 toggleCartDrawer(event) { 3177 if (event.detail && event.detail.isOpen !== undefined) { 3178 if (event.detail.isOpen) { 3179 this.openCartDrawer(); 3180 } else { 3181 this.open = false; 3182 this.scrollLock(false); 3183 } 3184 } else { 3185 this.openCartDrawer(); 3186 } 3187 }, 3188 openCartDrawer() { 3189 this.open = true; 3190 this.scrollLock(true); 3191 }, 3192 closeCartDrawer() { 3193 this.$dispatch('toggle-cart', { 3194 isOpen: false 3195 }); 3196 }, 3197 getSectionDataExtraActions() { 3198 if (!this.cart.extra_actions) return ''; 3199 const contentNode = document.createElement('div'); 3200 contentNode.innerHTML = this.cart.extra_actions; 3201 hyva.activateScripts(contentNode); 3202 return contentNode.innerHTML; 3203 } 3204 } 3205 } 3206</script>
3206 3207 3208<section x-cloak x-show="cart" id="cart-drawer" x-data="initCartDrawer()" 3209 @private-content-loaded.window="getData($event.detail.data)" 3210 @toggle-cart.window="toggleCartDrawer($event)" 3211 @keydown.escape="closeCartDrawer"> 3212 3213 <div role="dialog" aria-modal="true" :aria-hidden="!open" class="fixed inset-y-0 right-0 z-30 flex max-w-full"> 3214 <div class="backdrop" x-show="open" x-transition:enter="ease-out duration-500" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" @click="closeCartDrawer"></div> 3215 3216 <div class="relative w-screen max-w-md shadow-2xl" x-show="open" x-transition:enter="transform transition ease-in-out duration-500" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0"> 3217 3218 <div class="flex flex-col h-full bg-white text-black shadow-xl overflow-hidden"> 3219 3220 <header class="relative px-4 py-4 sm:px-6 border-b border-gray-100 flex-shrink-0 flex items-center justify-between bg-white z-[60]"> 3221 <div id="cart-drawer-title" class="text-lg font-medium text-gray-900"> 3222 <strong>Mi Carrito</strong> 3223 <span class="text-xs ml-2" x-show="maxItemsToDisplay && maxItemsToDisplay < itemsCount" x-text="getItemCountTitle()"></span> 3224 </div> 3225 3226 <button type="button" @click="closeCartDrawer" class="p-2 text-gray-400 hover:text-[#34515E] transition-colors" aria-label="Cerrar"> 3227 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6 h-6" width="24" height="24" role="img"> 3228 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 3229<title>x</title></svg> 3230 </button> 3231 </header> 3232 3233 <div class="flex-1 overflow-y-auto overscroll-contain px-1 py-3 sm:px-3 bg-white"> 3234 3235 <template x-if="!itemsCount"> 3236 <div class="px-4 py-6 text-center text-gray-500">El carrito está vacÃo</div> 3237 </template> 3238 3239 <template x-if="itemsCount"> 3240 <div class="relative grid gap-6 sm:gap-8 overflow-y-auto overscroll-y-contain"> 3241 <template x-for="item in cartItems" :key="item.item_id"> 3242 <div class="flex items-start p-3 space-x-4 transition duration-150 ease-in-out rounded-lg hover:bg-gray-100"> 3243 <div class="w-1/4 !ml-0"> 3244 <img :src="item.product_image.src" loading="lazy" :alt="item.product_name" /> 3245 </div> 3246 3247 <div class="w-3/4 space-y-2"> 3248 <div> 3249 <p class="text-xl font-bold" x-show="item.serie" x-text="item.serie"></p> 3250 <p class="text-lg text-gray-700"> 3251 <span x-text="item.qty"></span> x <span x-html="item.product_name"></span> 3252 </p> 3253 </div> 3254 3255 <template x-for="option in item.options" :key="option.label"> 3256 <div class="pt-2"> 3257 <p class="font-semibold" x-text="option.label + ':'"></p> 3258 <p class="text-secondary" x-html="option.value"></p> 3259 </div> 3260 </template> 3261 3262 <div class="flex items-end justify-between w-full mt-3"> 3263 <div class="flex items-center space-x-4"> 3264 <div class="flex items-center space-x-1 border border-gray-300 rounded-md"> 3265 <button type="button" class="p-1 text-gray-500 hover:text-gray-700" @click.prevent="updateItemQty(item.item_id, item.qty, 'sub')">-</button>
3266 <span class="text-base font-bold px-1" x-text="item.qty"></span> 3267 <button type="button" class="p-1 text-gray-500 hover:text-gray-700" @click.prevent="updateItemQty(item.item_id, item.qty, 'add')">+</button> 3268 </div> 3269 3270 <button type="button" @click="deleteItemFromCart(item.item_id)" class="p-1 text-gray-700 hover:text-red-600 transition"> 3271 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5" width="24" height="24" role="img"> 3272 <path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/> 3273<title>trash</title></svg> 3274 </button> 3275 </div> 3276 3277 <div class="text-right"> 3278 <p :class="{'font-bold text-base': isVipCustomer, 'text-gray-500 text-sm': !isVipCustomer && item.vip_price, 'font-bold': !item.vip_price}"> 3279 <span x-html="isVipCustomer ? item.vip_price : item.product_price"></span> 3280 </p> 3281 <div x-show="!isVipCustomer && item.vip_price" class="flex items-baseline justify-end gap-1.5 mt-1"> 3282 <span class="text-[11px] font-semibold text-gray-700 whitespace-nowrap tracking-wider uppercase">VIP</span> 3283 <span class="font-bold text-lg leading-none" style="color: #8cc4b2;" x-html="item.vip_price"></span> 3284 </div> 3285 </div> 3286 </div> 3287 </div> 3288 </div> 3289 </template> 3290 </div> 3291 </template> 3292 </div> 3293 3294 <div class="flex-shrink-0 bg-gray-50 border-t border-gray-200 overflow-y-auto max-h-[40vh]"> 3295 <template x-if="itemsCount"> 3296 <div class="p-3 space-y-3"> 3297 <div class="space-y-1"> 3298 <div class="flex justify-between text-s text-gray-500"> 3299 <span x-text="isLoggedIn ? 'Subtotal\u0020al\u0020precio\u0020VIP' : 'Subtotal'"></span> 3300 <span x-html="cart.subtotal"></span> 3301 </div> 3302 <template x-if="!isVipCustomer && cart.vip_subtotal"> 3303 <div class="flex justify-between items-center border-b border-gray-200 pb-2"> 3304 <span class="text-s font-bold text-[#34515E]">Subtotal VIP</span> 3305 <span x-html="cart.vip_subtotal" class="text-xl font-bold text-[#8cc4b2]"></span> 3306 </div> 3307 </template> 3308 </div> 3309 3310 <div class="space-y-4"> 3311 <div class="minicart-payment-logos flex flex-wrap justify-center gap-1 opacity-70 scale-[0.75] origin-center mt-2 mb-4" id="logos_minicart"> 3312 3313<div 3314 class="container flex gap-4 flex-wrap justify-center" 3315 aria-label="Payment Providers"> 3316 <!-- --> 3317 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a)"><path fill="#d9dff7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#1434cb" d="M19.108 10.212 14.243 21.82H11.07l-2.393-9.263c-.146-.57-.272-.78-.714-1.02-.722-.391-1.913-.759-2.962-.987l.071-.337h5.109c.651 0 1.237.434 1.385 1.184l1.264 6.715 3.124-7.9zm12.435 7.817c.013-3.063-4.236-3.232-4.206-4.6.009-.417.405-.86 1.273-.973.43-.056 1.616-.099 2.96.52l.527-2.461A8.1 8.1 0 0 0 29.29 10c-2.968 0-5.056 1.578-5.074 3.837-.019 1.67 1.491 2.603 2.629 3.158 1.17.569 1.563.934 1.558 1.443-.008.778-.933 1.122-1.798 1.135-1.509.024-2.385-.408-3.083-.733l-.544 2.543c.702.322 1.997.603 3.339.617 3.154 0 5.218-1.558 5.227-3.97m7.837 3.79h2.777l-2.424-11.607H37.17c-.577 0-1.063.336-1.278.852L31.387 21.82h3.152l.626-1.734h3.852zm-3.35-4.113 1.58-4.358.91 4.358zm-12.632-7.494L20.915 21.82h-3.002l2.483-11.607z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>visa</title></svg> 3318 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_2)"><path fill="#f1efeb" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#ff5f00" d="M28.376 8.139h-8.75v15.725h8.75z"/><path fill="#eb001b" d="M20.181 16a9.98 9.98 0 0 1 3.82-7.861A9.96 9.96 0 0 0 17.82 6c-5.522 0-10 4.478-10 10s4.478 10 10 10A9.96 9.96 0 0 0 24 23.861 9.98 9.98 0 0 1 20.182 16"/><path fill="#f79e1b" d="M40.178 16c0 5.522-4.477 10-10 10-2.333 0-4.477-.8-6.18-2.139A9.98 9.98 0 0 0 27.818 16a9.98 9.98 0 0 0-3.82-7.861A9.96 9.96 0 0 1 30.178 6c5.522 0 10 4.478 10 10"/></g><defs><clipPath id="a_2"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>mastercard</title></svg> 3319 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_3)"><path fill="#d6edff" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M43 10.5v9.523h-2.167V10.5zm-2.965 3.214v6.327H38.11v-.546a2.6 2.6 0 0 1-.83.546q-.465.201-1.006.203-.679 0-1.259-.253a3.2 3.2 0 0 1-1.006-.72 3.5 3.5 0 0 1-.682-1.06 3.7 3.7 0 0 1-.238-1.33q-.001-.708.238-1.313.252-.619.682-1.
3319076a3 3 0 0 1 1.006-.708 3 3 0 0 1 1.26-.267q.539 0 1.006.203.466.19.83.545v-.545h1.925zm-3.414 4.604q.592.001.97-.407.39-.404.39-1.035c0-.42-.13-.769-.39-1.036a1.27 1.27 0 0 0-.97-.406c-.391 0-.722.134-.983.406q-.377.405-.377 1.036c0 .42.127.769.377 1.035q.391.406.983.407M29.996 10.5q.857 0 1.462.24.604.24 1.02.67.428.444.668 1.013.239.57.238 1.227.001.657-.238 1.227c-.157.377-.383.72-.667 1.013q-.415.43-1.021.67-.604.24-1.462.24h-1.044v3.238h-2.205V10.5zm-.316 4.34c.296 0 .519-.03.681-.09q.254-.103.415-.253.34-.316.34-.847t-.34-.847a1.2 1.2 0 0 0-.415-.24q-.239-.101-.681-.102h-.731v2.378zm-11.055-1.126h2.393l1.624 3.034h.027l1.447-3.034h2.216l-4.748 9.538h-2.205l2.167-4.363zm-.427 0v6.327h-1.926v-.546a2.6 2.6 0 0 1-.83.546q-.466.201-1.006.203-.679 0-1.259-.253a3.2 3.2 0 0 1-1.006-.72 3.6 3.6 0 0 1-.682-1.06 3.7 3.7 0 0 1-.238-1.33q0-.708.238-1.313.251-.619.682-1.076a3 3 0 0 1 1.006-.708 3 3 0 0 1 1.26-.267q.539 0 1.006.203.467.19.83.545v-.545h1.925zm-3.414 4.604q.591.001.972-.407.392-.404.392-1.035c0-.42-.13-.769-.392-1.036a1.27 1.27 0 0 0-.972-.406q-.591-.001-.983.406-.378.405-.377 1.036c0 .42.128.769.377 1.035q.392.406.983.407M8.25 10.5q.857 0 1.462.24.604.24 1.02.67.428.444.668 1.013.239.57.238 1.227.001.657-.238 1.227c-.156.377-.383.72-.667 1.013q-.415.43-1.021.67-.604.24-1.462.24H7.205v3.238H5V10.5zm-.313 4.34c.295 0 .519-.03.681-.09a1.3 1.3 0 0 0 .415-.253q.34-.316.34-.847t-.34-.847a1.2 1.2 0 0 0-.415-.24q-.24-.101-.681-.102h-.731v2.378z"/></g><defs><clipPath id="a_3"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>paypal</title></svg> 3320 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_4)"><path fill="#fff1f7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M39.478 18.825c-.884 0-1.572-.724-1.572-1.603 0-.88.688-1.603 1.572-1.603s1.573.724 1.573 1.603c0 .88-.69 1.603-1.573 1.603m-.442 1.694c.754 0 1.716-.284 2.249-1.396l.052.025c-.234.608-.234.97-.234 1.06v.143H43v-6.258h-1.897v.142c0 .09 0 .453.233 1.06l-.051.026c-.533-1.112-1.495-1.396-2.249-1.396-1.806 0-3.08 1.422-3.08 3.297s1.274 3.297 3.08 3.297m-6.38-6.594c-.858 0-1.534.297-2.08 1.396l-.052-.026c.234-.607.234-.97.234-1.06v-.142H28.86v6.258h1.95v-3.297c0-.866.507-1.41 1.325-1.41.82 0 1.222.466 1.222 1.397v3.31h1.95v-3.982c0-1.423-1.118-2.444-2.652-2.444M26.04 15.32l-.052-.026c.234-.607.234-.97.234-1.06v-.142h-1.897v6.258h1.95l.012-3.013c0-.879.468-1.41 1.235-1.41.208 0 .377.027.572.078v-1.913c-.858-.181-1.625.142-2.054 1.228m-6.199 3.504c-.883 0-1.572-.724-1.572-1.603 0-.88.689-1.603 1.572-1.603s1.573.724 1.573 1.603c0 .88-.689 1.603-1.5
332073 1.603M19.4 20.52c.754 0 1.716-.284 2.249-1.396l.052.025c-.234.608-.234.97-.234 1.06v.143h1.897v-6.258h-1.897v.142c0 .09 0 .453.234 1.06l-.052.026c-.533-1.112-1.495-1.396-2.248-1.396-1.807 0-3.08 1.422-3.08 3.297s1.273 3.297 3.08 3.297m-5.796-.168h1.95V11.3h-1.95zm-1.43-9.051h-1.988c0 1.616-1 3.064-2.52 4.099l-.599.414V11.3H5v9.05h2.066v-4.486l3.418 4.487h2.521l-3.288-4.293c1.495-1.073 2.47-2.74 2.457-4.758"/></g><defs><clipPath id="a_4"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>klarna</title></svg> 3321 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_5)"><path fill="#e6e6e6" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M13.422 11.356a2.62 2.62 0 0 0 .604-1.856 2.6 2.6 0 0 0-1.718.88 2.47 2.47 0 0 0-.615 1.793 2.12 2.12 0 0 0 1.729-.817m.605.944c-.955-.063-1.761.541-2.217.541s-1.157-.509-1.91-.498a2.81 2.81 0 0 0-2.397 1.453c-1.06 1.76-.265 4.38.732 5.823.488.71 1.06 1.496 1.835 1.464s1.008-.467 1.888-.467 1.146.467 1.91.456c.763-.01 1.293-.71 1.781-1.421a6.4 6.4 0 0 0 .796-1.644 2.57 2.57 0 0 1-1.549-2.344 2.61 2.61 0 0 1 1.252-2.207 2.73 2.73 0 0 0-2.121-1.156m8.305-1.983a3.34 3.34 0 0 1 3.51 3.51 3.393 3.393 0 0 1-3.563 3.48h-2.291v3.648h-1.666V10.317zm-2.344 5.643h1.92a2.005 2.005 0 0 0 2.259-2.122 1.983 1.983 0 0 0-2.249-2.121h-1.91zm6.29 2.821c0-1.358 1.06-2.196 2.895-2.302l2.122-.127v-.594c0-.87-.584-1.39-1.56-1.39a1.485 1.485 0 0 0-1.644 1.146h-1.506c.096-1.39 1.294-2.45 3.214-2.45s3.097 1.008 3.097 2.567v5.367H31.37v-1.283a2.76 2.76 0 0 1-2.46 1.41 2.364 2.364 0 0 1-2.631-2.344m5.027-.7v-.615l-1.92.116c-.954.064-1.495.488-1.495 1.157 0 .668.562 1.124 1.421 1.124a1.87 1.87 0 0 0 1.994-1.782m3.033 5.781V22.61q.26.024.52 0a1.305 1.305 0 0 0 1.39-1.06l.137-.478-2.81-7.86h1.728l1.973 6.365 1.962-6.365H41l-2.917 8.189c-.657 1.888-1.432 2.493-3.044 2.493-.18 0-.573-.011-.7-.032"/></g><defs><clipPath id="a_5"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>apple-pay</title></svg> 3322 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_6)"><path fill="#e4e5e7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#3c4043" d="M22.869 16.488v3.933H21.62v-9.712h3.309q1.259 0 2.139.838.897.84.897 2.048c0 .826-.3 1.508-.898 2.06q-.869.828-2.138.827h-2.061zm0-4.583v3.387h2.087c.494 0 .91-.17 1.235-.5.331-.332.5-.735.5-1.19a1.62 1.62 0 0 0-.5-1.177q-.486-.516-1.235-.514h-2.087zm8.361 1.651q1.383 0 2.183.741.8.74.8 2.029v4.095h-1.19v-.923h-.052q-.771 1.139-2.06 1.138-1.1.001-1.84-.65-.741-.652-.741-1.626 0-1.033.78-1.638.781-.613 2.08-.611 1.113 0 1.827.41v-.287c0-.435-.17-.8-.514-1.105a1.76 1.76 0 0 0-1.209-.455c-.695 0-1.248.293-1.651.884l-1.099-.689q.909-1.314 2.685-1.313m-1.613 4.824c0 .325.136.598.416.812q.411.324.968.325.79 0 1.405-.585.616-.583.617-1.371-.584-.46-1.625-.462-.76.002-1.268.364-.515.381-.513.917M41 13.77l-4.16 9.57h-1.288l1.547-3.348-2.743-6.221h1.359l1.976 4.771h.026l1.924-4.771z"/><path fill="#4285f4" d="M17.904 15.695q-.001-.61-.104-1.171h-5.232v2.145l3.013.001a2.58 2.58 0 0 1-1.118 1.728v1.392h1.794c1.047-.97 1.647-2.402 1.647-4.095"/><path fill="#34a853" d="M14.464 18.398c-.5.337-1.142.534-1.895.534-1.453 0-2.685-.98-3.127-2.3h-1.85v1.436a5.57 5.57 0 0 0 4.977 3.067c1.505 0 2.768-.494 3.688-1.346z"/><path fill="#fabb05" d="M9.268 15.568c0-.37.062-.729.174-1.065v-1.436h-1.85A5.54 5.54 0 0 0 7 15.568c0 .9.214 1.749.592 2.501l1.85-1.435a3.4 3.4 0 0 1-.174-1.066"/><path fill="#e94235" d="M12.57 12.204c.82 0 1.556.283 2.136.835l1.59-1.588c-.966-.9-2.224-1.451-3.727-1.451a5.57 5.57 0 0 0-4.977 3.067l1.85 1.436c.442-1.32 1.674-2.3 3.127-2.3"/></g><defs><clipPath id="a_6"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>google-pay</title></svg> 3323 3324</div> </div> 3325 3326 <a @click.prevent.stop="closeCartDrawer; $dispatch('toggle-authentication', {url: 'https://www.mueblesbonitos.com/checkout/'});" 3327 href="https://www.mueblesbonitos.com/checkout/" 3328 class="block w-full text-center rounded-lg shadow font-bold text-base text-white py-3 transition hover:brightness-110" 3329 style="background-color: #34515E !important;"> 3330 Finalizar compra </a> 3331 </div> 3332 3333 <template x-if="!isVipCustomer"> 3334 <a href="https://www.mueblesbonitos.com/customer/account/login/" 3335 rel="nofollow" 3336 class="block p-2 rounded-lg bg-white border border-gray-200 text-center shadow-sm">
3337 <span class="text-[14px] font-bold text-[#34515E]"> 3338 ¿Quieres ser VIP? <span style="color: #8cc4b2;" class="underline ml-1">Pincha aquÃ</span> 3339 </span> 3340 </a> 3341 </template> 3342 </div> 3343 </template> 3344 </div> 3345 </div> 3346 </div> 3347 </div> 3348</section> 3349<klarna-placement data-key="top-strip-promotion-badge" data-locale="es-ES"></klarna-placement> <!-- BLOCK authentication-popup -->
3349<script> 3350 function initAuthentication() { 3351 return { 3352 open: false, 3353 close() { 3354 this.open = false; 3355 }, 3356 forceAuthentication: false, 3357 checkoutUrl: 'https://www.mueblesbonitos.com/checkout/index/', 3358 errors: 0, 3359 hasCaptchaToken: 0, 3360 displayErrorMessage: false, 3361 errorMessages: [], 3362 setErrorMessages(message) { 3363 this.errorMessages = [message]; 3364 this.displayErrorMessage = true; 3365 }, 3366 submitForm() { 3367 // Do not rename $form, the variable is expected to be declared in the recaptcha output 3368 const $form = document.querySelector('#login-form'); 3369 if (!this.hasCaptchaToken) { 3370 this.errors = 1; 3371 3372 3373 const executeGreCaptcha = () => { 3374 grecaptcha.ready(() => { 3375 grecaptcha.execute( 3376 '6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3', 3377 {action: 'submit'} 3378 ).then((token) => { 3379 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 3380 3381 if (tokenElement && token && token.length > 0) { 3382 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 3383 this.errors = 0; 3384 this.hasCaptchaToken = 1; 3385 (this.submitForm || $form.submit).call(this); 3386 } else { 3387 this.errors = 1; 3388 const error = tokenElement 3389 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 3390 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 3391 if (this.setErrorMessages) { 3392 this.setErrorMessages([error]) 3393 this.displayErrorMessage = true; 3394 } else { 3395 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 3396 } 3397 } 3398 }).catch(exception => { 3399 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 3400 }); 3401 }) 3402 } 3403 3404 if (window.grecaptcha) { 3405 executeGreCaptcha(); 3406 } else { 3407 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3"; 3408 const script = document.createElement('script'); 3409 script.setAttribute('type', 'text/javascript'); 3410 script.setAttribute('src', recaptchaUrl); 3411 document.head.appendChild(script); 3412 3413 script.addEventListener("load", executeGreCaptcha, false); 3414 } 3415 } 3416 3417 if (this.errors === 0) { 3418 this.dispatchLoginRequest($form); 3419 } 3420 }, 3421 onPrivateContentLoaded() { 3422 const data = this.$event.detail.data; 3423 const isLoggedIn = data.customer && data.customer.firstname; 3424 if (data.cart && !isLoggedIn) { 3425 this.forceAuthentication = !data.cart.isGuestCheckoutAllowed; 3426 } 3427 }, 3428 redirectIfAuthenticated() { 3429 const event = this.$event; 3430 this.open = this.forceAuthentication; 3431 3432 if (event.detail && event.detail.url) { 3433 this.checkoutUrl = event.detail.url; 3434 } 3435 if (!this.forceAuthentication) { 3436 window.location.href = this.checkoutUrl; 3437 } 3438 }, 3439 resetErrors() { 3440 this.errors = 0; 3441 }, 3442 dispatchLoginRequest(form) { 3443 this.isLoading = true; 3444 const username = this.$refs['customer-email'].value; 3445 const password = this.$refs['customer-password'].value; 3446 const formKey = hyva.getFormKey(); 3447 const bodyFields = { 3448 'username': username, 3449 'password': password, 3450 'formKey': formKey 3451 }; 3452 const fieldName = 'g\u002Drecaptcha\u002Dresponse'; 3453 const recaptchaField = fieldName && form[fieldName]; 3454 if (recaptchaField) { 3455 bodyFields[fieldName] = recaptchaField.value; 3456 } 3457 fetch('https://www.mueblesbonitos.com/customer/ajax/login/', { 3458 method: 'POST', 3459 headers: { 3460 'Content-Type': 'application/json', 3461 'X-Requested-With': 'XMLHttpRequest' 3462 }, 3463 body: JSON.stringify(bodyFields) 3464 } 3465 ).then(response => { 3466 return response.json() 3467 } 3468 ).then(data => { 3469 this.isLoading = false;
3470 if (data.errors) { 3471 this.setErrorMessages(data.message); 3472 this.errors = 1; 3473 this.hasCaptchaToken = 0; 3474 } else { 3475 window.location.href = this.checkoutUrl; 3476 } 3477 }); 3478 }, 3479 eventListeners: { 3480 ['@private-content-loaded.window']() { 3481 this.onPrivateContentLoaded(); 3482 }, 3483 ['@toggle-authentication.window']() { 3484 this.redirectIfAuthenticated(); 3485 }, 3486 ['@pageshow.window'](event) { 3487 if (event.persisted) { 3488 this.close(); 3489 }; 3490 } 3491 } 3492 } 3493 } 3494 3495 window.addEventListener('alpine:init', () => Alpine.data('initAuthentication', initAuthentication), {once: true}) 3496</script>
3496 3497 3498<dialog 3499 id="authentication-popup" 3500 aria-labelledby="authentication-popup-title" 3501 class="open:flex flex-col transition ease-out duration-300 motion-reduce:duration-0 p-0" 3502 x-data="initAuthentication" 3503 x-bind="eventListeners" 3504 x-show="open" 3505 x-htmldialog="close" 3506 closeby="any" 3507 x-transition 3508> 3509 <div class="pt-8 px-8"> 3510 <div class="flex gap-2 justify-between items-center"> 3511 <p id="authentication-popup-title" class="text-xl"> 3512 <strong>Identificador de cliente</strong> 3513 </p> 3514 <button 3515 type="button" 3516 class="btn bg-transparent border-transparent p-2" 3517 @click="close" 3518 aria-label="Cerrar panel" 3519 > 3520 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg> 3521 </button> 3522 </div> 3523 3524 <div class="message error" x-show="errors" x-cloak> 3525 <template x-for="(message, index) in errorMessages" :key="index"> 3526 <div> 3527 <template x-if="message"> 3528 <span x-html="message"></span> 3529 </template> 3530 </div> 3531 </template> 3532 </div> 3533 </div> 3534 3535 <div class="block-customer-login p-8"> 3536 <p id="authenticate-customer-login" class="text-lg mb-2"> 3537 <strong>Checkout using your account</strong> 3538 </p> 3539 3540 <form 3541 id="login-form" 3542 class="form form-login" 3543 method="post" 3544 @submit.prevent="submitForm" 3545 > 3546 <div class="control"> 3547 <input type="hidden" 3548 value="" 3549 name="g-recaptcha-response" 3550 > 3551</div> 3552 <input name="context" type="hidden" value="checkout"> 3553 3554 <div class="flex flex-col gap-4"> 3555 <div class="field email required"> 3556 <label for="form-login-username"> 3557 <span>Correo Electrónico</span> 3558 </label> 3559 <div class="control"> 3560 <input 3561 id="form-login-username" 3562 name="username" 3563 type="email" 3564 class="form-input w-full" 3565 required 3566 autocomplete="off" 3567 x-ref="customer-email" 3568 @change="resetErrors" 3569 > 3570 </div> 3571 </div> 3572 <div class="field password required"> 3573 <label for="form-login-password"> 3574 <span>Contraseña</span> 3575 </label> 3576 <div class="control"> 3577 <input 3578 id="form-login-password" 3579 name="password" 3580 type="password" 3581 class="form-input w-full" 3582 required 3583 autocomplete="off" 3584 x-ref="customer-password" 3585 @change="resetErrors" 3586 > 3587 </div> 3588 </div> 3589 </div> 3590 3591 <div class="actions-toolbar"> 3592 <button 3593 type="submit" 3594 class="btn btn-primary" 3595 > 3596 Iniciar Sesión </button> 3597 <a 3598 href="https://www.mueblesbonitos.com/customer/account/forgotpassword/" 3599 class="underline hover:no-underline" 3600 > 3601 ¿Olvidó su Contraseña? </a> 3602 </div> 3603 </form> 3604 <p class="prose my-4 text-sm"> 3605 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 3606</p> 3607 </div> 3608 <div class="block-new-customer p-8 border-t border-gray-300">
3609 <p id="authenticate-new-customer" class="text-lg mb-2"> 3610 <strong>Checkout as a new customer</strong> 3611 </p> 3612 3613 <div class="block-content"> 3614 <p class="mb-1"> 3615 Creating an account has many benefits: </p> 3616 <ul class="list-disc pl-5"> 3617 <li> See order and shipping status</li> 3618 <li> Track order history</li> 3619 <li> Check out faster</li> 3620 </ul> 3621 <div class="actions-toolbar mt-6 mb-2"> 3622 <a href="https://www.mueblesbonitos.com/customer/account/create/" 3623 class="inline-flex btn btn-primary"> 3624 Crear una Cuenta </a> 3625 </div> 3626 </div> 3627 </div> 3628</dialog> 3629<!-- /BLOCK authentication-popup --></div> 3630
3631<script> 3632 document.addEventListener('alpine:init', () => { 3633 window.initMenuDesktop = function() { 3634 return { 3635 maxLevel: parseInt(this.$el?.dataset?.maxLevel ?? '4', 10), 3636 setActiveMenu() { 3637 try { 3638 this.$el.querySelectorAll('[data-level]').forEach(() => {}); 3639 } catch (e) { 3640 console.warn('[menu] setActiveMenu skipped:', e); 3641 } 3642 } 3643 } 3644 } 3645 }); 3646</script>
3646 3647</header><div class="top-container"><nav class="breadcrumbs bg-container-lighter shadow-sm" aria-label="Breadcrumb"> 3648 <div class="container"> 3649 <ol class="items list-reset py-4 rounded flex flex-wrap text-grey text-sm"> 3650 <li class="item flex home"> 3651 <a 3652 href="https://www.mueblesbonitos.com/" 3653 aria-label="Ir a la página de inicio" 3654 >Inicio</a> 3655 </li> 3656 <li class="item flex category37"> 3657 <span aria-hidden="true" class="separator text-primary-lighter px-2">/</span> 3658 <span 3659 class="text-primary-lighter" 3660 aria-current="page" 3661 >Salones Modernos</span> 3662 </li> 3663 </ol> 3664 </div> 3665</nav> 3666
3667<script type="application/ld+json"> 3668{ 3669 "@context": "https://schema.org", 3670 "@type": "BreadcrumbList", 3671 "itemListElement": [ 3672 { 3673 "@type": "ListItem", 3674 "position": 1, 3675 "name": "Inicio", 3676 "item": "https://www.mueblesbonitos.com/" 3677 }, 3678 { 3679 "@type": "ListItem", 3680 "position": 2, 3681 "name": "Salones Modernos" 3682 } 3683 ] 3684}</script>
3684 3685 3686</div><main id="maincontent" class="page-main"><div id="contentarea" tabindex="-1"></div> 3687<div class="page messages">
3687<script> 3688 function initMessages() { 3689 "use strict"; 3690 return { 3691 messages: window.mageMessages || [], 3692 isEmpty() { 3693 return this.messages.reduce( 3694 function (isEmpty, message) { 3695 return isEmpty && message === undefined 3696 }, true 3697 ) 3698 }, 3699 hasMessages() { 3700 return !this.isEmpty(); 3701 }, 3702 hasMessage() { 3703 return !!this.message; 3704 }, 3705 removeMessage() { 3706 this.messages[this.index] = undefined; 3707 }, 3708 addMessages(messages, hideAfter) { 3709 messages.map((message) => { 3710 this.messages = this.messages.concat(message); 3711 if (hideAfter === undefined && message.type === 'success' && window.defaultSuccessMessageTimeout) { 3712 hideAfter = window.defaultSuccessMessageTimeout; 3713 } 3714 if (hideAfter) { 3715 this.setHideTimeOut(this.messages.length -1, hideAfter); 3716 } 3717 }); 3718 }, 3719 setHideTimeOut(messageIndex, hideAfter) { 3720 setTimeout((messageIndex) => { 3721 this.messages[messageIndex] = undefined; 3722 }, hideAfter, messageIndex); 3723 }, 3724 eventListeners: { 3725 ['@messages-loaded.window'](event) { 3726 this.addMessages(event.detail.messages, event.detail.hideAfter) 3727 }, 3728 ['@private-content-loaded.window'](event) { 3729 const data = event.detail.data; 3730 if ( 3731 data.messages && 3732 data.messages.messages && 3733 data.messages.messages.length 3734 ) { 3735 this.addMessages(data.messages.messages); 3736 } 3737 }, 3738 ['@clear-messages.window']() { 3739 this.messages = []; 3740 } 3741 }, 3742 getMessageUiId() { 3743 return 'message-' + this.message.type; 3744 } 3745 } 3746 } 3747 3748 window.addEventListener('alpine:init', () => Alpine.data('initMessages', initMessages), {once: true}) 3749</script>
3749 3750<section id="messages" 3751 x-data="initMessages" 3752 x-bind="eventListeners" 3753 aria-live="assertive" 3754 role="alert" 3755> 3756 <template x-if="hasMessages"> 3757 <div class="w-full"> 3758 <div class="messages container mx-auto py-3"> 3759 <template x-for="(message, index) in messages" :key="index"> 3760 <div> 3761 <template x-if="hasMessage"> 3762 <div class="message" 3763 :class="message.type" 3764 :ui-id="getMessageUiId" 3765 > 3766 <span x-html="message.text"></span> 3767 <button 3768 type="button" 3769 class="text-gray-600 hover:text-black" 3770 aria-label="Cerrar mensaje" 3771 @click.prevent="removeMessage" 3772 > 3773 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="stroke-current" width="18" height="18" aria-hidden="true"> 3774 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 3775</svg> 3776 </button> 3777 </div> 3778 </template> 3779 </div> 3780 </template> 3781 </div> 3782 </div> 3783 </template> 3784</section> 3785</div><div class="columns"><div class="column main"><div> 3786 <div class="category-buttons my-2 flex gap-2 overflow-x-auto snap-x snap-mandatory pb-2"> 3787 <a href="https://www.mueblesbonitos.com/salon/mueble-tv" 3788 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3789 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3790 snap-start shrink-0"> 3791 Mueble TV </a> 3792 <a href="https://www.mueblesbonitos.com/salon/aparadores" 3793 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3794 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3795 snap-start shrink-0"> 3796 Aparador </a> 3797 <a href="https://www.mueblesbonitos.com/salon/mesas-de-centro" 3798 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3799 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3800 snap-start shrink-0"> 3801 Mesas de Centro </a> 3802 <a href="https://www.mueblesbonitos.com/salon/mesas-y-sillas-de-comedor" 3803 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3804 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3805 snap-start shrink-0"> 3806 Mesas de Comedor </a> 3807 <a href="https://www.mueblesbonitos.com/salon/estanterias" 3808 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3809 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3810 snap-start shrink-0"> 3811 EstanterÃas de Diseño </a> 3812 <a href="https://www.mueblesbonitos.com/salon/vitrinas" 3813 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3814 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3815 snap-start shrink-0"> 3816 Vitrinas </a> 3817 <a href="https://www.mueblesbonitos.com/salon/armario" 3818 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3819 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3820 snap-start shrink-0"> 3821 Armarios de Salón </a> 3822 <a href="https://www.mueblesbonitos.com/salon/conjuntos-de-salon" 3823 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3824 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3825 snap-start shrink-0"> 3826 Conjuntos de Salón </a> 3827 <a href="https://www.mueblesbonitos.com/salon/muebles-con-chimenea" 3828 class="inline-flex items-center px-4 py-1 border rounded-full text-sm font-medium 3829 text-gray-700 bg-gray-200 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 3830 snap-start shrink-0"> 3831 Muebles con Chimenea </a> 3832 </div> 3833</div> 3834 3835 3836 <div id="amasty-shopby-product-list"> 3837 3838 <style> 3839 .products-grid .price-container, 3840 .products-list .price-container { 3841 display: none; 3842 } 3843 </style> 3844 3845 <div class="container flex flex-col items-start text-left mb-6 mt-4"> 3846 <h1 class="text-xl font-bold uppercase"> 3847 Salones modernos </h1> 3848 <div style="display: none"> 3849 <h2>Descubre nuestro catálogo de Salones Modernos</h2> 3850 </div> 3851 3852 3853 </div> 3854 3855 3856 <div class="container"> 3857 </div> 3858 3859 <section class="" id="product-list" aria-label="Lista de productos" tabindex="-1"> 3860 <div class="products wrapper mode-grid products-grid"> 3861 <ul role="list" class="mx-auto pt-4 pb-12 grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-4"> 3862 <li class="flex flex-col"> 3863 3864<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 3865 3866 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-140-cm-ani" class="flex flex-col grow w-full"> 3867 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 3868 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-ani-140cm-branca-e-sonoma_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-ani-140cm-branca-e-sonoma_1.jpg" width="360" height="360" alt="mesa-alta-ani-140cm-branca-e-sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-6916.window="updateImage" loading="lazy"></picture> 3869 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 3870 </div> 3871 3872 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 3873 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 3874 <strong>Ani</strong> 3875 </div> 3876 3877 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
3878 <span class="product-item-link">Mesa alta Blanco y Sonoma 140 cm Ani</span> 3879 </div> 3880 3881 3882 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-6916.window="updatePrice($event.detail);"> 3883 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="6916" data-price-box="product-id-6916"> 3884 <span 3885 x-data x-id="['product\u002Dprice\u002D6916']" class="price-container price-final_price tax weee" 3886 > 3887 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 3888 <span class="price"><span class="price">89,00 â¬</span></span> 3889 </span> 3890 3891 <span class="old-price mr-1"> 3892 <span class="price line-through text-gray-600"> 3893 <span class="price"><span class="price">95,00 â¬</span></span> 3894 3895 </span> 3896 </span> 3897 3898 3899 3900 </span> 3901</div></div> 3902 </div> 3903 </div> 3904 </a> 3905 3906 3907 <!-- <div>CATEGORIA: </div> --> 3908 <div class="product-item-variations px-4 py-2 mt-auto"> 3909 <div id="variaciones-listado-6916"> 3910 <div class="color-picker-grid-mode-clean"> 3911 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 3912 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 3913 Colores Disponibles: 3914 </span> 3915 3916 <div class="flex flex-wrap gap-4 items-center"> 3917 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-140-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-140-cm-ani"></div> </div> 3918 </div> 3919 </div> </div> 3920 </div> 3921 <div class="px-4 pb-4"> 3922 3923<div class="mt-1 flex flex-col"> 3924 <!-- Invitado: base price + lÃnea VIP (si existe) --> 3925 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 3926 95,00 ⬠</span> 3927 3928 <div class="flex items-baseline gap-1.5"> 3929 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 3930 89,00 ⬠</span> 3931 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 3932 Precio VIP </span> 3933 </div> 3934 3935 3936 </div> </div> 3937</div> 3938 3939<style> 3940 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 3941 .color-picker-grid-mode-clean, 3942 .color-picker-grid-mode-clean>div { 3943 display: flex !important; 3944 flex-direction: row !important; 3945 flex-wrap: wrap !important; 3946 align-items: center !important; 3947 gap: 6px !important; 3948 padding: 0 !important; 3949 margin: 0 !important; 3950 border: none !important; 3951 } 3952 3953 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 3954 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 3955 .color-picker-grid-mode-clean span.text-sm.font-bold, 3956 .color-picker-grid-mode-clean .w-32 { 3957 display: none !important; 3958 } 3959 3960 /* 3. Ajuste de las "bolitas" de color */ 3961 .color-picker-grid-mode-clean .w-9.h-9 { 3962 width: 22px !important; 3963 /* Tamaño reducido ideal para rejilla */ 3964 height: 22px !important; 3965 min-width: 22px !important; 3966 min-height: 22px !important; 3967 margin: 0 !important; 3968 transform: none !important; 3969 /* Evitamos que el seleccionado crezca y descuadre */ 3970 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 3971 } 3972 3973 /* 4. Ajuste del icono Check (V) de selección */ 3974 .color-picker-grid-mode-clean svg { 3975 width: 14px !important; 3976 height: 14px !important; 3977 } 3978 3979 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 3980 .product-item-variations { 3981 margin-top: 4px !important; 3982 margin-bottom: 4px !important; 3983 padding-top: 0 !important; 3984 padding-bottom: 0 !important; 3985 } 3986 3987 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 3988 .color-picker-grid-mode-clean .flex-wrap { 3989 gap: 6px !important; 3990 } 3991 3992 .product-item-photo>span picture, 3993 .product-item-photo>span img { 3994 width: 100% !important; 3995 height: auto !important; 3996 display: block !important; 3997 } 3998 3999 .product-item-photo>span picture { 4000 position: static !important; 4001 } 4002</style> </li> 4003 <li class="flex flex-col"> 4004 4005<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4006 4007 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-kyra-110cm-color-blanco-y-sonoma" class="flex flex-col grow w-full"> 4008 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4009 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-cor-branca-e-sonoma.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-cor-branca-e-sonoma.jpg" width="360" height="360" alt="mesa-alta-kyra-110cm-cor-branca-e-sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-6917.window="updateImage" loading="lazy"></picture> 4010 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4011 </div> 4012 4013 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4014 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4015 <strong>Kyra</strong> 4016 </div> 4017 4018 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4019 <span class="product-item-link">Mesa alta Kyra (110cm) color blanco y sonoma</span> 4020 </div> 4021 4022 4023 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-6917.window="updatePrice($event.detail);"> 4024 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="6917" data-price-box="product-id-6917"> 4025 <span 4026 x-data x-id="['product\u002Dprice\u002D6917']" class="price-container price-final_price tax weee" 4027 > 4028 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4029 <span class="price"><span class="price">79,00 â¬</span></span> 4030 </span> 4031 4032 <span class="old-price mr-1"> 4033 <span class="price line-through text-gray-600"> 4034 <span class="price"><span class="price">89,00 â¬</span></span> 4035 4036 </span> 4037 </span> 4038 4039 4040 4041 </span> 4042</div></div> 4043 </div> 4044 </div> 4045 </a> 4046 4047 4048 <!-- <div>CATEGORIA: </div> --> 4049 <div class="product-item-variations px-4 py-2 mt-auto"> 4050 <div id="variaciones-listado-6917"> 4051 <div class="color-picker-grid-mode-clean"> 4052 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4053 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4054 Colores Disponibles: 4055 </span> 4056 4057 <div class="flex flex-wrap gap-4 items-center"> 4058 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-110-cm-kyra" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-110-cm-kyra"></div> </div> 4059 </div> 4060 </div> </div> 4061 </div> 4062 <div class="px-4 pb-4"> 4063 4064<div class="mt-1 flex flex-col"> 4065 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4066 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4067 89,00 ⬠</span> 4068 4069 <div class="flex items-baseline gap-1.5"> 4070 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4071 79,00 ⬠</span> 4072 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4073 Precio VIP </span> 4074 </div> 4075 4076 4077 </div> </div> 4078</div> 4079 4080<style> 4081 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4082 .color-picker-grid-mode-clean, 4083 .color-picker-grid-mode-clean>div { 4084 display: flex !important; 4085 flex-direction: row !important; 4086 flex-wrap: wrap !important; 4087 align-items: center !important; 4088 gap: 6px !important; 4089 padding: 0 !important; 4090 margin: 0 !important; 4091 border: none !important; 4092 } 4093 4094 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4095 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4096 .color-picker-grid-mode-clean span.text-sm.font-bold, 4097 .color-picker-grid-mode-clean .w-32 { 4098 display: none !important; 4099 } 4100 4101 /* 3. Ajuste de las "bolitas" de color */ 4102 .color-picker-grid-mode-clean .w-9.h-9 { 4103 width: 22px !important; 4104 /* Tamaño reducido ideal para rejilla */ 4105 height: 22px !important; 4106 min-width: 22px !important; 4107 min-height: 22px !important; 4108 margin: 0 !important; 4109 transform: none !important; 4110 /* Evitamos que el seleccionado crezca y descuadre */ 4111 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4112 } 4113 4114 /* 4. Ajuste del icono Check (V) de selección */ 4115 .color-picker-grid-mode-clean svg { 4116 width: 14px !important; 4117 height: 14px !important; 4118 } 4119 4120 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4121 .product-item-variations { 4122 margin-top: 4px !important; 4123 margin-bottom: 4px !important; 4124 padding-top: 0 !important; 4125 padding-bottom: 0 !important; 4126 } 4127 4128 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4129 .color-picker-grid-mode-clean .flex-wrap { 4130 gap: 6px !important; 4131 } 4132 4133 .product-item-photo>span picture, 4134 .product-item-photo>span img { 4135 width: 100% !important; 4136 height: auto !important; 4137 display: block !important; 4138 } 4139 4140 .product-item-photo>span picture { 4141 position: static !important; 4142 } 4143</style> </li> 4144 <li class="flex flex-col"> 4145 4146<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4147 4148 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-kyra-110cm-color-blanco" class="flex flex-col grow w-full"> 4149 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4150 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-branca.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-branca.jpg" width="360" height="360" alt="mesa-alta-kyra-110cm-branca" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-6918.window="updateImage" loading="lazy"></picture> 4151 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4152 </div> 4153 4154 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4155 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4156 <strong>Kyra</strong> 4157 </div> 4158 4159 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4160 <span class="product-item-link">Mesa alta Kyra (110cm) color blanco</span> 4161 </div> 4162 4163 4164 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-6918.window="updatePrice($event.detail);"> 4165 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="6918" data-price-box="product-id-6918"> 4166 <span 4167 x-data x-id="['product\u002Dprice\u002D6918']" class="price-container price-final_price tax weee" 4168 > 4169 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4170 <span class="price"><span class="price">79,00 â¬</span></span> 4171 </span> 4172 4173 <span class="old-price mr-1"> 4174 <span class="price line-through text-gray-600"> 4175 <span class="price"><span class="price">89,00 â¬</span></span> 4176 4177 </span> 4178 </span> 4179 4180 4181 4182 </span> 4183</div></div> 4184 </div> 4185 </div> 4186 </a> 4187 4188 4189 <!-- <div>CATEGORIA: </div> --> 4190 <div class="product-item-variations px-4 py-2 mt-auto"> 4191 <div id="variaciones-listado-6918"> 4192 <div class="color-picker-grid-mode-clean"> 4193 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4194 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4195 Colores Disponibles: 4196 </span> 4197 4198 <div class="flex flex-wrap gap-4 items-center"> 4199 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco-y-sonoma" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco-y-sonoma"></div><div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-110-cm-kyra" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-110-cm-kyra"></div> </div> 4200 </div> 4201 </div> </div> 4202 </div> 4203 <div class="px-4 pb-4"> 4204 4205<div class="mt-1 flex flex-col"> 4206 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4207 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4208 89,00 ⬠</span> 4209 4210 <div class="flex items-baseline gap-1.5"> 4211 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4212 79,00 ⬠</span> 4213 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4214 Precio VIP </span> 4215 </div> 4216 4217 4218 </div> </div> 4219</div> 4220 4221<style> 4222 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4223 .color-picker-grid-mode-clean, 4224 .color-picker-grid-mode-clean>div { 4225 display: flex !important; 4226 flex-direction: row !important; 4227 flex-wrap: wrap !important; 4228 align-items: center !important; 4229 gap: 6px !important; 4230 padding: 0 !important; 4231 margin: 0 !important; 4232 border: none !important; 4233 } 4234 4235 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4236 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4237 .color-picker-grid-mode-clean span.text-sm.font-bold, 4238 .color-picker-grid-mode-clean .w-32 { 4239 display: none !important; 4240 } 4241 4242 /* 3. Ajuste de las "bolitas" de color */ 4243 .color-picker-grid-mode-clean .w-9.h-9 { 4244 width: 22px !important; 4245 /* Tamaño reducido ideal para rejilla */ 4246 height: 22px !important; 4247 min-width: 22px !important; 4248 min-height: 22px !important; 4249 margin: 0 !important; 4250 transform: none !important; 4251 /* Evitamos que el seleccionado crezca y descuadre */ 4252 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4253 } 4254 4255 /* 4. Ajuste del icono Check (V) de selección */ 4256 .color-picker-grid-mode-clean svg { 4257 width: 14px !important; 4258 height: 14px !important; 4259 } 4260 4261 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4262 .product-item-variations { 4263 margin-top: 4px !important; 4264 margin-bottom: 4px !important; 4265 padding-top: 0 !important; 4266 padding-bottom: 0 !important; 4267 } 4268 4269 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4270 .color-picker-grid-mode-clean .flex-wrap { 4271 gap: 6px !important; 4272 } 4273 4274 .product-item-photo>span picture, 4275 .product-item-photo>span img { 4276 width: 100% !important; 4277 height: auto !important; 4278 display: block !important; 4279 } 4280 4281 .product-item-photo>span picture { 4282 position: static !important; 4283 } 4284</style> </li> 4285 <li class="flex flex-col"> 4286 4287<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4288 4289 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-110-cm-kyra" class="flex flex-col grow w-full"> 4290 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4291 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-110-cm-kyra-03.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-110-cm-kyra-03.jpg" width="360" height="360" alt="mesa-alta-negro-sonoma-110-cm-kyra" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7140.window="updateImage" loading="lazy"></picture> 4292 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4293 </div> 4294 4295 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4296 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4297 <strong>Kyra</strong> 4298 </div> 4299 4300 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4301 <span class="product-item-link">Mesa alta Negro y Sonoma 110 cm Kyra</span> 4302 </div> 4303 4304 4305 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7140.window="updatePrice($event.detail);"> 4306 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7140" data-price-box="product-id-7140"> 4307 <span 4308 x-data x-id="['product\u002Dprice\u002D7140']" class="price-container price-final_price tax weee" 4309 > 4310 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4311 <span class="price"><span class="price">79,00 â¬</span></span> 4312 </span> 4313 4314 <span class="old-price mr-1"> 4315 <span class="price line-through text-gray-600"> 4316 <span class="price"><span class="price">89,00 â¬</span></span> 4317 4318 </span> 4319 </span> 4320 4321 4322 4323 </span> 4324</div></div> 4325 </div> 4326 </div> 4327 </a> 4328 4329 4330 <!-- <div>CATEGORIA: </div> --> 4331 <div class="product-item-variations px-4 py-2 mt-auto"> 4332 <div id="variaciones-listado-7140"> 4333 <div class="color-picker-grid-mode-clean"> 4334 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4335 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4336 Colores Disponibles: 4337 </span> 4338 4339 <div class="flex flex-wrap gap-4 items-center"> 4340 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco-y-sonoma" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco-y-sonoma"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-kyra-110cm-color-blanco"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 4341 </div> 4342 </div> </div> 4343 </div> 4344 <div class="px-4 pb-4"> 4345 4346<div class="mt-1 flex flex-col"> 4347 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4348 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4349 89,00 ⬠</span> 4350 4351 <div class="flex items-baseline gap-1.5"> 4352 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4353 79,00 ⬠</span> 4354 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4355 Precio VIP </span> 4356 </div> 4357 4358 4359 </div> </div> 4360</div> 4361 4362<style> 4363 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4364 .color-picker-grid-mode-clean, 4365 .color-picker-grid-mode-clean>div { 4366 display: flex !important; 4367 flex-direction: row !important; 4368 flex-wrap: wrap !important; 4369 align-items: center !important; 4370 gap: 6px !important; 4371 padding: 0 !important; 4372 margin: 0 !important; 4373 border: none !important; 4374 } 4375 4376 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4377 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4378 .color-picker-grid-mode-clean span.text-sm.font-bold, 4379 .color-picker-grid-mode-clean .w-32 { 4380 display: none !important; 4381 } 4382 4383 /* 3. Ajuste de las "bolitas" de color */ 4384 .color-picker-grid-mode-clean .w-9.h-9 { 4385 width: 22px !important; 4386 /* Tamaño reducido ideal para rejilla */ 4387 height: 22px !important; 4388 min-width: 22px !important; 4389 min-height: 22px !important; 4390 margin: 0 !important; 4391 transform: none !important; 4392 /* Evitamos que el seleccionado crezca y descuadre */ 4393 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4394 } 4395 4396 /* 4. Ajuste del icono Check (V) de selección */ 4397 .color-picker-grid-mode-clean svg { 4398 width: 14px !important; 4399 height: 14px !important; 4400 } 4401 4402 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4403 .product-item-variations { 4404 margin-top: 4px !important; 4405 margin-bottom: 4px !important; 4406 padding-top: 0 !important; 4407 padding-bottom: 0 !important; 4408 } 4409 4410 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4411 .color-picker-grid-mode-clean .flex-wrap { 4412 gap: 6px !important; 4413 } 4414 4415 .product-item-photo>span picture, 4416 .product-item-photo>span img { 4417 width: 100% !important; 4418 height: auto !important; 4419 display: block !important; 4420 } 4421 4422 .product-item-photo>span picture { 4423 position: static !important; 4424 } 4425</style> </li> 4426 <li class="flex flex-col"> 4427 4428<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4429 4430 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-140-cm-ani" class="flex flex-col grow w-full"> 4431 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4432 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-preto-sonoma-140-cm-ani_2.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-preto-sonoma-140-cm-ani_2.jpg" width="360" height="360" alt="mesa-alta-preto-sonoma-140-cm-ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7141.window="updateImage" loading="lazy"></picture> 4433 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4434 </div> 4435 4436 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4437 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4438 <strong>Ani</strong> 4439 </div> 4440 4441 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4442 <span class="product-item-link">Mesa alta Negro y Sonoma 140 cm Ani</span> 4443 </div> 4444 4445 4446 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7141.window="updatePrice($event.detail);"> 4447 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7141" data-price-box="product-id-7141"> 4448 <span 4449 x-data x-id="['product\u002Dprice\u002D7141']" class="price-container price-final_price tax weee" 4450 > 4451 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4452 <span class="price"><span class="price">89,00 â¬</span></span> 4453 </span> 4454 4455 <span class="old-price mr-1"> 4456 <span class="price line-through text-gray-600"> 4457 <span class="price"><span class="price">95,00 â¬</span></span> 4458 4459 </span> 4460 </span> 4461 4462 4463 4464 </span> 4465</div></div> 4466 </div> 4467 </div> 4468 </a> 4469 4470 4471 <!-- <div>CATEGORIA: </div> --> 4472 <div class="product-item-variations px-4 py-2 mt-auto"> 4473 <div id="variaciones-listado-7141"> 4474 <div class="color-picker-grid-mode-clean"> 4475 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4476 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4477 Colores Disponibles: 4478 </span> 4479 4480 <div class="flex flex-wrap gap-4 items-center"> 4481 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-140-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-140-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 4482 </div> 4483 </div> </div> 4484 </div> 4485 <div class="px-4 pb-4"> 4486 4487<div class="mt-1 flex flex-col"> 4488 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4489 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4490 95,00 ⬠</span> 4491 4492 <div class="flex items-baseline gap-1.5"> 4493 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4494 89,00 ⬠</span> 4495 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4496 Precio VIP </span> 4497 </div> 4498 4499 4500 </div> </div> 4501</div> 4502 4503<style> 4504 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4505 .color-picker-grid-mode-clean, 4506 .color-picker-grid-mode-clean>div { 4507 display: flex !important; 4508 flex-direction: row !important; 4509 flex-wrap: wrap !important; 4510 align-items: center !important; 4511 gap: 6px !important; 4512 padding: 0 !important; 4513 margin: 0 !important; 4514 border: none !important; 4515 } 4516 4517 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4518 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4519 .color-picker-grid-mode-clean span.text-sm.font-bold, 4520 .color-picker-grid-mode-clean .w-32 { 4521 display: none !important; 4522 } 4523 4524 /* 3. Ajuste de las "bolitas" de color */ 4525 .color-picker-grid-mode-clean .w-9.h-9 { 4526 width: 22px !important; 4527 /* Tamaño reducido ideal para rejilla */ 4528 height: 22px !important; 4529 min-width: 22px !important; 4530 min-height: 22px !important; 4531 margin: 0 !important; 4532 transform: none !important; 4533 /* Evitamos que el seleccionado crezca y descuadre */ 4534 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4535 } 4536 4537 /* 4. Ajuste del icono Check (V) de selección */ 4538 .color-picker-grid-mode-clean svg { 4539 width: 14px !important; 4540 height: 14px !important; 4541 } 4542 4543 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4544 .product-item-variations { 4545 margin-top: 4px !important; 4546 margin-bottom: 4px !important; 4547 padding-top: 0 !important; 4548 padding-bottom: 0 !important; 4549 } 4550 4551 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4552 .color-picker-grid-mode-clean .flex-wrap { 4553 gap: 6px !important; 4554 } 4555 4556 .product-item-photo>span picture, 4557 .product-item-photo>span img { 4558 width: 100% !important; 4559 height: auto !important; 4560 display: block !important; 4561 } 4562 4563 .product-item-photo>span picture { 4564 position: static !important; 4565 } 4566</style> </li> 4567 <li class="flex flex-col"> 4568 4569<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4570 4571 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-120-cm-ani" class="flex flex-col grow w-full"> 4572 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4573 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_4.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_4.jpg" width="360" height="360" alt="Mesa alta Blanco y Sonoma 120 cm Ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7142.window="updateImage" loading="lazy"></picture> 4574 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4575 </div> 4576 4577 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4578 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4579 <strong>Ani</strong> 4580 </div> 4581 4582 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4583 <span class="product-item-link">Mesa alta Blanco y Sonoma 120 cm Ani</span> 4584 </div> 4585 4586 4587 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7142.window="updatePrice($event.detail);"> 4588 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7142" data-price-box="product-id-7142"> 4589 <span 4590 x-data x-id="['product\u002Dprice\u002D7142']" class="price-container price-final_price tax weee" 4591 > 4592 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4593 <span class="price"><span class="price">79,00 â¬</span></span> 4594 </span> 4595 4596 <span class="old-price mr-1"> 4597 <span class="price line-through text-gray-600"> 4598 <span class="price"><span class="price">89,00 â¬</span></span> 4599 4600 </span> 4601 </span> 4602 4603 4604 4605 </span> 4606</div></div> 4607 </div> 4608 </div> 4609 </a> 4610 4611 4612 <!-- <div>CATEGORIA: </div> --> 4613 <div class="product-item-variations px-4 py-2 mt-auto"> 4614 <div id="variaciones-listado-7142"> 4615 <div class="color-picker-grid-mode-clean"> 4616 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4617 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4618 Colores Disponibles: 4619 </span> 4620 4621 <div class="flex flex-wrap gap-4 items-center"> 4622 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-120-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-120-cm-ani"></div> </div> 4623 </div> 4624 </div> </div> 4625 </div> 4626 <div class="px-4 pb-4"> 4627 4628<div class="mt-1 flex flex-col"> 4629 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4630 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4631 89,00 ⬠</span> 4632 4633 <div class="flex items-baseline gap-1.5"> 4634 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4635 79,00 ⬠</span> 4636 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4637 Precio VIP </span> 4638 </div> 4639 4640 4641 </div> </div> 4642</div> 4643 4644<style> 4645 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4646 .color-picker-grid-mode-clean, 4647 .color-picker-grid-mode-clean>div { 4648 display: flex !important; 4649 flex-direction: row !important; 4650 flex-wrap: wrap !important; 4651 align-items: center !important; 4652 gap: 6px !important; 4653 padding: 0 !important; 4654 margin: 0 !important; 4655 border: none !important; 4656 } 4657 4658 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4659 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4660 .color-picker-grid-mode-clean span.text-sm.font-bold, 4661 .color-picker-grid-mode-clean .w-32 { 4662 display: none !important; 4663 } 4664 4665 /* 3. Ajuste de las "bolitas" de color */ 4666 .color-picker-grid-mode-clean .w-9.h-9 { 4667 width: 22px !important; 4668 /* Tamaño reducido ideal para rejilla */ 4669 height: 22px !important; 4670 min-width: 22px !important; 4671 min-height: 22px !important; 4672 margin: 0 !important; 4673 transform: none !important; 4674 /* Evitamos que el seleccionado crezca y descuadre */ 4675 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4676 } 4677 4678 /* 4. Ajuste del icono Check (V) de selección */ 4679 .color-picker-grid-mode-clean svg { 4680 width: 14px !important; 4681 height: 14px !important; 4682 } 4683 4684 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4685 .product-item-variations { 4686 margin-top: 4px !important; 4687 margin-bottom: 4px !important; 4688 padding-top: 0 !important; 4689 padding-bottom: 0 !important; 4690 } 4691 4692 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4693 .color-picker-grid-mode-clean .flex-wrap { 4694 gap: 6px !important; 4695 } 4696 4697 .product-item-photo>span picture, 4698 .product-item-photo>span img { 4699 width: 100% !important; 4700 height: auto !important; 4701 display: block !important; 4702 } 4703 4704 .product-item-photo>span picture { 4705 position: static !important; 4706 } 4707</style> </li> 4708 <li class="flex flex-col"> 4709 4710<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4711 4712 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-120-cm-ani" class="flex flex-col grow w-full"> 4713 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4714 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-120-cm-ani-01_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-120-cm-ani-01_1.jpg" width="360" height="360" alt="Mesa alta Negro y Sonoma 120 cm Ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7143.window="updateImage" loading="lazy"></picture> 4715 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4716 </div> 4717 4718 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4719 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4720 <strong>Ani</strong> 4721 </div> 4722 4723 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4724 <span class="product-item-link">Mesa alta Negro y Sonoma 120 cm Ani</span> 4725 </div> 4726 4727 4728 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7143.window="updatePrice($event.detail);"> 4729 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7143" data-price-box="product-id-7143"> 4730 <span 4731 x-data x-id="['product\u002Dprice\u002D7143']" class="price-container price-final_price tax weee" 4732 > 4733 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4734 <span class="price"><span class="price">79,00 â¬</span></span> 4735 </span> 4736 4737 <span class="old-price mr-1"> 4738 <span class="price line-through text-gray-600"> 4739 <span class="price"><span class="price">89,00 â¬</span></span> 4740 4741 </span> 4742 </span> 4743 4744 4745 4746 </span> 4747</div></div> 4748 </div> 4749 </div> 4750 </a> 4751 4752 4753 <!-- <div>CATEGORIA: </div> --> 4754 <div class="product-item-variations px-4 py-2 mt-auto"> 4755 <div id="variaciones-listado-7143"> 4756 <div class="color-picker-grid-mode-clean"> 4757 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4758 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4759 Colores Disponibles: 4760 </span> 4761 4762 <div class="flex flex-wrap gap-4 items-center"> 4763 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-120-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-120-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 4764 </div> 4765 </div> </div> 4766 </div> 4767 <div class="px-4 pb-4"> 4768 4769<div class="mt-1 flex flex-col"> 4770 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4771 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4772 89,00 ⬠</span> 4773 4774 <div class="flex items-baseline gap-1.5"> 4775 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4776 79,00 ⬠</span> 4777 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4778 Precio VIP </span> 4779 </div> 4780 4781 4782 </div> </div> 4783</div> 4784 4785<style> 4786 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4787 .color-picker-grid-mode-clean, 4788 .color-picker-grid-mode-clean>div { 4789 display: flex !important; 4790 flex-direction: row !important; 4791 flex-wrap: wrap !important; 4792 align-items: center !important; 4793 gap: 6px !important; 4794 padding: 0 !important; 4795 margin: 0 !important; 4796 border: none !important; 4797 } 4798 4799 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4800 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4801 .color-picker-grid-mode-clean span.text-sm.font-bold, 4802 .color-picker-grid-mode-clean .w-32 { 4803 display: none !important; 4804 } 4805 4806 /* 3. Ajuste de las "bolitas" de color */ 4807 .color-picker-grid-mode-clean .w-9.h-9 { 4808 width: 22px !important; 4809 /* Tamaño reducido ideal para rejilla */ 4810 height: 22px !important; 4811 min-width: 22px !important; 4812 min-height: 22px !important; 4813 margin: 0 !important; 4814 transform: none !important; 4815 /* Evitamos que el seleccionado crezca y descuadre */ 4816 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4817 } 4818 4819 /* 4. Ajuste del icono Check (V) de selección */ 4820 .color-picker-grid-mode-clean svg { 4821 width: 14px !important; 4822 height: 14px !important; 4823 } 4824 4825 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4826 .product-item-variations { 4827 margin-top: 4px !important; 4828 margin-bottom: 4px !important; 4829 padding-top: 0 !important; 4830 padding-bottom: 0 !important; 4831 } 4832 4833 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4834 .color-picker-grid-mode-clean .flex-wrap { 4835 gap: 6px !important; 4836 } 4837 4838 .product-item-photo>span picture, 4839 .product-item-photo>span img { 4840 width: 100% !important; 4841 height: auto !important; 4842 display: block !important; 4843 } 4844 4845 .product-item-photo>span picture { 4846 position: static !important; 4847 } 4848</style> </li> 4849 <li class="flex flex-col"> 4850 4851<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4852 4853 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-100-cm-ani" class="flex flex-col grow w-full"> 4854 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4855 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-100-cm-ani-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-100-cm-ani-01.jpg" width="360" height="360" alt="Mesa alta Blanco y Sonoma 100 cm Ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7144.window="updateImage" loading="lazy"></picture> 4856 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4857 </div> 4858 4859 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 4860 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 4861 <strong>Ani</strong> 4862 </div> 4863 4864 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
4865 <span class="product-item-link">Mesa alta Blanco y Sonoma 100 cm Ani</span> 4866 </div> 4867 4868 4869 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7144.window="updatePrice($event.detail);"> 4870 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7144" data-price-box="product-id-7144"> 4871 <span 4872 x-data x-id="['product\u002Dprice\u002D7144']" class="price-container price-final_price tax weee" 4873 > 4874 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 4875 <span class="price"><span class="price">69,00 â¬</span></span> 4876 </span> 4877 4878 <span class="old-price mr-1"> 4879 <span class="price line-through text-gray-600"> 4880 <span class="price"><span class="price">79,00 â¬</span></span> 4881 4882 </span> 4883 </span> 4884 4885 4886 4887 </span> 4888</div></div> 4889 </div> 4890 </div> 4891 </a> 4892 4893 4894 <!-- <div>CATEGORIA: </div> --> 4895 <div class="product-item-variations px-4 py-2 mt-auto"> 4896 <div id="variaciones-listado-7144"> 4897 <div class="color-picker-grid-mode-clean"> 4898 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 4899 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 4900 Colores Disponibles: 4901 </span> 4902 4903 <div class="flex flex-wrap gap-4 items-center"> 4904 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-100-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-negro-y-sonoma-100-cm-ani"></div> </div> 4905 </div> 4906 </div> </div> 4907 </div> 4908 <div class="px-4 pb-4"> 4909 4910<div class="mt-1 flex flex-col"> 4911 <!-- Invitado: base price + lÃnea VIP (si existe) --> 4912 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 4913 79,00 ⬠</span> 4914 4915 <div class="flex items-baseline gap-1.5"> 4916 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 4917 69,00 ⬠</span> 4918 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 4919 Precio VIP </span> 4920 </div> 4921 4922 4923 </div> </div> 4924</div> 4925 4926<style> 4927 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 4928 .color-picker-grid-mode-clean, 4929 .color-picker-grid-mode-clean>div { 4930 display: flex !important; 4931 flex-direction: row !important; 4932 flex-wrap: wrap !important; 4933 align-items: center !important; 4934 gap: 6px !important; 4935 padding: 0 !important; 4936 margin: 0 !important; 4937 border: none !important; 4938 } 4939 4940 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 4941 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 4942 .color-picker-grid-mode-clean span.text-sm.font-bold, 4943 .color-picker-grid-mode-clean .w-32 { 4944 display: none !important; 4945 } 4946 4947 /* 3. Ajuste de las "bolitas" de color */ 4948 .color-picker-grid-mode-clean .w-9.h-9 { 4949 width: 22px !important; 4950 /* Tamaño reducido ideal para rejilla */ 4951 height: 22px !important; 4952 min-width: 22px !important; 4953 min-height: 22px !important; 4954 margin: 0 !important; 4955 transform: none !important; 4956 /* Evitamos que el seleccionado crezca y descuadre */ 4957 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 4958 } 4959 4960 /* 4. Ajuste del icono Check (V) de selección */ 4961 .color-picker-grid-mode-clean svg { 4962 width: 14px !important; 4963 height: 14px !important; 4964 } 4965 4966 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 4967 .product-item-variations { 4968 margin-top: 4px !important; 4969 margin-bottom: 4px !important; 4970 padding-top: 0 !important; 4971 padding-bottom: 0 !important; 4972 } 4973 4974 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 4975 .color-picker-grid-mode-clean .flex-wrap { 4976 gap: 6px !important; 4977 } 4978 4979 .product-item-photo>span picture, 4980 .product-item-photo>span img { 4981 width: 100% !important; 4982 height: auto !important; 4983 display: block !important; 4984 } 4985 4986 .product-item-photo>span picture { 4987 position: static !important; 4988 } 4989</style> </li> 4990 <li class="flex flex-col"> 4991 4992<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 4993 4994 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-100-cm-ani" class="flex flex-col grow w-full"> 4995 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 4996 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-100-cm-ani-01_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-100-cm-ani-01_1.jpg" width="360" height="360" alt="mesa-alta-negro-sonoma-100-cm-ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7145.window="updateImage" loading="lazy"></picture> 4997 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 4998 </div> 4999 5000 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5001 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5002 <strong>Ani</strong> 5003 </div> 5004 5005 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5006 <span class="product-item-link">Mesa alta Negro y Sonoma 100 cm Ani</span> 5007 </div> 5008 5009 5010 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7145.window="updatePrice($event.detail);"> 5011 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7145" data-price-box="product-id-7145"> 5012 <span 5013 x-data x-id="['product\u002Dprice\u002D7145']" class="price-container price-final_price tax weee" 5014 > 5015 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5016 <span class="price"><span class="price">69,00 â¬</span></span> 5017 </span> 5018 5019 <span class="old-price mr-1"> 5020 <span class="price line-through text-gray-600"> 5021 <span class="price"><span class="price">79,00 â¬</span></span> 5022 5023 </span> 5024 </span> 5025 5026 5027 5028 </span> 5029</div></div> 5030 </div> 5031 </div> 5032 </a> 5033 5034 5035 <!-- <div>CATEGORIA: </div> --> 5036 <div class="product-item-variations px-4 py-2 mt-auto"> 5037 <div id="variaciones-listado-7145"> 5038 <div class="color-picker-grid-mode-clean"> 5039 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5040 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5041 Colores Disponibles: 5042 </span> 5043 5044 <div class="flex flex-wrap gap-4 items-center"> 5045 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-100-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-blanco-y-sonoma-100-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 5046 </div> 5047 </div> </div> 5048 </div> 5049 <div class="px-4 pb-4"> 5050 5051<div class="mt-1 flex flex-col"> 5052 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5053 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5054 79,00 ⬠</span> 5055 5056 <div class="flex items-baseline gap-1.5"> 5057 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5058 69,00 ⬠</span> 5059 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5060 Precio VIP </span> 5061 </div> 5062 5063 5064 </div> </div> 5065</div> 5066 5067<style> 5068 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5069 .color-picker-grid-mode-clean, 5070 .color-picker-grid-mode-clean>div { 5071 display: flex !important; 5072 flex-direction: row !important; 5073 flex-wrap: wrap !important; 5074 align-items: center !important; 5075 gap: 6px !important; 5076 padding: 0 !important; 5077 margin: 0 !important; 5078 border: none !important; 5079 } 5080 5081 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5082 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5083 .color-picker-grid-mode-clean span.text-sm.font-bold, 5084 .color-picker-grid-mode-clean .w-32 { 5085 display: none !important; 5086 } 5087 5088 /* 3. Ajuste de las "bolitas" de color */ 5089 .color-picker-grid-mode-clean .w-9.h-9 { 5090 width: 22px !important; 5091 /* Tamaño reducido ideal para rejilla */ 5092 height: 22px !important; 5093 min-width: 22px !important; 5094 min-height: 22px !important; 5095 margin: 0 !important; 5096 transform: none !important; 5097 /* Evitamos que el seleccionado crezca y descuadre */ 5098 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5099 } 5100 5101 /* 4. Ajuste del icono Check (V) de selección */ 5102 .color-picker-grid-mode-clean svg { 5103 width: 14px !important; 5104 height: 14px !important; 5105 } 5106 5107 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5108 .product-item-variations { 5109 margin-top: 4px !important; 5110 margin-bottom: 4px !important; 5111 padding-top: 0 !important; 5112 padding-bottom: 0 !important; 5113 } 5114 5115 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5116 .color-picker-grid-mode-clean .flex-wrap { 5117 gap: 6px !important; 5118 } 5119 5120 .product-item-photo>span picture, 5121 .product-item-photo>span img { 5122 width: 100% !important; 5123 height: auto !important; 5124 display: block !important; 5125 } 5126 5127 .product-item-photo>span picture { 5128 position: static !important; 5129 } 5130</style> </li> 5131 <li class="flex flex-col"> 5132 5133<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5134 5135 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-140-cm-ani" class="flex flex-col grow w-full"> 5136 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5137 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-140-cm-ani-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-140-cm-ani-01.jpg" width="360" height="360" alt="Mesa alta con 2 Taburetes Blanco y Sonoma 140 cm Ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7147.window="updateImage" loading="lazy"></picture> 5138 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5139 </div> 5140 5141 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5142 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5143 <strong>Ani</strong> 5144 </div> 5145 5146 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5147 <span class="product-item-link">Mesa alta con 2 Taburetes Blanco y Sonoma 140 cm Ani</span> 5148 </div> 5149 5150 5151 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7147.window="updatePrice($event.detail);"> 5152 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7147" data-price-box="product-id-7147"> 5153 <span 5154 x-data x-id="['product\u002Dprice\u002D7147']" class="price-container price-final_price tax weee" 5155 > 5156 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5157 <span class="price"><span class="price">125,00 â¬</span></span> 5158 </span> 5159 5160 <span class="old-price mr-1"> 5161 <span class="price line-through text-gray-600"> 5162 <span class="price"><span class="price">139,00 â¬</span></span> 5163 5164 </span> 5165 </span> 5166 5167 5168 5169 </span> 5170</div></div> 5171 </div> 5172 </div> 5173 </a> 5174 5175 5176 <!-- <div>CATEGORIA: </div> --> 5177 <div class="product-item-variations px-4 py-2 mt-auto"> 5178 <div id="variaciones-listado-7147"> 5179 <div class="color-picker-grid-mode-clean"> 5180 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5181 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5182 Colores Disponibles: 5183 </span> 5184 5185 <div class="flex flex-wrap gap-4 items-center"> 5186 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-140-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-140-cm-ani"></div> </div> 5187 </div> 5188 </div> </div> 5189 </div> 5190 <div class="px-4 pb-4"> 5191 5192<div class="mt-1 flex flex-col"> 5193 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5194 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5195 139,00 ⬠</span> 5196 5197 <div class="flex items-baseline gap-1.5"> 5198 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5199 125,00 ⬠</span> 5200 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5201 Precio VIP </span> 5202 </div> 5203 5204 5205 </div> </div> 5206</div> 5207 5208<style> 5209 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5210 .color-picker-grid-mode-clean, 5211 .color-picker-grid-mode-clean>div { 5212 display: flex !important; 5213 flex-direction: row !important; 5214 flex-wrap: wrap !important; 5215 align-items: center !important; 5216 gap: 6px !important; 5217 padding: 0 !important; 5218 margin: 0 !important; 5219 border: none !important; 5220 } 5221 5222 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5223 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5224 .color-picker-grid-mode-clean span.text-sm.font-bold, 5225 .color-picker-grid-mode-clean .w-32 { 5226 display: none !important; 5227 } 5228 5229 /* 3. Ajuste de las "bolitas" de color */ 5230 .color-picker-grid-mode-clean .w-9.h-9 { 5231 width: 22px !important; 5232 /* Tamaño reducido ideal para rejilla */ 5233 height: 22px !important; 5234 min-width: 22px !important; 5235 min-height: 22px !important; 5236 margin: 0 !important; 5237 transform: none !important; 5238 /* Evitamos que el seleccionado crezca y descuadre */ 5239 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5240 } 5241 5242 /* 4. Ajuste del icono Check (V) de selección */ 5243 .color-picker-grid-mode-clean svg { 5244 width: 14px !important; 5245 height: 14px !important; 5246 } 5247 5248 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5249 .product-item-variations { 5250 margin-top: 4px !important; 5251 margin-bottom: 4px !important; 5252 padding-top: 0 !important; 5253 padding-bottom: 0 !important; 5254 } 5255 5256 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5257 .color-picker-grid-mode-clean .flex-wrap { 5258 gap: 6px !important; 5259 } 5260 5261 .product-item-photo>span picture, 5262 .product-item-photo>span img { 5263 width: 100% !important; 5264 height: auto !important; 5265 display: block !important; 5266 } 5267 5268 .product-item-photo>span picture { 5269 position: static !important; 5270 } 5271</style> </li> 5272 <li class="flex flex-col"> 5273 5274<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5275 5276 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-140-cm-ani" class="flex flex-col grow w-full"> 5277 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5278 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-140-cm-ani-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-140-cm-ani-01.jpg" width="360" height="360" alt="mesa-alta-con-2-taburetes-negro-sonoma-140-cm-ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7148.window="updateImage" loading="lazy"></picture> 5279 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5280 </div> 5281 5282 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5283 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5284 <strong>Ani</strong> 5285 </div> 5286 5287 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5288 <span class="product-item-link">Mesa alta con 2 Taburetes Negro y Sonoma 140 cm Ani</span> 5289 </div> 5290 5291 5292 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7148.window="updatePrice($event.detail);"> 5293 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7148" data-price-box="product-id-7148"> 5294 <span 5295 x-data x-id="['product\u002Dprice\u002D7148']" class="price-container price-final_price tax weee" 5296 > 5297 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5298 <span class="price"><span class="price">125,00 â¬</span></span> 5299 </span> 5300 5301 <span class="old-price mr-1"> 5302 <span class="price line-through text-gray-600"> 5303 <span class="price"><span class="price">139,00 â¬</span></span> 5304 5305 </span> 5306 </span> 5307 5308 5309 5310 </span> 5311</div></div> 5312 </div> 5313 </div> 5314 </a> 5315 5316 5317 <!-- <div>CATEGORIA: </div> --> 5318 <div class="product-item-variations px-4 py-2 mt-auto"> 5319 <div id="variaciones-listado-7148"> 5320 <div class="color-picker-grid-mode-clean"> 5321 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5322 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5323 Colores Disponibles: 5324 </span> 5325 5326 <div class="flex flex-wrap gap-4 items-center"> 5327 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-140-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-140-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 5328 </div> 5329 </div> </div> 5330 </div> 5331 <div class="px-4 pb-4"> 5332 5333<div class="mt-1 flex flex-col"> 5334 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5335 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5336 139,00 ⬠</span> 5337 5338 <div class="flex items-baseline gap-1.5"> 5339 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5340 125,00 ⬠</span> 5341 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5342 Precio VIP </span> 5343 </div> 5344 5345 5346 </div> </div> 5347</div> 5348 5349<style> 5350 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5351 .color-picker-grid-mode-clean, 5352 .color-picker-grid-mode-clean>div { 5353 display: flex !important; 5354 flex-direction: row !important; 5355 flex-wrap: wrap !important; 5356 align-items: center !important; 5357 gap: 6px !important; 5358 padding: 0 !important; 5359 margin: 0 !important; 5360 border: none !important; 5361 } 5362 5363 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5364 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5365 .color-picker-grid-mode-clean span.text-sm.font-bold, 5366 .color-picker-grid-mode-clean .w-32 { 5367 display: none !important; 5368 } 5369 5370 /* 3. Ajuste de las "bolitas" de color */ 5371 .color-picker-grid-mode-clean .w-9.h-9 { 5372 width: 22px !important; 5373 /* Tamaño reducido ideal para rejilla */ 5374 height: 22px !important; 5375 min-width: 22px !important; 5376 min-height: 22px !important; 5377 margin: 0 !important; 5378 transform: none !important; 5379 /* Evitamos que el seleccionado crezca y descuadre */ 5380 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5381 } 5382 5383 /* 4. Ajuste del icono Check (V) de selección */ 5384 .color-picker-grid-mode-clean svg { 5385 width: 14px !important; 5386 height: 14px !important; 5387 } 5388 5389 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5390 .product-item-variations { 5391 margin-top: 4px !important; 5392 margin-bottom: 4px !important; 5393 padding-top: 0 !important; 5394 padding-bottom: 0 !important; 5395 } 5396 5397 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5398 .color-picker-grid-mode-clean .flex-wrap { 5399 gap: 6px !important; 5400 } 5401 5402 .product-item-photo>span picture, 5403 .product-item-photo>span img { 5404 width: 100% !important; 5405 height: auto !important; 5406 display: block !important; 5407 } 5408 5409 .product-item-photo>span picture { 5410 position: static !important; 5411 } 5412</style> </li> 5413 <li class="flex flex-col"> 5414 5415<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5416 5417 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-120-cm-ani" class="flex flex-col grow w-full"> 5418 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5419 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_3.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_3.jpg" width="360" height="360" alt="mesa-alta-blanco-sonoma-120-cm-ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7149.window="updateImage" loading="lazy"></picture> 5420 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5421 </div> 5422 5423 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5424 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5425 <strong>Ani</strong> 5426 </div> 5427 5428 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5429 <span class="product-item-link">Mesa alta con 2 Taburetes Blanco y Sonoma 120 cm Ani</span> 5430 </div> 5431 5432 5433 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7149.window="updatePrice($event.detail);"> 5434 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7149" data-price-box="product-id-7149"> 5435 <span 5436 x-data x-id="['product\u002Dprice\u002D7149']" class="price-container price-final_price tax weee" 5437 > 5438 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5439 <span class="price"><span class="price">119,00 â¬</span></span> 5440 </span> 5441 5442 <span class="old-price mr-1"> 5443 <span class="price line-through text-gray-600"> 5444 <span class="price"><span class="price">129,00 â¬</span></span> 5445 5446 </span> 5447 </span> 5448 5449 5450 5451 </span> 5452</div></div> 5453 </div> 5454 </div> 5455 </a> 5456 5457 5458 <!-- <div>CATEGORIA: </div> --> 5459 <div class="product-item-variations px-4 py-2 mt-auto"> 5460 <div id="variaciones-listado-7149"> 5461 <div class="color-picker-grid-mode-clean"> 5462 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5463 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5464 Colores Disponibles: 5465 </span> 5466 5467 <div class="flex flex-wrap gap-4 items-center"> 5468 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-120-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-120-cm-ani"></div> </div> 5469 </div> 5470 </div> </div> 5471 </div> 5472 <div class="px-4 pb-4"> 5473 5474<div class="mt-1 flex flex-col"> 5475 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5476 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5477 129,00 ⬠</span> 5478 5479 <div class="flex items-baseline gap-1.5"> 5480 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5481 119,00 ⬠</span> 5482 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5483 Precio VIP </span> 5484 </div> 5485 5486 5487 </div> </div> 5488</div> 5489 5490<style> 5491 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5492 .color-picker-grid-mode-clean, 5493 .color-picker-grid-mode-clean>div { 5494 display: flex !important; 5495 flex-direction: row !important; 5496 flex-wrap: wrap !important; 5497 align-items: center !important; 5498 gap: 6px !important; 5499 padding: 0 !important; 5500 margin: 0 !important; 5501 border: none !important; 5502 } 5503 5504 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5505 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5506 .color-picker-grid-mode-clean span.text-sm.font-bold, 5507 .color-picker-grid-mode-clean .w-32 { 5508 display: none !important; 5509 } 5510 5511 /* 3. Ajuste de las "bolitas" de color */ 5512 .color-picker-grid-mode-clean .w-9.h-9 { 5513 width: 22px !important; 5514 /* Tamaño reducido ideal para rejilla */ 5515 height: 22px !important; 5516 min-width: 22px !important; 5517 min-height: 22px !important; 5518 margin: 0 !important; 5519 transform: none !important; 5520 /* Evitamos que el seleccionado crezca y descuadre */ 5521 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5522 } 5523 5524 /* 4. Ajuste del icono Check (V) de selección */ 5525 .color-picker-grid-mode-clean svg { 5526 width: 14px !important; 5527 height: 14px !important; 5528 } 5529 5530 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5531 .product-item-variations { 5532 margin-top: 4px !important; 5533 margin-bottom: 4px !important; 5534 padding-top: 0 !important; 5535 padding-bottom: 0 !important; 5536 } 5537 5538 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5539 .color-picker-grid-mode-clean .flex-wrap { 5540 gap: 6px !important; 5541 } 5542 5543 .product-item-photo>span picture, 5544 .product-item-photo>span img { 5545 width: 100% !important; 5546 height: auto !important; 5547 display: block !important; 5548 } 5549 5550 .product-item-photo>span picture { 5551 position: static !important; 5552 } 5553</style> </li> 5554 <li class="flex flex-col"> 5555 5556<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5557 5558 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-120-cm-ani" class="flex flex-col grow w-full"> 5559 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5560 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-120-cm-ani-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-120-cm-ani-01.jpg" width="360" height="360" alt="Mesa alta con 2 Taburetes 
5560Negro y Sonoma 120 cm Ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7150.window="updateImage" loading="lazy"></picture> 5561 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5562 </div> 5563 5564 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5565 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5566 <strong>Ani</strong> 5567 </div> 5568 5569 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight"> 5570 <span class="product-item-link">Mesa alta con 2 Taburetes Negro y Sonoma 120 cm Ani</span> 5571 </div> 5572 5573 5574 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7150.window="updatePrice($event.detail);"> 5575 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7150" data-price-box="product-id-7150"> 5576 <span 5577 x-data x-id="['product\u002Dprice\u002D7150']" class="price-container price-final_price tax weee" 5578 > 5579 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5580 <span class="price"><span class="price">119,00 â¬</span></span> 5581 </span> 5582 5583 <span class="old-price mr-1"> 5584 <span class="price line-through text-gray-600"> 5585 <span class="price"><span class="price">129,00 â¬</span></span> 5586 5587 </span> 5588 </span> 5589 5590 5591 5592 </span> 5593</div></div> 5594 </div> 5595 </div> 5596 </a> 5597 5598 5599 <!-- <div>CATEGORIA: </div> --> 5600 <div class="product-item-variations px-4 py-2 mt-auto"> 5601 <div id="variaciones-listado-7150"> 5602 <div class="color-picker-grid-mode-clean"> 5603 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5604 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5605 Colores Disponibles: 5606 </span> 5607 5608 <div class="flex flex-wrap gap-4 items-center"> 5609 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-120-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-120-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 5610 </div> 5611 </div> </div> 5612 </div> 5613 <div class="px-4 pb-4"> 5614 5615<div class="mt-1 flex flex-col"> 5616 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5617 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5618 129,00 ⬠</span> 5619 5620 <div class="flex items-baseline gap-1.5"> 5621 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5622 119,00 ⬠</span> 5623 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5624 Precio VIP </span> 5625 </div> 5626 5627 5628 </div> </div> 5629</div> 5630 5631<style> 5632 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5633 .color-picker-grid-mode-clean, 5634 .color-picker-grid-mode-clean>div { 5635 display: flex !important; 5636 flex-direction: row !important; 5637 flex-wrap: wrap !important; 5638 align-items: center !important; 5639 gap: 6px !important; 5640 padding: 0 !important; 5641 margin: 0 !important; 5642 border: none !important; 5643 } 5644 5645 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5646 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5647 .color-picker-grid-mode-clean span.text-sm.font-bold, 5648 .color-picker-grid-mode-clean .w-32 { 5649 display: none !important; 5650 } 5651 5652 /* 3. Ajuste de las "bolitas" de color */ 5653 .color-picker-grid-mode-clean .w-9.h-9 { 5654 width: 22px !important; 5655 /* Tamaño reducido ideal para rejilla */ 5656 height: 22px !important; 5657 min-width: 22px !important; 5658 min-height: 22px !important; 5659 margin: 0 !important; 5660 transform: none !important; 5661 /* Evitamos que el seleccionado crezca y descuadre */ 5662 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5663 } 5664 5665 /* 4. Ajuste del icono Check (V) de selección */ 5666 .color-picker-grid-mode-clean svg { 5667 width: 14px !important; 5668 height: 14px !important; 5669 } 5670 5671 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5672 .product-item-variations { 5673 margin-top: 4px !important; 5674 margin-bottom: 4px !important; 5675 padding-top: 0 !important; 5676 padding-bottom: 0 !important; 5677 } 5678 5679 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5680 .color-picker-grid-mode-clean .flex-wrap { 5681 gap: 6px !important; 5682 } 5683 5684 .product-item-photo>span picture, 5685 .product-item-photo>span img { 5686 width: 100% !important; 5687 height: auto !important; 5688 display: block !important; 5689 } 5690 5691 .product-item-photo>span picture { 5692 position: static !important; 5693 } 5694</style> </li> 5695 <li class="flex flex-col"> 5696 5697<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5698 5699 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-100-cm-ani" class="flex flex-col grow w-full"> 5700 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5701 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-100-cm-ani-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-100-cm-ani-01.jpg" width="360" height="360" alt="mesa-alta-con-2-taburetes-blanco-sonoma-100-cm-ani" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7151.window="updateImage" loading="lazy"></picture> 5702 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5703 </div> 5704 5705 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5706 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5707 <strong>Ani</strong> 5708 </div> 5709 5710 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5711 <span class="product-item-link">Mesa alta con 2 Taburetes Blanco y Sonoma 100 cm Ani</span> 5712 </div> 5713 5714 5715 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7151.window="updatePrice($event.detail);"> 5716 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7151" data-price-box="product-id-7151"> 5717 <span 5718 x-data x-id="['product\u002Dprice\u002D7151']" class="price-container price-final_price tax weee" 5719 > 5720 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5721 <span class="price"><span class="price">109,00 â¬</span></span> 5722 </span> 5723 5724 <span class="old-price mr-1"> 5725 <span class="price line-through text-gray-600"> 5726 <span class="price"><span class="price">119,00 â¬</span></span> 5727 5728 </span> 5729 </span> 5730 5731 5732 5733 </span> 5734</div></div> 5735 </div> 5736 </div> 5737 </a> 5738 5739 5740 <!-- <div>CATEGORIA: </div> --> 5741 <div class="product-item-variations px-4 py-2 mt-auto"> 5742 <div id="variaciones-listado-7151"> 5743 <div class="color-picker-grid-mode-clean"> 5744 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5745 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5746 Colores Disponibles: 5747 </span> 5748 5749 <div class="flex flex-wrap gap-4 items-center"> 5750 <div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-100-cm-ani" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-100-cm-ani"></div> </div> 5751 </div> 5752 </div> </div> 5753 </div> 5754 <div class="px-4 pb-4"> 5755 5756<div class="mt-1 flex flex-col"> 5757 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5758 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5759 119,00 ⬠</span> 5760 5761 <div class="flex items-baseline gap-1.5"> 5762 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5763 109,00 ⬠</span> 5764 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5765 Precio VIP </span> 5766 </div> 5767 5768 5769 </div> </div> 5770</div> 5771 5772<style> 5773 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5774 .color-picker-grid-mode-clean, 5775 .color-picker-grid-mode-clean>div { 5776 display: flex !important; 5777 flex-direction: row !important; 5778 flex-wrap: wrap !important; 5779 align-items: center !important; 5780 gap: 6px !important; 5781 padding: 0 !important; 5782 margin: 0 !important; 5783 border: none !important; 5784 } 5785 5786 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5787 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5788 .color-picker-grid-mode-clean span.text-sm.font-bold, 5789 .color-picker-grid-mode-clean .w-32 { 5790 display: none !important; 5791 } 5792 5793 /* 3. Ajuste de las "bolitas" de color */ 5794 .color-picker-grid-mode-clean .w-9.h-9 { 5795 width: 22px !important; 5796 /* Tamaño reducido ideal para rejilla */ 5797 height: 22px !important; 5798 min-width: 22px !important; 5799 min-height: 22px !important; 5800 margin: 0 !important; 5801 transform: none !important; 5802 /* Evitamos que el seleccionado crezca y descuadre */ 5803 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5804 } 5805 5806 /* 4. Ajuste del icono Check (V) de selección */ 5807 .color-picker-grid-mode-clean svg { 5808 width: 14px !important; 5809 height: 14px !important; 5810 } 5811 5812 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5813 .product-item-variations { 5814 margin-top: 4px !important; 5815 margin-bottom: 4px !important; 5816 padding-top: 0 !important; 5817 padding-bottom: 0 !important; 5818 } 5819 5820 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5821 .color-picker-grid-mode-clean .flex-wrap { 5822 gap: 6px !important; 5823 } 5824 5825 .product-item-photo>span picture, 5826 .product-item-photo>span img { 5827 width: 100% !important; 5828 height: auto !important; 5829 display: block !important; 5830 } 5831 5832 .product-item-photo>span picture { 5833 position: static !important; 5834 } 5835</style> </li> 5836 <li class="flex flex-col"> 5837 5838<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5839 5840 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-100-cm-ani" class="flex flex-col grow w-full"> 5841 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5842 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-100-cm-ani-01_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-100-cm-ani-01_1.jpg" width="360" height="360" alt="mesa-alta-con-2-taburetes-negro-sonoma-100-cm-ani-01" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7152.window="updateImage" loading="lazy"></picture> 5843 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5844 </div> 5845 5846 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5847 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5848 <strong>Ani</strong> 5849 </div> 5850 5851 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5852 <span class="product-item-link">Mesa alta con 2 Taburetes Negro y Sonoma 100 cm Ani</span> 5853 </div> 5854 5855 5856 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7152.window="updatePrice($event.detail);"> 5857 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7152" data-price-box="product-id-7152"> 5858 <span 5859 x-data x-id="['product\u002Dprice\u002D7152']" class="price-container price-final_price tax weee" 5860 > 5861 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 5862 <span class="price"><span class="price">109,00 â¬</span></span> 5863 </span> 5864 5865 <span class="old-price mr-1"> 5866 <span class="price line-through text-gray-600"> 5867 <span class="price"><span class="price">119,00 â¬</span></span> 5868 5869 </span> 5870 </span> 5871 5872 5873 5874 </span> 5875</div></div> 5876 </div> 5877 </div> 5878 </a> 5879 5880 5881 <!-- <div>CATEGORIA: </div> --> 5882 <div class="product-item-variations px-4 py-2 mt-auto"> 5883 <div id="variaciones-listado-7152"> 5884 <div class="color-picker-grid-mode-clean"> 5885 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 5886 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 5887 Colores Disponibles: 5888 </span> 5889 5890 <div class="flex flex-wrap gap-4 items-center"> 5891 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-100-cm-ani" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-100-cm-ani"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 5892 </div> 5893 </div> </div> 5894 </div> 5895 <div class="px-4 pb-4"> 5896 5897<div class="mt-1 flex flex-col"> 5898 <!-- Invitado: base price + lÃnea VIP (si existe) --> 5899 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 5900 119,00 ⬠</span> 5901 5902 <div class="flex items-baseline gap-1.5"> 5903 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 5904 109,00 ⬠</span> 5905 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 5906 Precio VIP </span> 5907 </div> 5908 5909 5910 </div> </div> 5911</div> 5912 5913<style> 5914 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 5915 .color-picker-grid-mode-clean, 5916 .color-picker-grid-mode-clean>div { 5917 display: flex !important; 5918 flex-direction: row !important; 5919 flex-wrap: wrap !important; 5920 align-items: center !important; 5921 gap: 6px !important; 5922 padding: 0 !important; 5923 margin: 0 !important; 5924 border: none !important; 5925 } 5926 5927 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 5928 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 5929 .color-picker-grid-mode-clean span.text-sm.font-bold, 5930 .color-picker-grid-mode-clean .w-32 { 5931 display: none !important; 5932 } 5933 5934 /* 3. Ajuste de las "bolitas" de color */ 5935 .color-picker-grid-mode-clean .w-9.h-9 { 5936 width: 22px !important; 5937 /* Tamaño reducido ideal para rejilla */ 5938 height: 22px !important; 5939 min-width: 22px !important; 5940 min-height: 22px !important; 5941 margin: 0 !important; 5942 transform: none !important; 5943 /* Evitamos que el seleccionado crezca y descuadre */ 5944 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 5945 } 5946 5947 /* 4. Ajuste del icono Check (V) de selección */ 5948 .color-picker-grid-mode-clean svg { 5949 width: 14px !important; 5950 height: 14px !important; 5951 } 5952 5953 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 5954 .product-item-variations { 5955 margin-top: 4px !important; 5956 margin-bottom: 4px !important; 5957 padding-top: 0 !important; 5958 padding-bottom: 0 !important; 5959 } 5960 5961 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 5962 .color-picker-grid-mode-clean .flex-wrap { 5963 gap: 6px !important; 5964 } 5965 5966 .product-item-photo>span picture, 5967 .product-item-photo>span img { 5968 width: 100% !important; 5969 height: auto !important; 5970 display: block !important; 5971 } 5972 5973 .product-item-photo>span picture { 5974 position: static !important; 5975 } 5976</style> </li> 5977 <li class="flex flex-col"> 5978 5979<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 5980 5981 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-110-cm-kyra" class="flex flex-col grow w-full"> 5982 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 5983 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-blanco-110-cm-kyra-01_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-blanco-110-cm-kyra-01_1.jpg" width="360" height="360" alt="mesa-alta-con-2-taburetes-blanco-blanco-110-cm-kyra" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7154.window="updateImage" loading="lazy"></picture> 5984 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 5985 </div> 5986 5987 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 5988 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 5989 <strong>Kyra</strong> 5990 </div> 5991 5992 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
5993 <span class="product-item-link">Mesa alta con 2 Taburetes Blanco 110 cm Kyra</span> 5994 </div> 5995 5996 5997 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7154.window="updatePrice($event.detail);"> 5998 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7154" data-price-box="product-id-7154"> 5999 <span 6000 x-data x-id="['product\u002Dprice\u002D7154']" class="price-container price-final_price tax weee" 6001 > 6002 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6003 <span class="price"><span class="price">129,00 â¬</span></span> 6004 </span> 6005 6006 <span class="old-price mr-1"> 6007 <span class="price line-through text-gray-600"> 6008 <span class="price"><span class="price">139,00 â¬</span></span> 6009 6010 </span> 6011 </span> 6012 6013 6014 6015 </span> 6016</div></div> 6017 </div> 6018 </div> 6019 </a> 6020 6021 6022 <!-- <div>CATEGORIA: </div> --> 6023 <div class="product-item-variations px-4 py-2 mt-auto"> 6024 <div id="variaciones-listado-7154"> 6025 <div class="color-picker-grid-mode-clean"> 6026 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6027 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6028 Colores Disponibles: 6029 </span> 6030 6031 <div class="flex flex-wrap gap-4 items-center"> 6032 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra"></div> </div> 6033 </div> 6034 </div> </div> 6035 </div> 6036 <div class="px-4 pb-4"> 6037 6038<div class="mt-1 flex flex-col"> 6039 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6040 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6041 139,00 ⬠</span> 6042 6043 <div class="flex items-baseline gap-1.5"> 6044 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6045 129,00 ⬠</span> 6046 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6047 Precio VIP </span> 6048 </div> 6049 6050 6051 </div> </div> 6052</div> 6053 6054<style> 6055 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6056 .color-picker-grid-mode-clean, 6057 .color-picker-grid-mode-clean>div { 6058 display: flex !important; 6059 flex-direction: row !important; 6060 flex-wrap: wrap !important; 6061 align-items: center !important; 6062 gap: 6px !important; 6063 padding: 0 !important; 6064 margin: 0 !important; 6065 border: none !important; 6066 } 6067 6068 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6069 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6070 .color-picker-grid-mode-clean span.text-sm.font-bold, 6071 .color-picker-grid-mode-clean .w-32 { 6072 display: none !important; 6073 } 6074 6075 /* 3. Ajuste de las "bolitas" de color */ 6076 .color-picker-grid-mode-clean .w-9.h-9 { 6077 width: 22px !important; 6078 /* Tamaño reducido ideal para rejilla */ 6079 height: 22px !important; 6080 min-width: 22px !important; 6081 min-height: 22px !important; 6082 margin: 0 !important; 6083 transform: none !important; 6084 /* Evitamos que el seleccionado crezca y descuadre */ 6085 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6086 } 6087 6088 /* 4. Ajuste del icono Check (V) de selección */ 6089 .color-picker-grid-mode-clean svg { 6090 width: 14px !important; 6091 height: 14px !important; 6092 } 6093 6094 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6095 .product-item-variations { 6096 margin-top: 4px !important; 6097 margin-bottom: 4px !important; 6098 padding-top: 0 !important; 6099 padding-bottom: 0 !important; 6100 } 6101 6102 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6103 .color-picker-grid-mode-clean .flex-wrap { 6104 gap: 6px !important; 6105 } 6106 6107 .product-item-photo>span picture, 6108 .product-item-photo>span img { 6109 width: 100% !important; 6110 height: auto !important; 6111 display: block !important; 6112 } 6113 6114 .product-item-photo>span picture { 6115 position: static !important; 6116 } 6117</style> </li> 6118 <li class="flex flex-col"> 6119 6120<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6121 6122 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra" class="flex flex-col grow w-full"> 6123 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6124 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-110-cm-kyra-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-110-cm-kyra-01.jpg" width="360" height="360" alt="mesa-alta-con-2-taburetes-blanco-sonoma-110-cm-kyra" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7155.window="updateImage" loading="lazy"></picture> 6125 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6126 </div> 6127 6128 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6129 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6130 <strong>Kyra</strong> 6131 </div> 6132 6133 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
6134 <span class="product-item-link">Mesa alta con 2 Taburetes Blanco y Sonoma 110 cm Kyra</span> 6135 </div> 6136 6137 6138 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7155.window="updatePrice($event.detail);"> 6139 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7155" data-price-box="product-id-7155"> 6140 <span 6141 x-data x-id="['product\u002Dprice\u002D7155']" class="price-container price-final_price tax weee" 6142 > 6143 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6144 <span class="price"><span class="price">129,00 â¬</span></span> 6145 </span> 6146 6147 <span class="old-price mr-1"> 6148 <span class="price line-through text-gray-600"> 6149 <span class="price"><span class="price">139,00 â¬</span></span> 6150 6151 </span> 6152 </span> 6153 6154 6155 6156 </span> 6157</div></div> 6158 </div> 6159 </div> 6160 </a> 6161 6162 6163 <!-- <div>CATEGORIA: </div> --> 6164 <div class="product-item-variations px-4 py-2 mt-auto"> 6165 <div id="variaciones-listado-7155"> 6166 <div class="color-picker-grid-mode-clean"> 6167 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6168 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6169 Colores Disponibles: 6170 </span> 6171 6172 <div class="flex flex-wrap gap-4 items-center"> 6173 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-110-cm-kyra" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-110-cm-kyra"></div><div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra" title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra"></div> </div> 6174 </div> 6175 </div> </div> 6176 </div> 6177 <div class="px-4 pb-4"> 6178 6179<div class="mt-1 flex flex-col"> 6180 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6181 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6182 139,00 ⬠</span> 6183 6184 <div class="flex items-baseline gap-1.5"> 6185 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6186 129,00 ⬠</span> 6187 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6188 Precio VIP </span> 6189 </div> 6190 6191 6192 </div> </div> 6193</div> 6194 6195<style> 6196 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6197 .color-picker-grid-mode-clean, 6198 .color-picker-grid-mode-clean>div { 6199 display: flex !important; 6200 flex-direction: row !important; 6201 flex-wrap: wrap !important; 6202 align-items: center !important; 6203 gap: 6px !important; 6204 padding: 0 !important; 6205 margin: 0 !important; 6206 border: none !important; 6207 } 6208 6209 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6210 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6211 .color-picker-grid-mode-clean span.text-sm.font-bold, 6212 .color-picker-grid-mode-clean .w-32 { 6213 display: none !important; 6214 } 6215 6216 /* 3. Ajuste de las "bolitas" de color */ 6217 .color-picker-grid-mode-clean .w-9.h-9 { 6218 width: 22px !important; 6219 /* Tamaño reducido ideal para rejilla */ 6220 height: 22px !important; 6221 min-width: 22px !important; 6222 min-height: 22px !important; 6223 margin: 0 !important; 6224 transform: none !important; 6225 /* Evitamos que el seleccionado crezca y descuadre */ 6226 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6227 } 6228 6229 /* 4. Ajuste del icono Check (V) de selección */ 6230 .color-picker-grid-mode-clean svg { 6231 width: 14px !important; 6232 height: 14px !important; 6233 } 6234 6235 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6236 .product-item-variations { 6237 margin-top: 4px !important; 6238 margin-bottom: 4px !important; 6239 padding-top: 0 !important; 6240 padding-bottom: 0 !important; 6241 } 6242 6243 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6244 .color-picker-grid-mode-clean .flex-wrap { 6245 gap: 6px !important; 6246 } 6247 6248 .product-item-photo>span picture, 6249 .product-item-photo>span img { 6250 width: 100% !important; 6251 height: auto !important; 6252 display: block !important; 6253 } 6254 6255 .product-item-photo>span picture { 6256 position: static !important; 6257 } 6258</style> </li> 6259 <li class="flex flex-col"> 6260 6261<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6262 6263 <a href="https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra" class="flex flex-col grow w-full"> 6264 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6265 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-110-cm-04_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-110-cm-04_1.jpg" width="360" height="360" alt="Mesa alta con 2 Taburetes 
6265Negro y Sonoma 110 cm Kyra" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7219.window="updateImage" loading="lazy"></picture> 6266 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6267 </div> 6268 6269 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6270 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6271 <strong>Kyra</strong> 6272 </div> 6273 6274 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight"> 6275 <span class="product-item-link">Mesa alta con 2 Taburetes Negro y Sonoma 110 cm Kyra</span> 6276 </div> 6277 6278 6279 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7219.window="updatePrice($event.detail);"> 6280 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7219" data-price-box="product-id-7219"> 6281 <span 6282 x-data x-id="['product\u002Dprice\u002D7219']" class="price-container price-final_price tax weee" 6283 > 6284 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6285 <span class="price"><span class="price">129,00 â¬</span></span> 6286 </span> 6287 6288 <span class="old-price mr-1"> 6289 <span class="price line-through text-gray-600"> 6290 <span class="price"><span class="price">139,00 â¬</span></span> 6291 6292 </span> 6293 </span> 6294 6295 6296 6297 </span> 6298</div></div> 6299 </div> 6300 </div> 6301 </a> 6302 6303 6304 <!-- <div>CATEGORIA: </div> --> 6305 <div class="product-item-variations px-4 py-2 mt-auto"> 6306 <div id="variaciones-listado-7219"> 6307 <div class="color-picker-grid-mode-clean"> 6308 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6309 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6310 Colores Disponibles: 6311 </span> 6312 6313 <div class="flex flex-wrap gap-4 items-center"> 6314 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-110-cm-kyra" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-110-cm-kyra"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra" title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra"></div><div class="relative flex items-center justify-center"><div title="BLSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #000000 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 6315 </div> 6316 </div> </div> 6317 </div> 6318 <div class="px-4 pb-4"> 6319 6320<div class="mt-1 flex flex-col"> 6321 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6322 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6323 139,00 ⬠</span> 6324 6325 <div class="flex items-baseline gap-1.5">
6326 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6327 129,00 ⬠</span> 6328 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6329 Precio VIP </span> 6330 </div> 6331 6332 6333 </div> </div> 6334</div> 6335 6336<style> 6337 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6338 .color-picker-grid-mode-clean, 6339 .color-picker-grid-mode-clean>div { 6340 display: flex !important; 6341 flex-direction: row !important; 6342 flex-wrap: wrap !important; 6343 align-items: center !important; 6344 gap: 6px !important; 6345 padding: 0 !important; 6346 margin: 0 !important; 6347 border: none !important; 6348 } 6349 6350 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6351 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6352 .color-picker-grid-mode-clean span.text-sm.font-bold, 6353 .color-picker-grid-mode-clean .w-32 { 6354 display: none !important; 6355 } 6356 6357 /* 3. Ajuste de las "bolitas" de color */ 6358 .color-picker-grid-mode-clean .w-9.h-9 { 6359 width: 22px !important; 6360 /* Tamaño reducido ideal para rejilla */ 6361 height: 22px !important; 6362 min-width: 22px !important; 6363 min-height: 22px !important; 6364 margin: 0 !important; 6365 transform: none !important; 6366 /* Evitamos que el seleccionado crezca y descuadre */ 6367 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6368 } 6369 6370 /* 4. Ajuste del icono Check (V) de selección */ 6371 .color-picker-grid-mode-clean svg { 6372 width: 14px !important; 6373 height: 14px !important; 6374 } 6375 6376 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6377 .product-item-variations { 6378 margin-top: 4px !important; 6379 margin-bottom: 4px !important; 6380 padding-top: 0 !important; 6381 padding-bottom: 0 !important; 6382 } 6383 6384 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6385 .color-picker-grid-mode-clean .flex-wrap { 6386 gap: 6px !important; 6387 } 6388 6389 .product-item-photo>span picture, 6390 .product-item-photo>span img { 6391 width: 100% !important; 6392 height: auto !important; 6393 display: block !important; 6394 } 6395 6396 .product-item-photo>span picture { 6397 position: static !important; 6398 } 6399</style> </li> 6400 <li class="flex flex-col"> 6401 6402<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6403 6404 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-iris-color-roble" class="flex flex-col grow w-full"> 6405 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6406 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-roble-1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-roble-1.jpg" width="360" height="360" alt="Aparador modelo Iris color Roble " class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7249.window="updateImage" loading="lazy"></picture> 6407 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6408 </div> 6409 6410 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6411 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6412 <strong>Iris</strong> 6413 </div> 6414 6415 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight"> 6416 <span class="product-item-link">Aparador modelo Iris color Roble</span> 6417 </div> 6418 6419 6420 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7249.window="updatePrice($event.detail);"> 6421 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7249" data-price-box="product-id-7249"> 6422 <span
6423 x-data x-id="['product\u002Dprice\u002D7249']" class="price-container price-final_price tax weee" 6424 > 6425 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6426 <span class="price"><span class="price">99,00 â¬</span></span> 6427 </span> 6428 6429 <span class="old-price mr-1"> 6430 <span class="price line-through text-gray-600"> 6431 <span class="price"><span class="price">109,00 â¬</span></span> 6432 6433 </span> 6434 </span> 6435 6436 6437 6438 </span> 6439</div></div> 6440 </div> 6441 </div> 6442 </a> 6443 6444 6445 <!-- <div>CATEGORIA: </div> --> 6446 <div class="product-item-variations px-4 py-2 mt-auto"> 6447 <div id="variaciones-listado-7249"> 6448 <div class="color-picker-grid-mode-clean"> 6449 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6450 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6451 Colores Disponibles: 6452 </span> 6453 6454 <div class="flex flex-wrap gap-4 items-center"> 6455 <div class="relative flex items-center justify-center"><div title="RORO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #D2B48C;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-iris-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-iris-color-blanco"></div> </div> 6456 </div> 6457 </div> </div> 6458 </div> 6459 <div class="px-4 pb-4"> 6460 6461<div class="mt-1 flex flex-col"> 6462 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6463 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6464 109,00 ⬠</span> 6465 6466 <div class="flex items-baseline gap-1.5"> 6467 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6468 99,00 ⬠</span> 6469 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6470 Precio VIP </span> 6471 </div> 6472 6473 6474 </div> </div> 6475</div> 6476 6477<style> 6478 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6479 .color-picker-grid-mode-clean, 6480 .color-picker-grid-mode-clean>div { 6481 display: flex !important; 6482 flex-direction: row !important; 6483 flex-wrap: wrap !important; 6484 align-items: center !important; 6485 gap: 6px !important; 6486 padding: 0 !important; 6487 margin: 0 !important; 6488 border: none !important; 6489 } 6490 6491 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6492 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6493 .color-picker-grid-mode-clean span.text-sm.font-bold, 6494 .color-picker-grid-mode-clean .w-32 { 6495 display: none !important; 6496 } 6497 6498 /* 3. Ajuste de las "bolitas" de color */ 6499 .color-picker-grid-mode-clean .w-9.h-9 { 6500 width: 22px !important; 6501 /* Tamaño reducido ideal para rejilla */ 6502 height: 22px !important; 6503 min-width: 22px !important; 6504 min-height: 22px !important; 6505 margin: 0 !important; 6506 transform: none !important; 6507 /* Evitamos que el seleccionado crezca y descuadre */ 6508 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6509 } 6510 6511 /* 4. Ajuste del icono Check (V) de selección */ 6512 .color-picker-grid-mode-clean svg { 6513 width: 14px !important; 6514 height: 14px !important; 6515 } 6516 6517 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6518 .product-item-variations { 6519 margin-top: 4px !important; 6520 margin-bottom: 4px !important; 6521 padding-top: 0 !important; 6522 padding-bottom: 0 !important; 6523 } 6524 6525 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6526 .color-picker-grid-mode-clean .flex-wrap { 6527 gap: 6px !important; 6528 } 6529 6530 .product-item-photo>span picture, 6531 .product-item-photo>span img { 6532 width: 100% !important; 6533 height: auto !important; 6534 display: block !important; 6535 } 6536 6537 .product-item-photo>span picture { 6538 position: static !important; 6539 } 6540</style> </li> 6541 <li class="flex flex-col"> 6542 6543<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6544 6545 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-iris-color-blanco" class="flex flex-col grow w-full"> 6546 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6547 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-blanco-1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-blanco-1.jpg" width="360" height="360" alt="Aparador modelo Iris color Blanco" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7250.window="updateImage" loading="lazy"></picture> 6548 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6549 </div> 6550 6551 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6552 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6553 <strong>Iris</strong> 6554 </div> 6555 6556 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
6557 <span class="product-item-link">Aparador modelo Iris color Blanco</span> 6558 </div> 6559 6560 6561 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7250.window="updatePrice($event.detail);"> 6562 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7250" data-price-box="product-id-7250"> 6563 <span 6564 x-data x-id="['product\u002Dprice\u002D7250']" class="price-container price-final_price tax weee" 6565 > 6566 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6567 <span class="price"><span class="price">99,00 â¬</span></span> 6568 </span> 6569 6570 <span class="old-price mr-1"> 6571 <span class="price line-through text-gray-600"> 6572 <span class="price"><span class="price">109,00 â¬</span></span> 6573 6574 </span> 6575 </span> 6576 6577 6578 6579 </span> 6580</div></div> 6581 </div> 6582 </div> 6583 </a> 6584 6585 6586 <!-- <div>CATEGORIA: </div> --> 6587 <div class="product-item-variations px-4 py-2 mt-auto"> 6588 <div id="variaciones-listado-7250"> 6589 <div class="color-picker-grid-mode-clean"> 6590 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6591 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6592 Colores Disponibles: 6593 </span> 6594 6595 <div class="flex flex-wrap gap-4 items-center"> 6596 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-iris-color-roble" title="RORO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #D2B48C;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-iris-color-roble"></div><div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 6597 </div> 6598 </div> </div> 6599 </div> 6600 <div class="px-4 pb-4"> 6601 6602<div class="mt-1 flex flex-col"> 6603 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6604 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6605 109,00 ⬠</span> 6606 6607 <div class="flex items-baseline gap-1.5"> 6608 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6609 99,00 ⬠</span> 6610 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6611 Precio VIP </span> 6612 </div> 6613 6614 6615 </div> </div> 6616</div> 6617 6618<style> 6619 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6620 .color-picker-grid-mode-clean, 6621 .color-picker-grid-mode-clean>div { 6622 display: flex !important; 6623 flex-direction: row !important; 6624 flex-wrap: wrap !important; 6625 align-items: center !important; 6626 gap: 6px !important; 6627 padding: 0 !important; 6628 margin: 0 !important; 6629 border: none !important; 6630 } 6631 6632 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6633 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6634 .color-picker-grid-mode-clean span.text-sm.font-bold, 6635 .color-picker-grid-mode-clean .w-32 { 6636 display: none !important; 6637 } 6638 6639 /* 3. Ajuste de las "bolitas" de color */ 6640 .color-picker-grid-mode-clean .w-9.h-9 { 6641 width: 22px !important; 6642 /* Tamaño reducido ideal para rejilla */ 6643 height: 22px !important; 6644 min-width: 22px !important; 6645 min-height: 22px !important; 6646 margin: 0 !important; 6647 transform: none !important; 6648 /* Evitamos que el seleccionado crezca y descuadre */ 6649 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6650 } 6651 6652 /* 4. Ajuste del icono Check (V) de selección */ 6653 .color-picker-grid-mode-clean svg { 6654 width: 14px !important; 6655 height: 14px !important; 6656 } 6657 6658 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6659 .product-item-variations { 6660 margin-top: 4px !important; 6661 margin-bottom: 4px !important; 6662 padding-top: 0 !important; 6663 padding-bottom: 0 !important; 6664 } 6665 6666 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6667 .color-picker-grid-mode-clean .flex-wrap { 6668 gap: 6px !important; 6669 } 6670 6671 .product-item-photo>span picture, 6672 .product-item-photo>span img { 6673 width: 100% !important; 6674 height: auto !important; 6675 display: block !important; 6676 } 6677 6678 .product-item-photo>span picture { 6679 position: static !important; 6680 } 6681</style> </li> 6682 <li class="flex flex-col"> 6683 6684<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6685 6686 <a href="https://www.mueblesbonitos.com/salon/mueble-tv-color-roble-alba-150cm-renzo" class="flex flex-col grow w-full"> 6687 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6688 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-color-roble-alba-150cm-renzo-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-color-roble-alba-150cm-renzo-01.jpg" width="360" height="360" alt="Mueble TV color roble alba 150cm Renzo" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7256.window="updateImage" loading="lazy"></picture> 6689 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6690 </div> 6691 6692 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6693 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6694 <strong>Renzo</strong> 6695 </div> 6696 6697 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
6698 <span class="product-item-link">Mueble TV color roble alba 150cm Renzo</span> 6699 </div> 6700 6701 6702 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7256.window="updatePrice($event.detail);"> 6703 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7256" data-price-box="product-id-7256"> 6704 <span 6705 x-data x-id="['product\u002Dprice\u002D7256']" class="price-container price-final_price tax weee" 6706 > 6707 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6708 <span class="price"><span class="price">72,00 â¬</span></span> 6709 </span> 6710 6711 <span class="old-price mr-1"> 6712 <span class="price line-through text-gray-600"> 6713 <span class="price"><span class="price">79,00 â¬</span></span> 6714 6715 </span> 6716 </span> 6717 6718 6719 6720 </span> 6721</div></div> 6722 </div> 6723 </div> 6724 </a> 6725 6726 6727 <!-- <div>CATEGORIA: </div> --> 6728 <div class="product-item-variations px-4 py-2 mt-auto"> 6729 <div id="variaciones-listado-7256"> 6730 <div class="color-picker-grid-mode-clean"> 6731 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6732 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6733 Colores Disponibles: 6734 </span> 6735 6736 <div class="flex flex-wrap gap-4 items-center"> 6737 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mueble-tv-color-blanco-150cm-renzo" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mueble-tv-color-blanco-150cm-renzo"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mueble-tv-color-negro-150cm-renzo" title="BLBL" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #000000;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mueble-tv-color-negro-150cm-renzo"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mueble-tv-color-roble-eos-150cm-renzo" title="ZOZO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #bfa37b;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mueble-tv-color-roble-eos-150cm-renzo"></div><div class="relative flex items-center justify-center"><div title="LOLO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #ce9f75;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 6738 </div> 6739 </div> </div> 6740 </div> 6741 <div class="px-4 pb-4"> 6742 6743<div class="mt-1 flex flex-col"> 6744 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6745 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6746 79,00 ⬠</span> 6747 6748 <div class="flex items-baseline gap-1.5"> 6749 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6750 72,00 ⬠</span> 6751 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6752 Precio VIP </span> 6753 </div> 6754 6755 6756 </div> </div> 6757</div> 6758 6759<style> 6760 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6761 .color-picker-grid-mode-clean, 6762 .color-picker-grid-mode-clean>div { 6763 display: flex !important; 6764 flex-direction: row !important; 6765 flex-wrap: wrap !important; 6766 align-items: center !important; 6767 gap: 6px !important; 6768 padding: 0 !important; 6769 margin: 0 !important; 6770 border: none !important; 6771 } 6772 6773 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6774 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6775 .color-picker-grid-mode-clean span.text-sm.font-bold, 6776 .color-picker-grid-mode-clean .w-32 { 6777 display: none !important; 6778 } 6779 6780 /* 3. Ajuste de las "bolitas" de color */ 6781 .color-picker-grid-mode-clean .w-9.h-9 { 6782 width: 22px !important; 6783 /* Tamaño reducido ideal para rejilla */ 6784 height: 22px !important; 6785 min-width: 22px !important; 6786 min-height: 22px !important; 6787 margin: 0 !important; 6788 transform: none !important; 6789 /* Evitamos que el seleccionado crezca y descuadre */ 6790 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6791 } 6792 6793 /* 4. Ajuste del icono Check (V) de selección */ 6794 .color-picker-grid-mode-clean svg { 6795 width: 14px !important; 6796 height: 14px !important; 6797 } 6798 6799 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6800 .product-item-variations { 6801 margin-top: 4px !important; 6802 margin-bottom: 4px !important; 6803 padding-top: 0 !important; 6804 padding-bottom: 0 !important; 6805 } 6806 6807 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6808 .color-picker-grid-mode-clean .flex-wrap { 6809 gap: 6px !important; 6810 } 6811 6812 .product-item-photo>span picture, 6813 .product-item-photo>span img { 6814 width: 100% !important; 6815 height: auto !important; 6816 display: block !important; 6817 } 6818 6819 .product-item-photo>span picture { 6820 position: static !important; 6821 } 6822</style> </li> 6823 <li class="flex flex-col"> 6824 6825<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6826 6827 <a href="https://www.mueblesbonitos.com/salon/aparador-blanco-y-sonoma-moderno-150-cm-serena" class="flex flex-col grow w-full"> 6828 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6829 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-color-blanco-y-sonoma-150-cm-serena-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-color-blanco-y-sonoma-150-cm-serena-01.jpg" width="360" height="360" alt=" Aparador color Blanco y Sonoma 150 cm Serena" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7259.window="updateImage" loading="lazy"></picture> 6830 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6831 </div> 6832 6833 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6834 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6835 <strong>Serena</strong> 6836 </div> 6837 6838 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
6839 <span class="product-item-link">Aparador Blanco y Sonoma Moderno 150 cm Serena</span> 6840 </div> 6841 6842 6843 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7259.window="updatePrice($event.detail);"> 6844 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7259" data-price-box="product-id-7259"> 6845 <span 6846 x-data x-id="['product\u002Dprice\u002D7259']" class="price-container price-final_price tax weee" 6847 > 6848 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6849 <span class="price"><span class="price">179,00 â¬</span></span> 6850 </span> 6851 6852 <span class="old-price mr-1"> 6853 <span class="price line-through text-gray-600"> 6854 <span class="price"><span class="price">199,00 â¬</span></span> 6855 6856 </span> 6857 </span> 6858 6859 6860 6861 </span> 6862</div></div> 6863 </div> 6864 </div> 6865 </a> 6866 6867 6868 <!-- <div>CATEGORIA: </div> --> 6869 <div class="product-item-variations px-4 py-2 mt-auto"> 6870 <div id="variaciones-listado-7259"> 6871 <div class="color-picker-grid-mode-clean"> 6872 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 6873 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 6874 Colores Disponibles: 6875 </span> 6876 6877 <div class="flex flex-wrap gap-4 items-center"> 6878 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-blanco-moderno-150-cm-serena" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-blanco-moderno-150-cm-serena"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-roble-alpes-moderno-150-cm-serena" title="MOMO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #b6a77e;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-roble-alpes-moderno-150-cm-serena"></div><div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 6879 </div> 6880 </div> </div> 6881 </div> 6882 <div class="px-4 pb-4"> 6883 6884<div class="mt-1 flex flex-col"> 6885 <!-- Invitado: base price + lÃnea VIP (si existe) --> 6886 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 6887 199,00 ⬠</span> 6888 6889 <div class="flex items-baseline gap-1.5"> 6890 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 6891 179,00 ⬠</span> 6892 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 6893 Precio VIP </span> 6894 </div> 6895 6896 6897 </div> </div> 6898</div> 6899 6900<style> 6901 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 6902 .color-picker-grid-mode-clean, 6903 .color-picker-grid-mode-clean>div { 6904 display: flex !important; 6905 flex-direction: row !important; 6906 flex-wrap: wrap !important; 6907 align-items: center !important; 6908 gap: 6px !important; 6909 padding: 0 !important; 6910 margin: 0 !important; 6911 border: none !important; 6912 } 6913 6914 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 6915 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 6916 .color-picker-grid-mode-clean span.text-sm.font-bold, 6917 .color-picker-grid-mode-clean .w-32 { 6918 display: none !important; 6919 } 6920 6921 /* 3. Ajuste de las "bolitas" de color */ 6922 .color-picker-grid-mode-clean .w-9.h-9 { 6923 width: 22px !important; 6924 /* Tamaño reducido ideal para rejilla */ 6925 height: 22px !important; 6926 min-width: 22px !important; 6927 min-height: 22px !important; 6928 margin: 0 !important; 6929 transform: none !important; 6930 /* Evitamos que el seleccionado crezca y descuadre */ 6931 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 6932 } 6933 6934 /* 4. Ajuste del icono Check (V) de selección */ 6935 .color-picker-grid-mode-clean svg { 6936 width: 14px !important; 6937 height: 14px !important; 6938 } 6939 6940 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 6941 .product-item-variations { 6942 margin-top: 4px !important; 6943 margin-bottom: 4px !important; 6944 padding-top: 0 !important; 6945 padding-bottom: 0 !important; 6946 } 6947 6948 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 6949 .color-picker-grid-mode-clean .flex-wrap { 6950 gap: 6px !important; 6951 } 6952 6953 .product-item-photo>span picture, 6954 .product-item-photo>span img { 6955 width: 100% !important; 6956 height: auto !important; 6957 display: block !important; 6958 } 6959 6960 .product-item-photo>span picture { 6961 position: static !important; 6962 } 6963</style> </li> 6964 <li class="flex flex-col"> 6965 6966<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 6967 6968 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-leo-color-blanco-mate" class="flex flex-col grow w-full"> 6969 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 6970 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-blanco-mate-09.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-blanco-mate-09.jpg" width="360" height="360" alt="Aparador modelo Leo color Blanco mate" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7260.window="updateImage" loading="lazy"></picture> 6971 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 6972 </div> 6973 6974 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 6975 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 6976 <strong>Leo</strong> 6977 </div> 6978 6979 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
6980 <span class="product-item-link">Aparador modelo Leo color Blanco mate</span> 6981 </div> 6982 6983 6984 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7260.window="updatePrice($event.detail);"> 6985 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7260" data-price-box="product-id-7260"> 6986 <span 6987 x-data x-id="['product\u002Dprice\u002D7260']" class="price-container price-final_price tax weee" 6988 > 6989 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 6990 <span class="price"><span class="price">99,00 â¬</span></span> 6991 </span> 6992 6993 <span class="old-price mr-1"> 6994 <span class="price line-through text-gray-600"> 6995 <span class="price"><span class="price">109,00 â¬</span></span> 6996 6997 </span> 6998 </span> 6999 7000 7001 7002 </span> 7003</div></div> 7004 </div> 7005 </div> 7006 </a> 7007 7008 7009 <!-- <div>CATEGORIA: </div> --> 7010 <div class="product-item-variations px-4 py-2 mt-auto"> 7011 <div id="variaciones-listado-7260"> 7012 <div class="color-picker-grid-mode-clean"> 7013 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7014 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7015 Colores Disponibles: 7016 </span> 7017 7018 <div class="flex flex-wrap gap-4 items-center"> 7019 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-leo-color-roble-eos" title="ZOZO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #bfa37b;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-leo-color-roble-eos"></div> </div> 7020 </div> 7021 </div> </div> 7022 </div> 7023 <div class="px-4 pb-4"> 7024 7025<div class="mt-1 flex flex-col"> 7026 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7027 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7028 109,00 ⬠</span> 7029 7030 <div class="flex items-baseline gap-1.5"> 7031 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7032 99,00 ⬠</span> 7033 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7034 Precio VIP </span> 7035 </div> 7036 7037 7038 </div> </div> 7039</div> 7040 7041<style> 7042 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7043 .color-picker-grid-mode-clean, 7044 .color-picker-grid-mode-clean>div { 7045 display: flex !important; 7046 flex-direction: row !important; 7047 flex-wrap: wrap !important; 7048 align-items: center !important; 7049 gap: 6px !important; 7050 padding: 0 !important; 7051 margin: 0 !important; 7052 border: none !important; 7053 } 7054 7055 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7056 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7057 .color-picker-grid-mode-clean span.text-sm.font-bold, 7058 .color-picker-grid-mode-clean .w-32 { 7059 display: none !important; 7060 } 7061 7062 /* 3. Ajuste de las "bolitas" de color */ 7063 .color-picker-grid-mode-clean .w-9.h-9 { 7064 width: 22px !important; 7065 /* Tamaño reducido ideal para rejilla */ 7066 height: 22px !important; 7067 min-width: 22px !important; 7068 min-height: 22px !important; 7069 margin: 0 !important; 7070 transform: none !important; 7071 /* Evitamos que el seleccionado crezca y descuadre */ 7072 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7073 } 7074 7075 /* 4. Ajuste del icono Check (V) de selección */ 7076 .color-picker-grid-mode-clean svg { 7077 width: 14px !important; 7078 height: 14px !important; 7079 } 7080 7081 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7082 .product-item-variations { 7083 margin-top: 4px !important; 7084 margin-bottom: 4px !important; 7085 padding-top: 0 !important; 7086 padding-bottom: 0 !important; 7087 } 7088 7089 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7090 .color-picker-grid-mode-clean .flex-wrap { 7091 gap: 6px !important; 7092 } 7093 7094 .product-item-photo>span picture, 7095 .product-item-photo>span img { 7096 width: 100% !important; 7097 height: auto !important; 7098 display: block !important; 7099 } 7100 7101 .product-item-photo>span picture { 7102 position: static !important; 7103 } 7104</style> </li> 7105 <li class="flex flex-col"> 7106 7107<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7108 7109 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-leo-color-roble-eos" class="flex flex-col grow w-full"> 7110 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7111 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-roble-eos-mate-05.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-roble-eos-mate-05.jpg" width="360" height="360" alt="Aparador modelo Leo color Roble Eos" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7261.window="updateImage" loading="lazy"></picture> 7112 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7113 </div> 7114 7115 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7116 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7117 <strong>Leo</strong> 7118 </div> 7119 7120 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7121 <span class="product-item-link">Aparador modelo Leo color Roble Eos</span> 7122 </div> 7123 7124 7125 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7261.window="updatePrice($event.detail);"> 7126 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7261" data-price-box="product-id-7261"> 7127 <span 7128 x-data x-id="['product\u002Dprice\u002D7261']" class="price-container price-final_price tax weee" 7129 > 7130 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7131 <span class="price"><span class="price">99,00 â¬</span></span> 7132 </span> 7133 7134 <span class="old-price mr-1"> 7135 <span class="price line-through text-gray-600"> 7136 <span class="price"><span class="price">109,00 â¬</span></span> 7137 7138 </span> 7139 </span> 7140 7141 7142 7143 </span> 7144</div></div> 7145 </div> 7146 </div> 7147 </a> 7148 7149 7150 <!-- <div>CATEGORIA: </div> --> 7151 <div class="product-item-variations px-4 py-2 mt-auto"> 7152 <div id="variaciones-listado-7261"> 7153 <div class="color-picker-grid-mode-clean"> 7154 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7155 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7156 Colores Disponibles: 7157 </span> 7158 7159 <div class="flex flex-wrap gap-4 items-center"> 7160 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-leo-color-blanco-mate" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-leo-color-blanco-mate"></div><div class="relative flex items-center justify-center"><div title="ZOZO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #bfa37b;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 7161 </div> 7162 </div> </div> 7163 </div> 7164 <div class="px-4 pb-4"> 7165 7166<div class="mt-1 flex flex-col"> 7167 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7168 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7169 109,00 ⬠</span> 7170 7171 <div class="flex items-baseline gap-1.5"> 7172 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7173 99,00 ⬠</span> 7174 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7175 Precio VIP </span> 7176 </div> 7177 7178 7179 </div> </div> 7180</div> 7181 7182<style> 7183 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7184 .color-picker-grid-mode-clean, 7185 .color-picker-grid-mode-clean>div { 7186 display: flex !important; 7187 flex-direction: row !important; 7188 flex-wrap: wrap !important; 7189 align-items: center !important; 7190 gap: 6px !important; 7191 padding: 0 !important; 7192 margin: 0 !important; 7193 border: none !important; 7194 } 7195 7196 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7197 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7198 .color-picker-grid-mode-clean span.text-sm.font-bold, 7199 .color-picker-grid-mode-clean .w-32 { 7200 display: none !important; 7201 } 7202 7203 /* 3. Ajuste de las "bolitas" de color */ 7204 .color-picker-grid-mode-clean .w-9.h-9 { 7205 width: 22px !important; 7206 /* Tamaño reducido ideal para rejilla */ 7207 height: 22px !important; 7208 min-width: 22px !important; 7209 min-height: 22px !important; 7210 margin: 0 !important; 7211 transform: none !important; 7212 /* Evitamos que el seleccionado crezca y descuadre */ 7213 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7214 } 7215 7216 /* 4. Ajuste del icono Check (V) de selección */ 7217 .color-picker-grid-mode-clean svg { 7218 width: 14px !important; 7219 height: 14px !important; 7220 } 7221 7222 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7223 .product-item-variations { 7224 margin-top: 4px !important; 7225 margin-bottom: 4px !important; 7226 padding-top: 0 !important; 7227 padding-bottom: 0 !important; 7228 } 7229 7230 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7231 .color-picker-grid-mode-clean .flex-wrap { 7232 gap: 6px !important; 7233 } 7234 7235 .product-item-photo>span picture, 7236 .product-item-photo>span img { 7237 width: 100% !important; 7238 height: auto !important; 7239 display: block !important; 7240 } 7241 7242 .product-item-photo>span picture { 7243 position: static !important; 7244 } 7245</style> </li> 7246 <li class="flex flex-col"> 7247 7248<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7249 7250 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-duna-color-roble-eos" class="flex flex-col grow w-full"> 7251 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7252 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-duna-color-roble-eos-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-duna-color-roble-eos-01.jpg" width="360" height="360" alt="Aparador modelo Duna color Roble Eos" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7262.window="updateImage" loading="lazy"></picture> 7253 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7254 </div> 7255 7256 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7257 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7258 <strong>Duna</strong> 7259 </div> 7260 7261 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7262 <span class="product-item-link">Aparador modelo Duna color Roble Eos</span> 7263 </div> 7264 7265 7266 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7262.window="updatePrice($event.detail);"> 7267 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7262" data-price-box="product-id-7262"> 7268 <span 7269 x-data x-id="['product\u002Dprice\u002D7262']" class="price-container price-final_price tax weee" 7270 > 7271 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7272 <span class="price"><span class="price">79,00 â¬</span></span> 7273 </span> 7274 7275 <span class="old-price mr-1"> 7276 <span class="price line-through text-gray-600"> 7277 <span class="price"><span class="price">89,00 â¬</span></span> 7278 7279 </span> 7280 </span> 7281 7282 7283 7284 </span> 7285</div></div> 7286 </div> 7287 </div> 7288 </a> 7289 7290 7291 <!-- <div>CATEGORIA: </div> --> 7292 <div class="product-item-variations px-4 py-2 mt-auto"> 7293 <div id="variaciones-listado-7262"> 7294 <div class="color-picker-grid-mode-clean"> 7295 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7296 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7297 Colores Disponibles: 7298 </span> 7299 7300 <div class="flex flex-wrap gap-4 items-center"> 7301 <div class="relative flex items-center justify-center"><div title="ZOZO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #bfa37b;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 7302 </div> 7303 </div> </div> 7304 </div> 7305 <div class="px-4 pb-4"> 7306 7307<div class="mt-1 flex flex-col"> 7308 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7309 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7310 89,00 ⬠</span> 7311 7312 <div class="flex items-baseline gap-1.5"> 7313 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7314 79,00 ⬠</span> 7315 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7316 Precio VIP </span> 7317 </div> 7318 7319 7320 </div> </div> 7321</div> 7322 7323<style> 7324 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7325 .color-picker-grid-mode-clean, 7326 .color-picker-grid-mode-clean>div { 7327 display: flex !important; 7328 flex-direction: row !important; 7329 flex-wrap: wrap !important; 7330 align-items: center !important; 7331 gap: 6px !important; 7332 padding: 0 !important; 7333 margin: 0 !important; 7334 border: none !important; 7335 } 7336 7337 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7338 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7339 .color-picker-grid-mode-clean span.text-sm.font-bold, 7340 .color-picker-grid-mode-clean .w-32 { 7341 display: none !important; 7342 } 7343 7344 /* 3. Ajuste de las "bolitas" de color */ 7345 .color-picker-grid-mode-clean .w-9.h-9 { 7346 width: 22px !important; 7347 /* Tamaño reducido ideal para rejilla */ 7348 height: 22px !important; 7349 min-width: 22px !important; 7350 min-height: 22px !important; 7351 margin: 0 !important; 7352 transform: none !important; 7353 /* Evitamos que el seleccionado crezca y descuadre */ 7354 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7355 } 7356 7357 /* 4. Ajuste del icono Check (V) de selección */ 7358 .color-picker-grid-mode-clean svg { 7359 width: 14px !important; 7360 height: 14px !important; 7361 } 7362 7363 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7364 .product-item-variations { 7365 margin-top: 4px !important; 7366 margin-bottom: 4px !important; 7367 padding-top: 0 !important; 7368 padding-bottom: 0 !important; 7369 } 7370 7371 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7372 .color-picker-grid-mode-clean .flex-wrap { 7373 gap: 6px !important; 7374 } 7375 7376 .product-item-photo>span picture, 7377 .product-item-photo>span img { 7378 width: 100% !important; 7379 height: auto !important; 7380 display: block !important; 7381 } 7382 7383 .product-item-photo>span picture { 7384 position: static !important; 7385 } 7386</style> </li> 7387 <li class="flex flex-col"> 7388 7389<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7390 7391 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-vega-color-blanco-mate" class="flex flex-col grow w-full"> 7392 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7393 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-blanco-mate-1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-blanco-mate-1.jpg" width="360" height="360" alt="Aparador modelo Vega cor Carvalho Alba" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7263.window="updateImage" loading="lazy"></picture> 7394 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7395 </div> 7396 7397 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7398 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7399 <strong>Vega</strong> 7400 </div> 7401 7402 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7403 <span class="product-item-link">Aparador modelo Vega color Blanco mate</span> 7404 </div> 7405 7406 7407 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7263.window="updatePrice($event.detail);"> 7408 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7263" data-price-box="product-id-7263"> 7409 <span 7410 x-data x-id="['product\u002Dprice\u002D7263']" class="price-container price-final_price tax weee" 7411 > 7412 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7413 <span class="price"><span class="price">89,00 â¬</span></span> 7414 </span> 7415 7416 <span class="old-price mr-1"> 7417 <span class="price line-through text-gray-600"> 7418 <span class="price"><span class="price">99,00 â¬</span></span> 7419 7420 </span> 7421 </span> 7422 7423 7424 7425 </span> 7426</div></div> 7427 </div> 7428 </div> 7429 </a> 7430 7431 7432 <!-- <div>CATEGORIA: </div> --> 7433 <div class="product-item-variations px-4 py-2 mt-auto"> 7434 <div id="variaciones-listado-7263"> 7435 <div class="color-picker-grid-mode-clean"> 7436 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7437 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7438 Colores Disponibles: 7439 </span> 7440 7441 <div class="flex flex-wrap gap-4 items-center"> 7442 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-vega-color-roble-alba" title="LOLO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #ce9f75;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-vega-color-roble-alba"></div> </div> 7443 </div> 7444 </div> </div> 7445 </div> 7446 <div class="px-4 pb-4"> 7447 7448<div class="mt-1 flex flex-col"> 7449 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7450 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7451 99,00 ⬠</span> 7452 7453 <div class="flex items-baseline gap-1.5"> 7454 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7455 89,00 ⬠</span> 7456 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7457 Precio VIP </span> 7458 </div> 7459 7460 7461 </div> </div> 7462</div> 7463 7464<style> 7465 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7466 .color-picker-grid-mode-clean, 7467 .color-picker-grid-mode-clean>div { 7468 display: flex !important; 7469 flex-direction: row !important; 7470 flex-wrap: wrap !important; 7471 align-items: center !important; 7472 gap: 6px !important; 7473 padding: 0 !important; 7474 margin: 0 !important; 7475 border: none !important; 7476 } 7477 7478 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7479 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7480 .color-picker-grid-mode-clean span.text-sm.font-bold, 7481 .color-picker-grid-mode-clean .w-32 { 7482 display: none !important; 7483 } 7484 7485 /* 3. Ajuste de las "bolitas" de color */ 7486 .color-picker-grid-mode-clean .w-9.h-9 { 7487 width: 22px !important; 7488 /* Tamaño reducido ideal para rejilla */ 7489 height: 22px !important; 7490 min-width: 22px !important; 7491 min-height: 22px !important; 7492 margin: 0 !important; 7493 transform: none !important; 7494 /* Evitamos que el seleccionado crezca y descuadre */ 7495 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7496 } 7497 7498 /* 4. Ajuste del icono Check (V) de selección */ 7499 .color-picker-grid-mode-clean svg { 7500 width: 14px !important; 7501 height: 14px !important; 7502 } 7503 7504 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7505 .product-item-variations { 7506 margin-top: 4px !important; 7507 margin-bottom: 4px !important; 7508 padding-top: 0 !important; 7509 padding-bottom: 0 !important; 7510 } 7511 7512 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7513 .color-picker-grid-mode-clean .flex-wrap { 7514 gap: 6px !important; 7515 } 7516 7517 .product-item-photo>span picture, 7518 .product-item-photo>span img { 7519 width: 100% !important; 7520 height: auto !important; 7521 display: block !important; 7522 } 7523 7524 .product-item-photo>span picture { 7525 position: static !important; 7526 } 7527</style> </li> 7528 <li class="flex flex-col"> 7529 7530<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7531 7532 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-vega-color-roble-alba" class="flex flex-col grow w-full"> 7533 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7534 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-roble-alba-01_1_1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-roble-alba-01_1_1.jpg" width="360" height="360" alt="Aparador modelo Vega color Roble Alba " class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7264.window="updateImage" loading="lazy"></picture> 7535 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7536 </div> 7537 7538 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7539 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7540 <strong>Vega</strong> 7541 </div> 7542 7543 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7544 <span class="product-item-link">Aparador modelo Vega color Roble Alba</span> 7545 </div> 7546 7547 7548 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7264.window="updatePrice($event.detail);"> 7549 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7264" data-price-box="product-id-7264"> 7550 <span 7551 x-data x-id="['product\u002Dprice\u002D7264']" class="price-container price-final_price tax weee" 7552 > 7553 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7554 <span class="price"><span class="price">89,00 â¬</span></span> 7555 </span> 7556 7557 <span class="old-price mr-1"> 7558 <span class="price line-through text-gray-600"> 7559 <span class="price"><span class="price">99,00 â¬</span></span> 7560 7561 </span> 7562 </span> 7563 7564 7565 7566 </span> 7567</div></div> 7568 </div> 7569 </div> 7570 </a> 7571 7572 7573 <!-- <div>CATEGORIA: </div> --> 7574 <div class="product-item-variations px-4 py-2 mt-auto"> 7575 <div id="variaciones-listado-7264"> 7576 <div class="color-picker-grid-mode-clean"> 7577 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7578 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7579 Colores Disponibles: 7580 </span> 7581 7582 <div class="flex flex-wrap gap-4 items-center"> 7583 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-vega-color-blanco-mate" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-vega-color-blanco-mate"></div><div class="relative flex items-center justify-center"><div title="LOLO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #ce9f75;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 7584 </div> 7585 </div> </div> 7586 </div> 7587 <div class="px-4 pb-4"> 7588 7589<div class="mt-1 flex flex-col"> 7590 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7591 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7592 99,00 ⬠</span> 7593 7594 <div class="flex items-baseline gap-1.5"> 7595 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7596 89,00 ⬠</span> 7597 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7598 Precio VIP </span> 7599 </div> 7600 7601 7602 </div> </div> 7603</div> 7604 7605<style> 7606 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7607 .color-picker-grid-mode-clean, 7608 .color-picker-grid-mode-clean>div { 7609 display: flex !important; 7610 flex-direction: row !important; 7611 flex-wrap: wrap !important; 7612 align-items: center !important; 7613 gap: 6px !important; 7614 padding: 0 !important; 7615 margin: 0 !important; 7616 border: none !important; 7617 } 7618 7619 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7620 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7621 .color-picker-grid-mode-clean span.text-sm.font-bold, 7622 .color-picker-grid-mode-clean .w-32 { 7623 display: none !important; 7624 } 7625 7626 /* 3. Ajuste de las "bolitas" de color */ 7627 .color-picker-grid-mode-clean .w-9.h-9 { 7628 width: 22px !important; 7629 /* Tamaño reducido ideal para rejilla */ 7630 height: 22px !important; 7631 min-width: 22px !important; 7632 min-height: 22px !important; 7633 margin: 0 !important; 7634 transform: none !important; 7635 /* Evitamos que el seleccionado crezca y descuadre */ 7636 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7637 } 7638 7639 /* 4. Ajuste del icono Check (V) de selección */ 7640 .color-picker-grid-mode-clean svg { 7641 width: 14px !important; 7642 height: 14px !important; 7643 } 7644 7645 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7646 .product-item-variations { 7647 margin-top: 4px !important; 7648 margin-bottom: 4px !important; 7649 padding-top: 0 !important; 7650 padding-bottom: 0 !important; 7651 } 7652 7653 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7654 .color-picker-grid-mode-clean .flex-wrap { 7655 gap: 6px !important; 7656 } 7657 7658 .product-item-photo>span picture, 7659 .product-item-photo>span img { 7660 width: 100% !important; 7661 height: auto !important; 7662 display: block !important; 7663 } 7664 7665 .product-item-photo>span picture { 7666 position: static !important; 7667 } 7668</style> </li> 7669 <li class="flex flex-col"> 7670 7671<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7672 7673 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-clark-color-blanco-y-sonoma" class="flex flex-col grow w-full"> 7674 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7675 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-clark-color-blanco-y-sonoma-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-clark-color-blanco-y-sonoma-01.jpg" width="360" height="360" alt="Aparador modelo Clark color blanco y sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7265.window="updateImage" loading="lazy"></picture> 7676 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7677 </div> 7678 7679 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7680 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7681 <strong>Clark</strong> 7682 </div> 7683 7684 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7685 <span class="product-item-link">Aparador modelo Clark color blanco y sonoma</span> 7686 </div> 7687 7688 7689 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7265.window="updatePrice($event.detail);"> 7690 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7265" data-price-box="product-id-7265"> 7691 <span 7692 x-data x-id="['product\u002Dprice\u002D7265']" class="price-container price-final_price tax weee" 7693 > 7694 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7695 <span class="price"><span class="price">149,00 â¬</span></span> 7696 </span> 7697 7698 <span class="old-price mr-1"> 7699 <span class="price line-through text-gray-600"> 7700 <span class="price"><span class="price">169,00 â¬</span></span> 7701 7702 </span> 7703 </span> 7704 7705 7706 7707 </span> 7708</div></div> 7709 </div> 7710 </div> 7711 </a> 7712 7713 7714 <!-- <div>CATEGORIA: </div> --> 7715 <div class="product-item-variations px-4 py-2 mt-auto"> 7716 <div id="variaciones-listado-7265"> 7717 <div class="color-picker-grid-mode-clean"> 7718 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7719 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7720 Colores Disponibles: 7721 </span> 7722 7723 <div class="flex flex-wrap gap-4 items-center"> 7724 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-clark-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-clark-color-blanco"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-clark-color-negro" title="BLBL" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #000000;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-clark-color-negro"></div><div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 7725 </div> 7726 </div> </div> 7727 </div> 7728 <div class="px-4 pb-4"> 7729 7730<div class="mt-1 flex flex-col"> 7731 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7732 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7733 169,00 ⬠</span> 7734 7735 <div class="flex items-baseline gap-1.5"> 7736 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7737 149,00 ⬠</span> 7738 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7739 Precio VIP </span> 7740 </div> 7741 7742 7743 </div> </div> 7744</div> 7745 7746<style> 7747 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7748 .color-picker-grid-mode-clean, 7749 .color-picker-grid-mode-clean>div { 7750 display: flex !important; 7751 flex-direction: row !important; 7752 flex-wrap: wrap !important; 7753 align-items: center !important; 7754 gap: 6px !important; 7755 padding: 0 !important; 7756 margin: 0 !important; 7757 border: none !important; 7758 } 7759 7760 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7761 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7762 .color-picker-grid-mode-clean span.text-sm.font-bold, 7763 .color-picker-grid-mode-clean .w-32 { 7764 display: none !important; 7765 } 7766 7767 /* 3. Ajuste de las "bolitas" de color */ 7768 .color-picker-grid-mode-clean .w-9.h-9 { 7769 width: 22px !important; 7770 /* Tamaño reducido ideal para rejilla */ 7771 height: 22px !important; 7772 min-width: 22px !important; 7773 min-height: 22px !important; 7774 margin: 0 !important; 7775 transform: none !important; 7776 /* Evitamos que el seleccionado crezca y descuadre */ 7777 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7778 } 7779 7780 /* 4. Ajuste del icono Check (V) de selección */ 7781 .color-picker-grid-mode-clean svg { 7782 width: 14px !important; 7783 height: 14px !important; 7784 } 7785 7786 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7787 .product-item-variations { 7788 margin-top: 4px !important; 7789 margin-bottom: 4px !important; 7790 padding-top: 0 !important; 7791 padding-bottom: 0 !important; 7792 } 7793 7794 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7795 .color-picker-grid-mode-clean .flex-wrap { 7796 gap: 6px !important; 7797 } 7798 7799 .product-item-photo>span picture, 7800 .product-item-photo>span img { 7801 width: 100% !important; 7802 height: auto !important; 7803 display: block !important; 7804 } 7805 7806 .product-item-photo>span picture { 7807 position: static !important; 7808 } 7809</style> </li> 7810 <li class="flex flex-col"> 7811 7812<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7813 7814 <a href="https://www.mueblesbonitos.com/salon/aparador-modelo-nevada-color-blanco-y-sonoma" class="flex flex-col grow w-full"> 7815 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7816 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-nevada-color-blanco-y-sonoma-1.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-nevada-color-blanco-y-sonoma-1.jpg" width="360" height="360" alt="Aparador modelo Nevada color blanco y sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7266.window="updateImage" loading="lazy"></picture> 7817 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7818 </div> 7819 7820 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7821 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7822 <strong>Nevada</strong> 7823 </div> 7824 7825 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7826 <span class="product-item-link">Aparador modelo Nevada color blanco y sonoma</span> 7827 </div> 7828 7829 7830 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7266.window="updatePrice($event.detail);"> 7831 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7266" data-price-box="product-id-7266"> 7832 <span 7833 x-data x-id="['product\u002Dprice\u002D7266']" class="price-container price-final_price tax weee" 7834 > 7835 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7836 <span class="price"><span class="price">149,00 â¬</span></span> 7837 </span> 7838 7839 <span class="old-price mr-1"> 7840 <span class="price line-through text-gray-600"> 7841 <span class="price"><span class="price">169,00 â¬</span></span> 7842 7843 </span> 7844 </span> 7845 7846 7847 7848 </span> 7849</div></div> 7850 </div> 7851 </div> 7852 </a> 7853 7854 7855 <!-- <div>CATEGORIA: </div> --> 7856 <div class="product-item-variations px-4 py-2 mt-auto"> 7857 <div id="variaciones-listado-7266"> 7858 <div class="color-picker-grid-mode-clean"> 7859 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 7860 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 7861 Colores Disponibles: 7862 </span> 7863 7864 <div class="flex flex-wrap gap-4 items-center"> 7865 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-nevada-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-nevada-color-blanco"></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-modelo-nevada-color-negro" title="BLBL" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #000000;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-modelo-nevada-color-negro"></div><div class="relative flex items-center justify-center"><div title="WHSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background: linear-gradient(135deg, #FFFFFF 50%, #E3C9A6 50%);outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 7866 </div> 7867 </div> </div> 7868 </div> 7869 <div class="px-4 pb-4"> 7870 7871<div class="mt-1 flex flex-col"> 7872 <!-- Invitado: base price + lÃnea VIP (si existe) --> 7873 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 7874 169,00 ⬠</span> 7875 7876 <div class="flex items-baseline gap-1.5"> 7877 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 7878 149,00 ⬠</span> 7879 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 7880 Precio VIP </span> 7881 </div> 7882 7883 7884 </div> </div> 7885</div> 7886 7887<style> 7888 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 7889 .color-picker-grid-mode-clean, 7890 .color-picker-grid-mode-clean>div { 7891 display: flex !important; 7892 flex-direction: row !important; 7893 flex-wrap: wrap !important; 7894 align-items: center !important; 7895 gap: 6px !important; 7896 padding: 0 !important; 7897 margin: 0 !important; 7898 border: none !important; 7899 } 7900 7901 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 7902 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 7903 .color-picker-grid-mode-clean span.text-sm.font-bold, 7904 .color-picker-grid-mode-clean .w-32 { 7905 display: none !important; 7906 } 7907 7908 /* 3. Ajuste de las "bolitas" de color */ 7909 .color-picker-grid-mode-clean .w-9.h-9 { 7910 width: 22px !important; 7911 /* Tamaño reducido ideal para rejilla */ 7912 height: 22px !important; 7913 min-width: 22px !important; 7914 min-height: 22px !important; 7915 margin: 0 !important; 7916 transform: none !important; 7917 /* Evitamos que el seleccionado crezca y descuadre */ 7918 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 7919 } 7920 7921 /* 4. Ajuste del icono Check (V) de selección */ 7922 .color-picker-grid-mode-clean svg { 7923 width: 14px !important; 7924 height: 14px !important; 7925 } 7926 7927 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 7928 .product-item-variations { 7929 margin-top: 4px !important; 7930 margin-bottom: 4px !important; 7931 padding-top: 0 !important; 7932 padding-bottom: 0 !important; 7933 } 7934 7935 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 7936 .color-picker-grid-mode-clean .flex-wrap { 7937 gap: 6px !important; 7938 } 7939 7940 .product-item-photo>span picture, 7941 .product-item-photo>span img { 7942 width: 100% !important; 7943 height: auto !important; 7944 display: block !important; 7945 } 7946 7947 .product-item-photo>span picture { 7948 position: static !important; 7949 } 7950</style> </li> 7951 <li class="flex flex-col"> 7952 7953<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 7954 7955 <a href="https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-2-puertas-color-blanco" class="flex flex-col grow w-full"> 7956 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 7957 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-blanco-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-blanco-01.jpg" width="360" height="360" alt="Aparador acanalado modelo Logan 2 puertas color Blanco" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7267.window="updateImage" loading="lazy"></picture> 7958 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 7959 </div> 7960 7961 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 7962 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 7963 <strong>Logan</strong> 7964 </div> 7965 7966 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
7967 <span class="product-item-link">Aparador acanalado modelo Logan 2 puertas color Blanco</span> 7968 </div> 7969 7970 7971 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7267.window="updatePrice($event.detail);"> 7972 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7267" data-price-box="product-id-7267"> 7973 <span 7974 x-data x-id="['product\u002Dprice\u002D7267']" class="price-container price-final_price tax weee" 7975 > 7976 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 7977 <span class="price"><span class="price">129,00 â¬</span></span> 7978 </span> 7979 7980 <span class="old-price mr-1"> 7981 <span class="price line-through text-gray-600"> 7982 <span class="price"><span class="price">139,00 â¬</span></span> 7983 7984 </span> 7985 </span> 7986 7987 7988 7989 </span> 7990</div></div> 7991 </div> 7992 </div> 7993 </a> 7994 7995 7996 <!-- <div>CATEGORIA: </div> --> 7997 <div class="product-item-variations px-4 py-2 mt-auto"> 7998 <div id="variaciones-listado-7267"> 7999 <div class="color-picker-grid-mode-clean"> 8000 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8001 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8002 Colores Disponibles: 8003 </span> 8004 8005 <div class="flex flex-wrap gap-4 items-center"> 8006 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-2-puertas-color-sonoma" title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-2-puertas-color-sonoma"></div> </div> 8007 </div> 8008 </div> </div> 8009 </div> 8010 <div class="px-4 pb-4"> 8011 8012<div class="mt-1 flex flex-col"> 8013 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8014 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8015 139,00 ⬠</span> 8016 8017 <div class="flex items-baseline gap-1.5"> 8018 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8019 129,00 ⬠</span> 8020 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8021 Precio VIP </span> 8022 </div> 8023 8024 8025 </div> </div> 8026</div> 8027 8028<style> 8029 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8030 .color-picker-grid-mode-clean, 8031 .color-picker-grid-mode-clean>div { 8032 display: flex !important; 8033 flex-direction: row !important; 8034 flex-wrap: wrap !important; 8035 align-items: center !important; 8036 gap: 6px !important; 8037 padding: 0 !important; 8038 margin: 0 !important; 8039 border: none !important; 8040 } 8041 8042 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8043 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8044 .color-picker-grid-mode-clean span.text-sm.font-bold, 8045 .color-picker-grid-mode-clean .w-32 { 8046 display: none !important; 8047 } 8048 8049 /* 3. Ajuste de las "bolitas" de color */ 8050 .color-picker-grid-mode-clean .w-9.h-9 { 8051 width: 22px !important; 8052 /* Tamaño reducido ideal para rejilla */ 8053 height: 22px !important; 8054 min-width: 22px !important; 8055 min-height: 22px !important; 8056 margin: 0 !important; 8057 transform: none !important; 8058 /* Evitamos que el seleccionado crezca y descuadre */ 8059 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8060 } 8061 8062 /* 4. Ajuste del icono Check (V) de selección */ 8063 .color-picker-grid-mode-clean svg { 8064 width: 14px !important; 8065 height: 14px !important; 8066 } 8067 8068 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8069 .product-item-variations { 8070 margin-top: 4px !important; 8071 margin-bottom: 4px !important; 8072 padding-top: 0 !important; 8073 padding-bottom: 0 !important; 8074 } 8075 8076 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8077 .color-picker-grid-mode-clean .flex-wrap { 8078 gap: 6px !important; 8079 } 8080 8081 .product-item-photo>span picture, 8082 .product-item-photo>span img { 8083 width: 100% !important; 8084 height: auto !important; 8085 display: block !important; 8086 } 8087 8088 .product-item-photo>span picture { 8089 position: static !important; 8090 } 8091</style> </li> 8092 <li class="flex flex-col"> 8093 8094<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8095 8096 <a href="https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-2-puertas-color-sonoma" class="flex flex-col grow w-full"> 8097 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8098 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-sonoma-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-sonoma-01.jpg" width="360" height="360" alt="Aparador acanalado modelo Logan 2 puertas color Sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7268.window="updateImage" loading="lazy"></picture> 8099 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8100 </div> 8101 8102 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8103 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8104 <strong>Logan</strong> 8105 </div> 8106 8107 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8108 <span class="product-item-link">Aparador acanalado modelo Logan 2 puertas color Sonoma</span> 8109 </div> 8110 8111 8112 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7268.window="updatePrice($event.detail);"> 8113 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7268" data-price-box="product-id-7268"> 8114 <span 8115 x-data x-id="['product\u002Dprice\u002D7268']" class="price-container price-final_price tax weee" 8116 > 8117 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8118 <span class="price"><span class="price">129,00 â¬</span></span> 8119 </span> 8120 8121 <span class="old-price mr-1"> 8122 <span class="price line-through text-gray-600"> 8123 <span class="price"><span class="price">139,00 â¬</span></span> 8124 8125 </span> 8126 </span> 8127 8128 8129 8130 </span> 8131</div></div> 8132 </div> 8133 </div> 8134 </a> 8135 8136 8137 <!-- <div>CATEGORIA: </div> --> 8138 <div class="product-item-variations px-4 py-2 mt-auto"> 8139 <div id="variaciones-listado-7268"> 8140 <div class="color-picker-grid-mode-clean"> 8141 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8142 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8143 Colores Disponibles: 8144 </span> 8145 8146 <div class="flex flex-wrap gap-4 items-center"> 8147 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-2-puertas-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-2-puertas-color-blanco"></div><div class="relative flex items-center justify-center"><div title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 8148 </div> 8149 </div> </div> 8150 </div> 8151 <div class="px-4 pb-4"> 8152 8153<div class="mt-1 flex flex-col"> 8154 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8155 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8156 139,00 ⬠</span> 8157 8158 <div class="flex items-baseline gap-1.5"> 8159 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8160 129,00 ⬠</span> 8161 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8162 Precio VIP </span> 8163 </div> 8164 8165 8166 </div> </div> 8167</div> 8168 8169<style> 8170 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8171 .color-picker-grid-mode-clean, 8172 .color-picker-grid-mode-clean>div { 8173 display: flex !important; 8174 flex-direction: row !important; 8175 flex-wrap: wrap !important; 8176 align-items: center !important; 8177 gap: 6px !important; 8178 padding: 0 !important; 8179 margin: 0 !important; 8180 border: none !important; 8181 } 8182 8183 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8184 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8185 .color-picker-grid-mode-clean span.text-sm.font-bold, 8186 .color-picker-grid-mode-clean .w-32 { 8187 display: none !important; 8188 } 8189 8190 /* 3. Ajuste de las "bolitas" de color */ 8191 .color-picker-grid-mode-clean .w-9.h-9 { 8192 width: 22px !important; 8193 /* Tamaño reducido ideal para rejilla */ 8194 height: 22px !important; 8195 min-width: 22px !important; 8196 min-height: 22px !important; 8197 margin: 0 !important; 8198 transform: none !important; 8199 /* Evitamos que el seleccionado crezca y descuadre */ 8200 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8201 } 8202 8203 /* 4. Ajuste del icono Check (V) de selección */ 8204 .color-picker-grid-mode-clean svg { 8205 width: 14px !important; 8206 height: 14px !important; 8207 } 8208 8209 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8210 .product-item-variations { 8211 margin-top: 4px !important; 8212 margin-bottom: 4px !important; 8213 padding-top: 0 !important; 8214 padding-bottom: 0 !important; 8215 } 8216 8217 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8218 .color-picker-grid-mode-clean .flex-wrap { 8219 gap: 6px !important; 8220 } 8221 8222 .product-item-photo>span picture, 8223 .product-item-photo>span img { 8224 width: 100% !important; 8225 height: auto !important; 8226 display: block !important; 8227 } 8228 8229 .product-item-photo>span picture { 8230 position: static !important; 8231 } 8232</style> </li> 8233 <li class="flex flex-col"> 8234 8235<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8236 8237 <a href="https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-3-puertas-color-blanco" class="flex flex-col grow w-full"> 8238 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8239 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-blanco-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-blanco-01.jpg" width="360" height="360" alt="Aparador acanalado modelo Logan 3 puertas color Blanco" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7269.window="updateImage" loading="lazy"></picture> 8240 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8241 </div> 8242 8243 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8244 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8245 <strong>Logan</strong> 8246 </div> 8247 8248 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8249 <span class="product-item-link">Aparador acanalado modelo Logan 3 puertas color Blanco</span> 8250 </div> 8251 8252 8253 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7269.window="updatePrice($event.detail);"> 8254 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7269" data-price-box="product-id-7269"> 8255 <span 8256 x-data x-id="['product\u002Dprice\u002D7269']" class="price-container price-final_price tax weee" 8257 > 8258 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8259 <span class="price"><span class="price">169,00 â¬</span></span> 8260 </span> 8261 8262 <span class="old-price mr-1"> 8263 <span class="price line-through text-gray-600"> 8264 <span class="price"><span class="price">189,00 â¬</span></span> 8265 8266 </span> 8267 </span> 8268 8269 8270 8271 </span> 8272</div></div> 8273 </div> 8274 </div> 8275 </a> 8276 8277 8278 <!-- <div>CATEGORIA: </div> --> 8279 <div class="product-item-variations px-4 py-2 mt-auto"> 8280 <div id="variaciones-listado-7269"> 8281 <div class="color-picker-grid-mode-clean"> 8282 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8283 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8284 Colores Disponibles: 8285 </span> 8286 8287 <div class="flex flex-wrap gap-4 items-center"> 8288 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-3-puertas-color-sonoma" title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-3-puertas-color-sonoma"></div> </div> 8289 </div> 8290 </div> </div> 8291 </div> 8292 <div class="px-4 pb-4"> 8293 8294<div class="mt-1 flex flex-col"> 8295 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8296 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8297 189,00 ⬠</span> 8298 8299 <div class="flex items-baseline gap-1.5"> 8300 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8301 169,00 ⬠</span> 8302 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8303 Precio VIP </span> 8304 </div> 8305 8306 8307 </div> </div> 8308</div> 8309 8310<style> 8311 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8312 .color-picker-grid-mode-clean, 8313 .color-picker-grid-mode-clean>div { 8314 display: flex !important; 8315 flex-direction: row !important; 8316 flex-wrap: wrap !important; 8317 align-items: center !important; 8318 gap: 6px !important; 8319 padding: 0 !important; 8320 margin: 0 !important; 8321 border: none !important; 8322 } 8323 8324 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8325 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8326 .color-picker-grid-mode-clean span.text-sm.font-bold, 8327 .color-picker-grid-mode-clean .w-32 { 8328 display: none !important; 8329 } 8330 8331 /* 3. Ajuste de las "bolitas" de color */ 8332 .color-picker-grid-mode-clean .w-9.h-9 { 8333 width: 22px !important; 8334 /* Tamaño reducido ideal para rejilla */ 8335 height: 22px !important; 8336 min-width: 22px !important; 8337 min-height: 22px !important; 8338 margin: 0 !important; 8339 transform: none !important; 8340 /* Evitamos que el seleccionado crezca y descuadre */ 8341 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8342 } 8343 8344 /* 4. Ajuste del icono Check (V) de selección */ 8345 .color-picker-grid-mode-clean svg { 8346 width: 14px !important; 8347 height: 14px !important; 8348 } 8349 8350 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8351 .product-item-variations { 8352 margin-top: 4px !important; 8353 margin-bottom: 4px !important; 8354 padding-top: 0 !important; 8355 padding-bottom: 0 !important; 8356 } 8357 8358 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8359 .color-picker-grid-mode-clean .flex-wrap { 8360 gap: 6px !important; 8361 } 8362 8363 .product-item-photo>span picture, 8364 .product-item-photo>span img { 8365 width: 100% !important; 8366 height: auto !important; 8367 display: block !important; 8368 } 8369 8370 .product-item-photo>span picture { 8371 position: static !important; 8372 } 8373</style> </li> 8374 <li class="flex flex-col"> 8375 8376<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8377 8378 <a href="https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-3-puertas-color-sonoma" class="flex flex-col grow w-full"> 8379 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8380 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-sonoma-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-sonoma-01.jpg" width="360" height="360" alt="Aparador acanalado modelo Logan 3 puertas color Sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7270.window="updateImage" loading="lazy"></picture> 8381 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8382 </div> 8383 8384 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8385 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8386 <strong>Logan</strong> 8387 </div> 8388 8389 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8390 <span class="product-item-link">Aparador acanalado modelo Logan 3 puertas color Sonoma</span> 8391 </div> 8392 8393 8394 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7270.window="updatePrice($event.detail);"> 8395 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7270" data-price-box="product-id-7270"> 8396 <span 8397 x-data x-id="['product\u002Dprice\u002D7270']" class="price-container price-final_price tax weee" 8398 > 8399 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8400 <span class="price"><span class="price">169,00 â¬</span></span> 8401 </span> 8402 8403 <span class="old-price mr-1"> 8404 <span class="price line-through text-gray-600"> 8405 <span class="price"><span class="price">189,00 â¬</span></span> 8406 8407 </span> 8408 </span> 8409 8410 8411 8412 </span> 8413</div></div> 8414 </div> 8415 </div> 8416 </a> 8417 8418 8419 <!-- <div>CATEGORIA: </div> --> 8420 <div class="product-item-variations px-4 py-2 mt-auto"> 8421 <div id="variaciones-listado-7270"> 8422 <div class="color-picker-grid-mode-clean"> 8423 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8424 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8425 Colores Disponibles: 8426 </span> 8427 8428 <div class="flex flex-wrap gap-4 items-center"> 8429 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-3-puertas-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-acanalado-modelo-logan-3-puertas-color-blanco"></div><div class="relative flex items-center justify-center"><div title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 8430 </div> 8431 </div> </div> 8432 </div> 8433 <div class="px-4 pb-4"> 8434 8435<div class="mt-1 flex flex-col"> 8436 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8437 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8438 189,00 ⬠</span> 8439 8440 <div class="flex items-baseline gap-1.5"> 8441 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8442 169,00 ⬠</span> 8443 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8444 Precio VIP </span> 8445 </div> 8446 8447 8448 </div> </div> 8449</div> 8450 8451<style> 8452 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8453 .color-picker-grid-mode-clean, 8454 .color-picker-grid-mode-clean>div { 8455 display: flex !important; 8456 flex-direction: row !important; 8457 flex-wrap: wrap !important; 8458 align-items: center !important; 8459 gap: 6px !important; 8460 padding: 0 !important; 8461 margin: 0 !important; 8462 border: none !important; 8463 } 8464 8465 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8466 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8467 .color-picker-grid-mode-clean span.text-sm.font-bold, 8468 .color-picker-grid-mode-clean .w-32 { 8469 display: none !important; 8470 } 8471 8472 /* 3. Ajuste de las "bolitas" de color */ 8473 .color-picker-grid-mode-clean .w-9.h-9 { 8474 width: 22px !important; 8475 /* Tamaño reducido ideal para rejilla */ 8476 height: 22px !important; 8477 min-width: 22px !important; 8478 min-height: 22px !important; 8479 margin: 0 !important; 8480 transform: none !important; 8481 /* Evitamos que el seleccionado crezca y descuadre */ 8482 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8483 } 8484 8485 /* 4. Ajuste del icono Check (V) de selección */ 8486 .color-picker-grid-mode-clean svg { 8487 width: 14px !important; 8488 height: 14px !important; 8489 } 8490 8491 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8492 .product-item-variations { 8493 margin-top: 4px !important; 8494 margin-bottom: 4px !important; 8495 padding-top: 0 !important; 8496 padding-bottom: 0 !important; 8497 } 8498 8499 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8500 .color-picker-grid-mode-clean .flex-wrap { 8501 gap: 6px !important; 8502 } 8503 8504 .product-item-photo>span picture, 8505 .product-item-photo>span img { 8506 width: 100% !important; 8507 height: auto !important; 8508 display: block !important; 8509 } 8510 8511 .product-item-photo>span picture { 8512 position: static !important; 8513 } 8514</style> </li> 8515 <li class="flex flex-col"> 8516 8517<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8518 8519 <a href="https://www.mueblesbonitos.com/salon/mueble-tv-acanalado-modelo-logan-color-blanco" class="flex flex-col grow w-full"> 8520 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8521 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-blanco-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-blanco-01.jpg" width="360" height="360" alt="Mueble TV acanalado modelo Logan color Blanco
" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7271.window="updateImage" loading="lazy"></picture> 8522 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8523 </div> 8524 8525 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8526 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8527 <strong>Logan</strong> 8528 </div> 8529 8530 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8531 <span class="product-item-link">Mueble TV acanalado modelo Logan color Blanco</span> 8532 </div> 8533 8534 8535 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7271.window="updatePrice($event.detail);"> 8536 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7271" data-price-box="product-id-7271"> 8537 <span 8538 x-data x-id="['product\u002Dprice\u002D7271']" class="price-container price-final_price tax weee" 8539 > 8540 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8541 <span class="price"><span class="price">109,00 â¬</span></span> 8542 </span> 8543 8544 <span class="old-price mr-1"> 8545 <span class="price line-through text-gray-600"> 8546 <span class="price"><span class="price">119,00 â¬</span></span> 8547 8548 </span> 8549 </span> 8550 8551 8552 8553 </span> 8554</div></div> 8555 </div> 8556 </div> 8557 </a> 8558 8559 8560 <!-- <div>CATEGORIA: </div> --> 8561 <div class="product-item-variations px-4 py-2 mt-auto"> 8562 <div id="variaciones-listado-7271"> 8563 <div class="color-picker-grid-mode-clean"> 8564 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8565 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8566 Colores Disponibles: 8567 </span> 8568 8569 <div class="flex flex-wrap gap-4 items-center"> 8570 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mueble-tv-acanalado-modelo-logan-color-sonoma" title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mueble-tv-acanalado-modelo-logan-color-sonoma"></div> </div> 8571 </div> 8572 </div> </div> 8573 </div> 8574 <div class="px-4 pb-4"> 8575 8576<div class="mt-1 flex flex-col"> 8577 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8578 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8579 119,00 ⬠</span> 8580 8581 <div class="flex items-baseline gap-1.5"> 8582 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8583 109,00 ⬠</span> 8584 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8585 Precio VIP </span> 8586 </div> 8587 8588 8589 </div> </div> 8590</div> 8591 8592<style> 8593 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8594 .color-picker-grid-mode-clean, 8595 .color-picker-grid-mode-clean>div { 8596 display: flex !important; 8597 flex-direction: row !important; 8598 flex-wrap: wrap !important; 8599 align-items: center !important; 8600 gap: 6px !important; 8601 padding: 0 !important; 8602 margin: 0 !important; 8603 border: none !important; 8604 } 8605 8606 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8607 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8608 .color-picker-grid-mode-clean span.text-sm.font-bold, 8609 .color-picker-grid-mode-clean .w-32 { 8610 display: none !important; 8611 } 8612 8613 /* 3. Ajuste de las "bolitas" de color */ 8614 .color-picker-grid-mode-clean .w-9.h-9 { 8615 width: 22px !important; 8616 /* Tamaño reducido ideal para rejilla */ 8617 height: 22px !important; 8618 min-width: 22px !important; 8619 min-height: 22px !important; 8620 margin: 0 !important; 8621 transform: none !important; 8622 /* Evitamos que el seleccionado crezca y descuadre */ 8623 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8624 } 8625 8626 /* 4. Ajuste del icono Check (V) de selección */ 8627 .color-picker-grid-mode-clean svg { 8628 width: 14px !important; 8629 height: 14px !important; 8630 } 8631 8632 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8633 .product-item-variations { 8634 margin-top: 4px !important; 8635 margin-bottom: 4px !important; 8636 padding-top: 0 !important; 8637 padding-bottom: 0 !important; 8638 } 8639 8640 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8641 .color-picker-grid-mode-clean .flex-wrap { 8642 gap: 6px !important; 8643 } 8644 8645 .product-item-photo>span picture, 8646 .product-item-photo>span img { 8647 width: 100% !important; 8648 height: auto !important; 8649 display: block !important; 8650 } 8651 8652 .product-item-photo>span picture { 8653 position: static !important; 8654 } 8655</style> </li> 8656 <li class="flex flex-col"> 8657 8658<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8659 8660 <a href="https://www.mueblesbonitos.com/salon/mueble-tv-acanalado-modelo-logan-color-sonoma" class="flex flex-col grow w-full"> 8661 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8662 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-sonoma-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-sonoma-01.jpg" width="360" height="360" alt="Mueble TV acanalado modelo Logan color Sonoma" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7272.window="updateImage" loading="lazy"></picture> 8663 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8664 </div> 8665 8666 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8667 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8668 <strong>Logan</strong> 8669 </div> 8670 8671 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8672 <span class="product-item-link">Mueble TV acanalado modelo Logan color Sonoma</span> 8673 </div> 8674 8675 8676 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7272.window="updatePrice($event.detail);"> 8677 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7272" data-price-box="product-id-7272"> 8678 <span 8679 x-data x-id="['product\u002Dprice\u002D7272']" class="price-container price-final_price tax weee" 8680 > 8681 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8682 <span class="price"><span class="price">109,00 â¬</span></span> 8683 </span> 8684 8685 <span class="old-price mr-1"> 8686 <span class="price line-through text-gray-600"> 8687 <span class="price"><span class="price">119,00 â¬</span></span> 8688 8689 </span> 8690 </span> 8691 8692 8693 8694 </span> 8695</div></div> 8696 </div> 8697 </div> 8698 </a> 8699 8700 8701 <!-- <div>CATEGORIA: </div> --> 8702 <div class="product-item-variations px-4 py-2 mt-auto"> 8703 <div id="variaciones-listado-7272"> 8704 <div class="color-picker-grid-mode-clean"> 8705 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8706 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8707 Colores Disponibles: 8708 </span> 8709 8710 <div class="flex flex-wrap gap-4 items-center"> 8711 <div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/mueble-tv-acanalado-modelo-logan-color-blanco" title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/mueble-tv-acanalado-modelo-logan-color-blanco"></div><div class="relative flex items-center justify-center"><div title="SOSO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #E3C9A6;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #FFF" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div> </div> 8712 </div> 8713 </div> </div> 8714 </div> 8715 <div class="px-4 pb-4"> 8716 8717<div class="mt-1 flex flex-col"> 8718 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8719 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8720 119,00 ⬠</span> 8721 8722 <div class="flex items-baseline gap-1.5"> 8723 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8724 109,00 ⬠</span> 8725 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8726 Precio VIP </span> 8727 </div> 8728 8729 8730 </div> </div> 8731</div> 8732 8733<style> 8734 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8735 .color-picker-grid-mode-clean, 8736 .color-picker-grid-mode-clean>div { 8737 display: flex !important; 8738 flex-direction: row !important; 8739 flex-wrap: wrap !important; 8740 align-items: center !important; 8741 gap: 6px !important; 8742 padding: 0 !important; 8743 margin: 0 !important; 8744 border: none !important; 8745 } 8746 8747 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8748 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8749 .color-picker-grid-mode-clean span.text-sm.font-bold, 8750 .color-picker-grid-mode-clean .w-32 { 8751 display: none !important; 8752 } 8753 8754 /* 3. Ajuste de las "bolitas" de color */ 8755 .color-picker-grid-mode-clean .w-9.h-9 { 8756 width: 22px !important; 8757 /* Tamaño reducido ideal para rejilla */ 8758 height: 22px !important; 8759 min-width: 22px !important; 8760 min-height: 22px !important; 8761 margin: 0 !important; 8762 transform: none !important; 8763 /* Evitamos que el seleccionado crezca y descuadre */ 8764 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8765 } 8766 8767 /* 4. Ajuste del icono Check (V) de selección */ 8768 .color-picker-grid-mode-clean svg { 8769 width: 14px !important; 8770 height: 14px !important; 8771 } 8772 8773 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8774 .product-item-variations { 8775 margin-top: 4px !important; 8776 margin-bottom: 4px !important; 8777 padding-top: 0 !important; 8778 padding-bottom: 0 !important; 8779 } 8780 8781 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8782 .color-picker-grid-mode-clean .flex-wrap { 8783 gap: 6px !important; 8784 } 8785 8786 .product-item-photo>span picture, 8787 .product-item-photo>span img { 8788 width: 100% !important; 8789 height: auto !important; 8790 display: block !important; 8791 } 8792 8793 .product-item-photo>span picture { 8794 position: static !important; 8795 } 8796</style> </li> 8797 <li class="flex flex-col"> 8798 8799<div class="item product product-item product_addtocart_form card card-interactive flex flex-col w-full grow border border-gray-100 shadow-sm hover:shadow-md transition-shadow duration-300 bg-white rounded-md overflow-hidden"> 8800 8801 <a href="https://www.mueblesbonitos.com/salon/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-blanco" class="flex flex-col grow w-full"> 8802 <div class="product photo product-item-photo w-full relative overflow-hidden z-0" tabindex="-1"> 8803 <picture class="product-image-photo"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-blanco-01.webp"><img src="https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-blanco-01.jpg" width="360" height="360" alt="
Aparador Acanalado Renzo M de 1 Puerta y Cajonera - Blanco" class="product-image-photo" loading="lazy" x-data="initProductItemImage" @update-gallery-7273.window="updateImage" loading="lazy"></picture> 8804 <!-- BLOQUE DEL DESCUENTO BADGE SUPERPUESTO --> 8805 </div> 8806 8807 <div class="product-info flex flex-col grow p-4 pb-0 text-left"> 8808 <div class="mt-2 mb-1 text-primary font-semibold text-xl"> 8809 <strong>Renzo</strong> 8810 </div> 8811 8812 <div class="mt-1 mb-1 text-primary text-texto font-semibold leading-tight">
8813 <span class="product-item-link">â¨Aparador Acanalado Renzo M de 1 Puerta y Cajonera - Blanco</span> 8814 </div> 8815 8816 8817 <div class="pt-2 flex justify-start items-center" x-data="initPriceBox()" x-defer="intersect" @update-prices-7273.window="updatePrice($event.detail);"> 8818 <div><div class="price-box price-final_price" data-role="priceBox" data-product-id="7273" data-price-box="product-id-7273"> 8819 <span 8820 x-data x-id="['product\u002Dprice\u002D7273']" class="price-container price-final_price tax weee" 8821 > 8822 <span class="price-wrapper text-3xl text-gray-900 font-semibold"> 8823 <span class="price"><span class="price">139,00 â¬</span></span> 8824 </span> 8825 8826 <span class="old-price mr-1"> 8827 <span class="price line-through text-gray-600"> 8828 <span class="price"><span class="price">149,00 â¬</span></span> 8829 8830 </span> 8831 </span> 8832 8833 8834 8835 </span> 8836</div></div> 8837 </div> 8838 </div> 8839 </a> 8840 8841 8842 <!-- <div>CATEGORIA: </div> --> 8843 <div class="product-item-variations px-4 py-2 mt-auto"> 8844 <div id="variaciones-listado-7273"> 8845 <div class="color-picker-grid-mode-clean"> 8846 <div class="flex flex-col md:flex-row md:items-center py-4 border-b border-gray-100 last:border-0"> 8847 <span class="text-xl font-bold text-gray-800 md:w-auto md:min-w-max mr-4 whitespace-nowrap mb-2 md:mb-0"> 8848 Colores Disponibles: 8849 </span> 8850 8851 <div class="flex flex-wrap gap-4 items-center"> 8852 <div class="relative flex items-center justify-center"><div title="WHWH" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #FFFFFF;outline: 2px solid #000; outline-offset: 2px; transform: scale(1.15); z-index: 10;"><svg class="w-5 h-5 drop-shadow-md" style="color: #000" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path></svg></div></div><div class="relative flex items-center justify-center"><a href="https://www.mueblesbonitos.com/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-roble-alba" title="LOLO" class="w-9 h-9 rounded-full shadow-sm transition-all duration-200 flex items-center justify-center" style="background-color: #ce9f75;border: 1px solid #e5e7eb;"></a href="https://www.mueblesbonitos.com/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-roble-alba"></div> </div> 8853 </div> 8854 </div> </div> 8855 </div> 8856 <div class="px-4 pb-4"> 8857 8858<div class="mt-1 flex flex-col"> 8859 <!-- Invitado: base price + lÃnea VIP (si existe) --> 8860 <span class="text-base md:text-base font-semibold text-gray-400 leading-tight"> 8861 149,00 ⬠</span> 8862 8863 <div class="flex items-baseline gap-1.5"> 8864 <span class="text-3xl md:text-3xl font-bold leading-tight" style="color: #34515E;"> 8865 139,00 ⬠</span> 8866 <span class="text-[11px] md:text-xs font-semibold" style="color: #8cc4b2;"> 8867 Precio VIP </span> 8868 </div> 8869 8870 8871 </div> </div> 8872</div> 8873 8874<style> 8875 /* 1. Contenedor principal: Alineación horizontal y sin espacios extra */ 8876 .color-picker-grid-mode-clean, 8877 .color-picker-grid-mode-clean>div { 8878 display: flex !important; 8879 flex-direction: row !important; 8880 flex-wrap: wrap !important; 8881 align-items: center !important; 8882 gap: 6px !important; 8883 padding: 0 !important; 8884 margin: 0 !important; 8885 border: none !important; 8886 } 8887 8888 /* 2. Ocultar el texto "Colores:" (o Couleurs, Colori, etc.) */ 8889 /* El método renderSection imprime un span con el tÃtulo, lo eliminamos */ 8890 .color-picker-grid-mode-clean span.text-sm.font-bold, 8891 .color-picker-grid-mode-clean .w-32 { 8892 display: none !important; 8893 } 8894 8895 /* 3. Ajuste de las "bolitas" de color */ 8896 .color-picker-grid-mode-clean .w-9.h-9 { 8897 width: 22px !important; 8898 /* Tamaño reducido ideal para rejilla */ 8899 height: 22px !important; 8900 min-width: 22px !important; 8901 min-height: 22px !important; 8902 margin: 0 !important; 8903 transform: none !important; 8904 /* Evitamos que el seleccionado crezca y descuadre */ 8905 box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); 8906 } 8907 8908 /* 4. Ajuste del icono Check (V) de selección */ 8909 .color-picker-grid-mode-clean svg { 8910 width: 14px !important; 8911 height: 14px !important; 8912 } 8913 8914 /* 5. Aseguramos que el contenedor de variaciones no empuje el precio */ 8915 .product-item-variations { 8916 margin-top: 4px !important; 8917 margin-bottom: 4px !important; 8918 padding-top: 0 !important; 8919 padding-bottom: 0 !important; 8920 } 8921 8922 /* 6. Espaciado interno de los grupos (por si acaso el helper mete gaps) */ 8923 .color-picker-grid-mode-clean .flex-wrap { 8924 gap: 6px !important; 8925 } 8926 8927 .product-item-photo>span picture, 8928 .product-item-photo>span img { 8929 width: 100% !important; 8930 height: auto !important; 8931 display: block !important; 8932 } 8933 8934 .product-item-photo>span picture { 8935 position: static !important; 8936 } 8937</style> </li> 8938 </ul> 8939 </div> 8940
8940<script> 8941 function initToolbar_6ac74549b01a6() { 8942 return { 8943 options: {"productListToolbarForm":{"mode":"product_list_mode","direction":"product_list_dir","order":"product_list_order","limit":"product_list_limit","modeDefault":"grid","directionDefault":"asc","orderDefault":"position","limitDefault":36,"url":"https:\/\/www.mueblesbonitos.com\/salon","formKey":"GoQ6wnK4Gflfjncs","post":false,"page":"p"}}.productListToolbarForm || {}, 8944 getUrlParams: function () { 8945 let decode = window.decodeURIComponent, 8946 urlPaths = this.options.url.split('?'), 8947 urlParams = urlPaths[1] ? urlPaths[1].split('&') : [], 8948 params = {}, 8949 parameters, i; 8950 8951 for (i = 0; i < urlParams.length; i++) { 8952 parameters = urlParams[i].split('='); 8953 params[decode(parameters[0])] = parameters[1] !== undefined ? 8954 decode(parameters[1].replace(/\+/g, '%20')) : 8955 ''; 8956 } 8957 8958 return params; 8959 }, 8960 getCurrentLimit: function () { 8961 return this.getUrlParams()[this.options.limit] || this.options.limitDefault; 8962 }, 8963 getCurrentPage: function () { 8964 return this.getUrlParams()[this.options.page] || 1; 8965 }, 8966 changeUrl(paramName, paramValue, defaultValue) { 8967 let urlPaths = this.options.url.split('?'), 8968 baseUrl = urlPaths[0], 8969 paramData = this.getUrlParams(), 8970 currentPage = this.getCurrentPage(), 8971 newPage; 8972 8973 /** 8974 * calculates the page on which the first item of the current page will 8975 * be with the new limit and sets that number as the new page 8976 */ 8977 if (currentPage > 1 && paramName === this.options.limit) { 8978 newPage = Math.floor(this.getCurrentLimit() * (currentPage - 1) / paramValue) + 1; 8979 8980 if (newPage > 1) { 8981 paramData[this.options.page] = newPage; 8982 } else { 8983 delete paramData[this.options.page]; 8984 } 8985 } 8986 8987 paramData[paramName] = paramValue; 8988 8989 if (this.options.post) { 8990 hyva.postForm({action: baseUrl, data: paramData, skipUenc: true}); 8991 } else { 8992 if (paramValue === defaultValue.toString()) { 8993 delete paramData[paramName]; 8994 } 8995 paramData = Object.keys(paramData).length === 0 8996 ? '' 8997 : '?' + (new URLSearchParams(paramData)); 8998 location.href = baseUrl + paramData 8999 } 9000 } 9001 } 9002 } 9003</script>
9003 9004 <div x-data="initToolbar_6ac74549b01a6()" 9005 class="toolbar toolbar-products grid grid-cols-4 sm:grid-cols-8 md:grid-cols-4 9006 lg:grid-cols-8 grid-flow-row gap-2 items-center"> 9007 <p class="toolbar-amount text-sm leading-5 text-gray-700 order-3 sm:order-2 md:order-3 9008 lg:order-2 col-span-2 gap-x-1" id="toolbar-amount"> 9009 Productos <span class="toolbar-number">1</span>-<span class="toolbar-number">36</span> of <span class="toolbar-number">377</span> </p> 9010 9011 9012 9013 <div class="flex justify-center order-2 col-span-4"> 9014 <nav class="inline-flex items-center pages" aria-label="pagination"> 9015 <ol class="relative z-0 inline-flex shadow-sm items pages-items"> 9016 <li class="item pages-item-previous"> 9017 <a 9018 role="link" 9019 class="previous relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 rounded-l-md px-3 py-2 text-gray-400 9020 border-gray-200" 9021 aria-disabled="true" 9022 aria-label="Anterior" 9023 > 9024 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20" aria-hidden="true"> 9025 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 9026</svg> 9027 </a> 9028 </li> 9029 9030 9031 9032 <li class="item -ml-px"> 9033 <a 9034 href="https://www.mueblesbonitos.com/salon" 9035 class="page relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 z-10 px-4 py-2 text-gray-700 bg-gray-100 border-primary" 9036 aria-current="page" 9037 > 9038 <span class="sr-only label"> 9039 You're currently reading page </span> 9040 1 </a> 9041 </li> 9042 <li class="item -ml-px"> 9043 <a 9044 href="https://www.mueblesbonitos.com/salon?p=2" 9045 class="page relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 px-4 py-2 text-gray-700" 9046 > 9047 <span class="sr-only label">Page</span> 9048 <span>2</span> 9049 </a> 9050 </li> 9051 <li class="item -ml-px"> 9052 <a 9053 href="https://www.mueblesbonitos.com/salon?p=3" 9054 class="page relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 px-4 py-2 text-gray-700" 9055 >
9056 <span class="sr-only label">Page</span> 9057 <span>3</span> 9058 </a> 9059 </li> 9060 <li class="item -ml-px"> 9061 <a 9062 href="https://www.mueblesbonitos.com/salon?p=4" 9063 class="page relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 px-4 py-2 text-gray-700" 9064 > 9065 <span class="sr-only label">Page</span> 9066 <span>4</span> 9067 </a> 9068 </li> 9069 <li class="item -ml-px"> 9070 <a 9071 href="https://www.mueblesbonitos.com/salon?p=5" 9072 class="page relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 px-4 py-2 text-gray-700" 9073 > 9074 <span class="sr-only label">Page</span> 9075 <span>5</span> 9076 </a> 9077 </li> 9078 9079 9080 9081 <li class="item pages-item-next -ml-px"> 9082 <a 9083 href="https://www.mueblesbonitos.com/salon?p=2" 9084 class="action next relative inline-flex items-center text-sm font-medium leading-5 bg-white border border-gray-300 transition duration-150 ease-in-out hover:text-gray-400 focus:z-10 focus:outline-none focus:border-primary-lighter focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 rounded-r-md px-3 py-2 text-gray-500" 9085 aria-label="Siguiente" 9086 > 9087 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20" aria-hidden="true"> 9088 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 9089</svg> 9090 </a> 9091 </li> 9092 </ol> 9093 </nav> 9094 </div> 9095 9096 9097 9098 9099 <div class="field limiter flex items-center order-3 sm:order-2 md:order-3 lg:order-2 col-span-2 justify-end"> 9100 <div class="control"> 9101 <label class="text-sm label"> 9102 <span class="mr-2" aria-label="Mostrar elementos por página"> 9103 Mostrar </span> 9104 <select 9105 class="form-select limiter-options" 9106 @change="changeUrl( 9107 'product_list_limit', 9108 $event.currentTarget.options[$event.currentTarget.selectedIndex].value, 9109 options.limitDefault 9110 )" 9111 > 9112 <option value="12" 9113 > 9114 12 </option> 9115 <option value="24" 9116 > 9117 24 </option> 9118 <option value="36" 9119 selected="selected" 9120 > 9121 36 </option> 9122 </select> 9123 </label> 9124 </div> 9125 </div> 9126 </div> 9127 </section> 9128 9129 <div data-retailrocket-markup-block="REPLACE_ID" data-category-id="37" style="padding: 0px 25px;"></div> 9130
9130<script type="text/javascript"> 9131 (window["rrApiOnReady"] = window["rrApiOnReady"] || []).push(function() { 9132 try { 9133 rrApi.categoryView(37); 9134 } catch (e) {} 9135 }) 9136 </script>
9136 9137 9138
9138<script type="application/ld+json" id="carrusel_OK"> 9139 { 9140 "@context": "https://schema.org/", 9141 "numberOfItems": "36", 9142 "@type": "ItemList", 9143 "itemListOrder": "Relevance", 9144 "itemListElement": [{"@type":"ListItem","position":1,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-140-cm-ani","name":"Mesa alta Blanco y Sonoma 140 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-ani-140cm-branca-e-sonoma_1.jpg"},{"@type":"ListItem","position":2,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-kyra-110cm-color-blanco-y-sonoma","name":"Mesa alta Kyra (110cm) color blanco y sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-cor-branca-e-sonoma.jpg"},{"@type":"ListItem","position":3,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-kyra-110cm-color-blanco","name":"Mesa alta Kyra (110cm) color blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-kyra-110cm-branca.jpg"},{"@type":"ListItem","position":4,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-110-cm-kyra","name":"Mesa alta Negro y Sonoma 110 cm Kyra","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-110-cm-kyra-03.jpg"},{"@type":"ListItem","position":5,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-140-cm-ani","name":"Mesa alta Negro y Sonoma 140 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-preto-sonoma-140-cm-ani_2.jpg"},{"@type":"ListItem","position":6,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-120-cm-ani","name":"Mesa alta Blanco y Sonoma 120 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_4.jpg"},{"@type":"ListItem","position":7,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-120-cm-ani","name":"Mesa alta Negro y Sonoma 120 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-120-cm-ani-01_1.jpg"},{"@type":"ListItem","position":8,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-blanco-y-sonoma-100-cm-ani","name":"Mesa alta Blanco y Sonoma 100 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-100-cm-ani-01.jpg"},{"@type":"ListItem","position":9,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-negro-y-sonoma-100-cm-ani","name":"Mesa alta Negro y Sonoma 100 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-negro-sonoma-100-cm-ani-01_1.jpg"},{"@type":"ListItem","position":10,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-140-cm-ani","name":"Mesa alta con 2 Taburetes Blanco y Sonoma 140 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-140-cm-ani-01.jpg"},{"@type":"ListItem","position":11,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-140-cm-ani","name":"Mesa alta con 2 Taburetes Negro y Sonoma 140 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-140-cm-ani-01.jpg"},{"@type":"ListItem","position":12,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-120-cm-ani","name":"Mesa alta con 2 Taburetes Blanco y Sonoma 120 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-blanco-sonoma-120-cm-ani-01_3.jpg"},{"@type":"ListItem","position":13,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-120-cm-ani","name":"Mesa alta con 2 Taburetes Negro y Sonoma 120 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-120-cm-ani-01.jpg"},{"@type":"ListItem","position":14,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-100-cm-ani","name":"Mesa alta con 2 Taburetes Blanco y Sonoma 100 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-100-cm-ani-01.jpg"},{"@type":"ListItem","position":15,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-100-cm-ani","name":"Mesa alta con 2 Taburetes Negro y Sonoma 100 cm Ani","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-100-cm-ani-01_1.jpg"},{"@type":"ListItem","position":16,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-110-cm-kyra","name":"Mesa alta con 2 Taburetes Blanco 110 cm Kyra","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-blanco-110-cm-kyra-01_1.jpg"},{"@type":"ListItem","position":17,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-blanco-y-sonoma-110-cm-kyra","name":"Mesa alta con 2 Taburetes Blanco y Sonoma 110 cm Kyra","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-blanco-sonoma-110-cm-kyra-01.jpg"},{"@type":"ListItem","position":18,"url":"https://www.mueblesbonitos.com/salon/mesa-alta-con-2-taburetes-negro-y-sonoma-110-cm-kyra","name":"Mesa alta con 2 Taburetes Negro y Sonoma 110 cm Kyra","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/e/mesa-alta-con-2-taburetes-negro-sonoma-110-cm-04_1.jpg"},{"@type":"ListItem","position":19,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-iris-color-roble","name":"Aparador modelo Iris color Roble","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-roble-1.jpg"},{"@type":"ListItem","position":20,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-iris-color-blanco","name":"Aparador modelo Iris color Blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-iris-color-blanco-1.jpg"},{"@type":"ListItem","position":21,"url":"https://www.mueblesbonitos.com/salon/mueble-tv-color-roble-alba-150cm-renzo","name":"Mueble TV color roble alba 150cm Renzo","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-color-roble-alba-150cm-renzo-01.jpg"},{"@type":"ListItem","position":22,"url":"https://www.mueblesbonitos.com/salon/aparador-blanco-y-sonoma-moderno-150-cm-serena","name":"Aparador Blanco y Sonoma Moderno 150 cm Serena","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-color-blanco-y-sonoma-150-cm-serena-01.jpg"},{"@type":"ListItem","position":23,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-leo-color-blanco-mate","name":"Aparador modelo Leo color Blanco mate","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-blanco-mate-09.jpg"},{"@type":"ListItem","position":24,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-leo-color-roble-eos","name":"Aparador modelo Leo color Roble Eos","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-leo-color-roble-eos-mate-05.jpg"},{"@type":"ListItem","position":25,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-duna-color-roble-eos","name":"Aparador modelo Duna color Roble Eos","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-duna-color-roble-eos-01.jpg"},{"@type":"ListItem","position":26,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-vega-color-blanco-mate","name":"Aparador modelo Vega color Blanco mate","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-blanco-mate-1.jpg"},{"@type":"ListItem","position":27,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-vega-color-roble-alba","
9144name":"Aparador modelo Vega color Roble Alba","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-vega-color-roble-alba-01_1_1.jpg"},{"@type":"ListItem","position":28,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-clark-color-blanco-y-sonoma","name":"Aparador modelo Clark color blanco y sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-clark-color-blanco-y-sonoma-01.jpg"},{"@type":"ListItem","position":29,"url":"https://www.mueblesbonitos.com/salon/aparador-modelo-nevada-color-blanco-y-sonoma","name":"Aparador modelo Nevada color blanco y sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-modelo-nevada-color-blanco-y-sonoma-1.jpg"},{"@type":"ListItem","position":30,"url":"https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-2-puertas-color-blanco","name":"Aparador acanalado modelo Logan 2 puertas color Blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-blanco-01.jpg"},{"@type":"ListItem","position":31,"url":"https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-2-puertas-color-sonoma","name":"Aparador acanalado modelo Logan 2 puertas color Sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-2-puertas-color-sonoma-01.jpg"},{"@type":"ListItem","position":32,"url":"https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-3-puertas-color-blanco","name":"Aparador acanalado modelo Logan 3 puertas color Blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-blanco-01.jpg"},{"@type":"ListItem","position":33,"url":"https://www.mueblesbonitos.com/salon/aparador-acanalado-modelo-logan-3-puertas-color-sonoma","name":"Aparador acanalado modelo Logan 3 puertas color Sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-modelo-logan-3-puertas-color-sonoma-01.jpg"},{"@type":"ListItem","position":34,"url":"https://www.mueblesbonitos.com/salon/mueble-tv-acanalado-modelo-logan-color-blanco","name":"Mueble TV acanalado modelo Logan color Blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-blanco-01.jpg"},{"@type":"ListItem","position":35,"url":"https://www.mueblesbonitos.com/salon/mueble-tv-acanalado-modelo-logan-color-sonoma","name":"Mueble TV acanalado modelo Logan color Sonoma","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/m/u/mueble-tv-acanalado-modelo-logan-color-sonoma-01.jpg"},{"@type":"ListItem","position":36,"url":"https://www.mueblesbonitos.com/salon/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-blanco","name":"\u2028Aparador Acanalado Renzo M de 1 Puerta y Cajonera - Blanco","image":"https://www.mueblesbonitos.com/media/catalog/product/cache/67ee89799642c567a71fc92f3699d937/a/p/aparador-acanalado-renzo-m-de-1-puerta-y-cajonera-blanco-01.jpg"}] } 9145 </script>
9145 9146 9147 <div class="w-full px-4 py-6 custom-category-description-block"> 9148 <style> 9149 .custom-category-description-block, 9150 .catdesc-content, 9151 .catdesc-content * { 9152 font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important; 9153 } 9154 9155 /* Forzamos visibilidad completa para SEO */ 9156 .catdesc-content { 9157 display: block !important; 9158 height: auto !important; 9159 max-height: none !important; 9160 overflow: visible !important; 9161 color: #374151; 9162 line-height: 1.625; 9163 } 9164 9165 /* Limpieza de estilos de Page Builder para ancho completo */ 9166 .catdesc-content [data-appearance="contained"], 9167 .catdesc-content [data-element="inner"], 9168 .catdesc-content [data-content-type="row"] { 9169 max-width: none !important; 9170 width: 100% !important; 9171 margin: 0 !important; 9172 padding: 0 !important; 9173 } 9174 9175 .catdesc-content { 9176 width: 100% !important; 9177 max-width: none !important; 9178 } 9179 </style> 9180 9181 <div class="catdesc-wrap relative mt-3 w-full"> 9182 <div class="catdesc-content prose max-w-none w-full"> 9183 <div class="category-description"> 9184 <div data-content-type="html" data-appearance="default" data-element="main" data-decoded="true"><h2>Muebles de Salón Modernos y Económicos</h2> 9185<p>Los <strong>muebles de salón modernos</strong> definen el espacio más utilizado del hogar: el lugar donde se descansa, se recibe a los invitados y se convive en familia. En Muebles Bonitos, con más de 15 años de experiencia y exposición en Alicante (visita con cita previa), encontrarás desde muebles TV y aparadores hasta composiciones modulares completas â todos con <strong>3 años de garantÃa oficial</strong>, <strong>envÃo gratuito a PenÃnsula y Baleares</strong> y entrega en <strong>1-3 dÃas hábiles</strong> (Express <strong>24h</strong> disponible). Para envÃos a Canarias, Ceuta y Melilla se aplican gastos por tramos.</p> 9186 9187<p>Gracias a la venta directa de fábrica, ofrecemos <strong>conjuntos de salón comedor modernos</strong> con acabados de alta calidad a precios competitivos. La mayorÃa de nuestros modelos son <strong>modulares</strong>, lo que permite configurar el espacio a medida y adaptarlo a las necesidades cambiantes del hogar. Desde composiciones compactas para pisos pequeños hasta grandes conjuntos que aprovechan toda la pared, el catálogo cubre todos los formatos. Muchos modelos incorporan además <strong>iluminación LED integrada</strong>, un detalle que añade profundidad y ambiente al conjunto sin necesidad de puntos de luz adicionales.</p> 9188 9189<h3>Muebles esenciales para el salón: guÃa rápida</h3> 9190<p>El salón es la estancia más versátil del hogar. Antes de elegir, es útil tener claro qué piezas necesitas y qué función cumple cada una:</p> 9191 9192<table> 9193<thead> 9194<tr> 9195<th>Tipo de mueble</th> 9196<th>Función principal</th> 9197<th>Ideal para...</th> 9198</tr> 9199</thead> 9200<tbody> 9201<tr> 9202<td><strong>Mueble TV</strong></td> 9203<td>Soporte del televisor y centro de entretenimiento.</td> 9204<td>Organizar la zona de sofás y ocultar el cableado.</td> 9205</tr> 9206<tr> 9207<td><strong>Aparador</strong></td> 9208<td>Almacenaje de vajilla, mantelerÃa y objetos del dÃa a dÃa.</td> 9209<td>Comedores y zonas de paso, con superficie decorativa.</td> 9210</tr> 9211<tr> 9212<td><strong>Vitrina</strong></td> 9213<td>Exposición de vajillas, colecciones y decoración.</td> 9214<td>Salones que buscan combinar almacenaje y exhibición.</td> 9215</tr> 9216<tr> 9217<td><strong>Mesa de centro</strong></td> 9218<td>Superficie de apoyo junto al sofá.</td> 9219<td>Organizar la zona de estar con funcionalidad y estilo.</td> 9220</tr> 9221<tr> 9222<td><strong>EstanterÃa</strong></td> 9223<td>Almacenaje abierto para libros, plantas y decoración.</td> 9224<td>Aprovechar la altura de las paredes y estructurar el espacio.</td> 9225</tr> 9226<tr> 9227<td><strong>Mueble con chimenea</strong></td> 9228<td>Elemento decorativo con chimenea eléctrica integrada.</td> 9229<td>Salones que buscan calidez y un punto focal diferenciador.</td> 9230</tr> 9231</tbody> 9232</table> 9233 9234<h3>Estilos de salón: encuentra tu decoración ideal</h3> 9235<p>En Muebles Bonitos el catálogo responde a los estilos más demandados actualmente. El acabado en <strong>blanco mate o blanco brillo</strong> â nuestra lÃnea Premium â es el más solicitado para salones luminosos y contemporáneos: aporta limpieza visual y hace que los espacios parezcan más amplios. El <strong>roble y el sonoma</strong> encajan a la perfección con estilos nórdicos o naturales, aportando calidez y textura orgánica. Los modelos en <strong>negro</strong> son la opción ideal para quienes buscan un contraste elegante y sofisticado. Y las combinaciones bicolor â por ejemplo blanco con roble â permiten composiciones más ricas visualmente sin perder coherencia estética.</p> 9236<p>La modularidad es otro de los grandes valores del catálogo. Los <strong>muebles de salón modulares</strong> permiten empezar con una composición básica e ir ampliándola con el tiempo: añadir una vitrina lateral, incorporar un armario colgante o completar la pared con estanterÃas a medida que cambian las necesidades del hogar.</p> 9237 9238<h3>Cómo distribuir los muebles del salón</h3> 9239<p>Una buena distribución mejora tanto la funcionalidad como la sensación de amplitud. Desde Muebles Bonitos recomendamos tener en cuenta estas proporciones básicas: deja al menos <strong>90 cm de paso libre</strong> entre muebles para garantizar la circulación cómoda. El sofá deberÃa estar a entre <strong>150 y 250 cm del mueble TV</strong>, en función del tamaño de la pantalla. En salones rectangulares, colocar el mueble TV en la pared más corta y el sofá frente a él aprovecha mejor el espacio. Para salones pequeños, los muebles con patas o suspendidos liberan el suelo visualmente y aportan sensación de amplitud.</p> 9240 9241<h3>¿Por qué elegir los muebles de salón de Muebles Bonitos?</h3> 9242<p>En Muebles Bonitos trabajamos con venta directa de fábrica, lo que nos permite ofrecer <strong>muebles de salón baratos</strong> sin comprometer la calidad. Todos los productos pasan controles de fabricación rigurosos y están respaldados por <strong>3 años de garantÃa oficial</strong>. El proceso de compra es sencillo y seguro: elige tu modelo, realiza el pedido online y recÃbelo en casa en <strong>1-3 dÃas hábiles</strong> â el 95% de los pedidos llega en menos de 48 horas. Si necesitas verlo antes de comprar, puedes visitar nuestra exposición en Alicante con cita previa o contactarnos a través del chat online.</p> 9243 9244<h3>Preguntas frecuentes sobre muebles de salón</h3> 9245 9246<h4>¿Qué muebles son imprescindibles en un salón?</h4> 9247<p>Los muebles esenciales de un salón son el <strong>mueble TV</strong> como eje central de la zona de entretenimiento, el <strong>sofá</strong> y una <strong>mesa de centro</strong> para la zona de estar. A partir de ahÃ, un <strong>aparador</strong> aporta almacenaje y superficie decorativa, y una <strong>estanterÃa</strong> permite organizar libros y objetos. En Muebles Bonitos encontrarás todos estos elementos en cole
9247cciones coordinadas, lo que facilita conseguir un resultado coherente sin necesidad de combinar estilos distintos.</p> 9248 9249<h4>¿Cómo amueblar un salón comedor pequeño?</h4> 9250<p>Para salones pequeños, desde Muebles Bonitos recomendamos priorizar muebles con doble función: una <strong>mesa de centro elevable</strong> que sirva también como mesa de comedor, un <strong>mueble TV suspendido</strong> que libere el suelo, y un <strong>aparador estrecho colgante</strong> en lugar de uno voluminoso apoyado. Los acabados en <strong>blanco o tonos claros</strong> reflejan la luz y amplÃan visualmente el espacio. Evita saturar las paredes y deja al menos un rincón libre para que el ojo descanse.</p> 9251 9252<h4>¿Cómo combinar los muebles del salón?</h4> 9253<p>La clave es elegir una colección coordinada o respetar una misma gama de acabados. En Muebles Bonitos los muebles de salón están disponibles en acabados como <strong>blanco mate, blanco brillo, negro, roble y sonoma</strong>, pensados para combinarse entre sÃ. Una regla sencilla: elige un acabado dominante para las piezas grandes (mueble TV, aparador) y complementa con un segundo tono en las piezas más pequeñas (mesa de centro, estanterÃa).</p> 9254 9255<h4>¿Cuánto tarda en llegar un pedido de muebles de salón?</h4> 9256<p>Los pedidos con destino a <strong>PenÃnsula y Baleares</strong> se entregan en <strong>1-3 dÃas hábiles</strong>
9256, y el 95% llega en menos de 48 horas. Si necesitas recibirlo antes, el <strong>servicio Express de Muebles Bonitos</strong> garantiza la entrega en <strong>24h</strong>. La entrega se realiza a pie de calle. Para envÃos a Canarias, Ceuta y Melilla el plazo puede ser superior.</p> 9257 9258<h4>¿El envÃo es gratuito a toda España?</h4> 9259<p>El envÃo es gratuito para pedidos con destino a <strong>PenÃnsula y Baleares</strong>. Para envÃos a <strong>Canarias, Ceuta y Melilla</strong> se aplican gastos de transporte por tramos según el valor de la mercancÃa, más los costes de despacho de aduanas (IGIC/IPSI) que se abonan al recibir el pedido.</p> 9260 9261<h4>¿Qué métodos de pago están disponibles?</h4> 9262<p>En Muebles Bonitos puedes pagar con <strong>tarjeta bancaria</strong> (Visa/Mastercard), <strong>Bizum</strong>, <strong>PayPal</strong>, <strong>Apple Pay</strong>, <strong>Google Pay</strong>, <strong>transferencia bancaria</strong> o <strong>contrarreembolso</strong> (con coste de gestión). Si prefieres fraccionar el importe, <strong>Klarna</strong> permite dividir la compra en 3 cuotas sin intereses, pagar a los 30 dÃas o financiar a largo plazo.</p> 9263 9264<h4>¿Los muebles de salón tienen garantÃa?</h4> 9265<p>SÃ. Todos los muebles de salón de Muebles Bonitos incluyen <strong>3 años de garantÃa oficial</strong>, cubriendo defectos de fabricación y materiales conforme a la normativa vigente en España. Dispones además de <strong>60 dÃas naturales</strong> desde la recepción para solicitar una devolución, sin necesidad de justificar tu decisión. <a href="/garantias_y_devoluciones" rel="nofollow" target="_blank" style="text-decoration: underline;">Más información sobre garantÃas y devoluciones</a>.</p> 9266 9267<h3>Explora otras categorÃas de muebles de diseño para tu hogar:</h3> 9268<ul> 9269 <li>Organiza la zona de paso desde la entrada con nuestros <a href="https://www.mueblesbonitos.com/recibidores">Recibidores</a>.</li> 9270 <li>Harmoniza la decoración de tu hogar hasta la zona de descanso con la sección de <a href="https://www.mueblesbonitos.com/dormitorio">Dormitorios</a>.</li> 9271 <li>Completa la lÃnea estilÃstica de tu vivienda descubriendo nuestras opciones de <a href="https://www.mueblesbonitos.com/bano">Muebles de Baño</a>.</li> 9272 <li>Optimiza el espacio con piezas funcionales y versátiles de la gama <a href="https://www.mueblesbonitos.com/decoracion-y-auxiliares">Muebles Auxiliares</a>.</li> 9273</ul> 9274
9275<script type="application/ld+json"> 9276{ 9277 "@context": "https://schema.org", 9278 "@type": "FAQPage", 9279 "mainEntity": [ 9280 { 9281 "@type": "Question", 9282 "name": "¿Qué muebles son imprescindibles en un salón?", 9283 "acceptedAnswer": { 9284 "@type": "Answer", 9285 "text": "Los muebles esenciales de un salón son el mueble TV como eje central de la zona de entretenimiento, el sofá y una mesa de centro para la zona de estar. A partir de ahÃ, un aparador aporta almacenaje y superficie decorativa, y una estanterÃa permite organizar libros y objetos. En Muebles Bonitos encontrarás todos estos elementos en colecciones coordinadas, lo que facilita conseguir un resultado coherente sin necesidad de combinar estilos distintos." 9286 } 9287 }, 9288 { 9289 "@type": "Question", 9290 "name": "¿Cómo amueblar un salón comedor pequeño?", 9291 "acceptedAnswer": { 9292 "@type": "Answer", 9293 "text": "Para salones pequeños, desde Muebles Bonitos recomendamos priorizar muebles con doble función: una mesa de centro elevable que sirva también como mesa de comedor, un mueble TV suspendido que libere el suelo, y un aparador estrecho colgante en lugar de uno voluminoso apoyado. Los acabados en blanco o tonos claros reflejan la luz y amplÃan visualmente el espacio." 9294 } 9295 }, 9296 { 9297 "@type": "Question", 9298 "name": "¿Cómo combinar los muebles del salón?", 9299 "acceptedAnswer": { 9300 "@type": "Answer", 9301 "text": "La clave es elegir una colección coordinada o respetar una misma gama de acabados. En Muebles Bonitos los muebles de salón están disponibles en acabados como blanco mate, blanco brillo, negro, roble y sonoma, pensados para combinarse entre sÃ. Una regla sencilla: elige un acabado dominante para las piezas grandes (mueble TV, aparador) y complementa con un segundo tono en las piezas más pequeñas (mesa de centro, estanterÃa)." 9302 } 9303 }, 9304 { 9305 "@type": "Question", 9306 "name": "¿Cuánto tarda en llegar un pedido de muebles de salón?", 9307 "acceptedAnswer": { 9308 "@type": "Answer", 9309 "text": "Los pedidos con destino a PenÃnsula y Baleares se entregan en 1-3 dÃas hábiles, y el 95% llega en menos de 48 horas. Si necesitas re
9309cibirlo antes, el servicio Express de Muebles Bonitos garantiza la entrega en 24h. La entrega se realiza a pie de calle. Para envÃos a Canarias, Ceuta y Melilla el plazo puede ser superior." 9310 } 9311 }, 9312 { 9313 "@type": "Question", 9314 "name": "¿El envÃo es gratuito a toda España?", 9315 "acceptedAnswer": { 9316 "@type": "Answer", 9317 "text": "El envÃo es gratuito para pedidos con destino a PenÃnsula y Baleares. Para envÃos a Canarias, Ceuta y Melilla se aplican gastos de transporte por tramos según el valor de la mercancÃa, más los costes de despacho de aduanas (IGIC/IPSI) que se abonan al recibir el pedido." 9318 } 9319 }, 9320 { 9321 "@type": "Question", 9322 "name": "¿Qué métodos de pago están disponibles?", 9323 "acceptedAnswer": { 9324 "@type": "Answer", 9325 "text": "En Muebles Bonitos puedes pagar con tarjeta bancaria (Visa/Mastercard), Bizum, PayPal, Apple Pay, Google Pay, transferencia bancaria o contrarreembolso (con coste de gestión). Si prefieres fraccionar el importe, Klarna permite dividir la compra en 3 cuotas sin intereses, pagar a los 30 dÃas o financiar a largo plazo." 9326 } 9327 }, 9328 { 9329 "@type": "Question", 9330 "name": "¿Los muebles de salón tienen garantÃa?", 9331 "acceptedAnswer": { 9332 "@type": "Answer", 9333 "text": "SÃ. Todos los muebles de salón de Muebles Bonitos incluyen 3 años de garantÃa oficial, cubriendo defectos de fabricación y materiales conforme a la normativa vigente en España. Dispones además de 60 dÃas naturales desde la recepción para solicitar una devolución, sin necesidad de justificar tu decisión." 9334 } 9335 } 9336 ] 9337} 9338</script>
9338</div> </div> 9339 </div> 9340 </div> 9341 </div> 9342 9343</div>
9344<script type="text/x-magento-init"> 9345 { 9346 ".sidebar #narrow-by-list": { 9347 "accordion": { 9348 "multipleCollapsible": true, 9349 "active": [] 9350 } 9351 } 9352 } 9353</script>
9353 9354
9355<script type="text/x-magento-init"> 9356 { 9357 ".products-grid, .products-list": { 9358 "amShopbySwatchesChoose": { 9359 "listSwatches": [] } 9360 } 9361 } 9362</script>
9362 9363
9364<script type="text/x-magento-init"> 9365 { 9366 "#narrow-by-list": { 9367 "amShopbyFiltersSync": { 9368 } 9369 } 9370 } 9371</script>
9371 9372 9373
9373<script nonce="NHloMjlxYjRvd29oc2pwMTVtZWtkbWl2eW5peXJnb2Y="> 9374 function hasWebP() { 9375 var elem = document.createElement('canvas'); 9376 9377 if (!!(elem.getContext && elem.getContext('2d'))) { 9378 return elem.toDataURL('image/webp').indexOf('data:image/webp') === 0; 9379 } 9380 return false; 9381 } 9382 9383 if (hasWebP()) { 9384 document.body.classList.add("webp"); 9385 } else { 9386 document.body.classList.add("no-webp"); 9387 }</script>
9387<script></script>
9387<div class="amshopby-filters-bottom-cms"> 9388 </div> 9389 9390<div data-am-js="js-init"> 9391
9391<script type="text/x-magento-init"> 9392 { 9393 "[data-am-js='filter-item-default']": { 9394 "amShopbyFilterItemDefault": { 9395 "collectFilters": 0, 9396 "clearUrl": "https://www.mueblesbonitos.com/salon" 9397 } 9398 }, 9399 "*": { 9400 "amShopbyResponsive": {} 9401 } 9402 } 9403 </script>
9403 9404 9405 </div> 9406</div></div></main><footer class="page-footer"><div class="footer content"> 9407 9408<div class="bg-zinc-100 border-t border-zinc-200"> 9409 <div class="container py-8 mx-auto"> 9410 <div class="grid grid-cols-1 lg:grid-cols-4 lg:gap-6 text-slate-600"> 9411 9412<!-- desactivado por Santi --> 9413<!-- <nav aria-label="Shop"> 9414 <ul> 9415 <li> 9416 <a 9417 href="https://www.mueblesbonitos.com/home/" 9418 class="block py-1.5 hover:underline" 9419 >What's new</a> 9420 </li> 9421 <li> 9422 <a 9423 href="https://www.mueblesbonitos.com/home/" 9424 class="block py-1.5 hover:underline" 9425 >Women</a> 9426 </li> 9427 <li> 9428 <a 9429 href="https://www.mueblesbonitos.com/home/" 9430 class="block py-1.5 hover:underline" 9431 >Men</a> 9432 </li> 9433 <li> 9434 <a 9435 href="https://www.mueblesbonitos.com/home/" 9436 class="block py-1.5 hover:underline" 9437 >Gear</a> 9438 </li> 9439 <li> 9440 <a 9441 href="https://www.mueblesbonitos.com/home/" 9442 class="block py-1.5 hover:underline" 9443 >Training</a> 9444 </li> 9445 <li> 9446 <a 9447 href="https://www.mueblesbonitos.com/home/" 9448 class="block py-1.5 hover:underline" 9449 >Sale</a> 9450 </li> 9451 </ul> 9452</nav> --> 9453 9454 <div 9455 x-data="mobileFooterCollpase" 9456 x-bind="eventListeners" 9457 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 9458 data-open="true" 9459 > 9460 <div 9461 class="group flex w-full items-center justify-between py-4 gap-2 font-bold text-slate-700 lg:pt-0" 9462 data-id="footer_column_1" 9463 x-bind="setToggleRoles" 9464 @click="toggle" 9465 @keyup.enter="toggle" 9466 @keyup.space="toggle" 9467 > 9468 <span>Aviso legal</span> 9469 <span 9470 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 9471 x-ref="toggleIcon" 9472 > 9473 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 9474 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 9475</svg> 9476 </span> 9477 </div> 9478 <div 9479 id="footer_column_1" 9480 class="aria-[hidden=true]:hidden" 9481 x-bind="setCollapseRoles" 9482 > 9483 <div class="pt-0.5 pb-2.5"> 9484 9485<li class="nav item mb-2 last:mb-0"> 9486 <a href="https://www.mueblesbonitos.com/garantias_y_devoluciones" 9487 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9488 " 9489 > 9490 GarantÃas y devoluciones </a> 9491</li> 9492<li class="nav item mb-2 last:mb-0"> 9493 <a href="https://www.mueblesbonitos.com/condiciones-legales" 9494 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9495 " 9496 > 9497 Condiciones legales </a> 9498</li> 9499<li class="nav item mb-2 last:mb-0"> 9500 <a href="https://www.mueblesbonitos.com/privacidad" 9501 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9502 " 9503 > 9504 PolÃtica de privacidad </a> 9505</li> 9506<li class="nav item mb-2 last:mb-0"> 9507 <a href="https://www.mueblesbonitos.com/cookies-mb" 9508 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9509 " 9510 > 9511 PolÃtica de cookies </a> 9512</li> </div> 9513 </div> 9514 </div> 9515 9516 <div 9517 x-data="mobileFooterCollpase" 9518 x-bind="eventListeners" 9519 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 9520 data-open="false" 9521 > 9522 <div 9523 class="group flex w-full items-center justify-between py-4 gap-2 font-bold text-slate-700 lg:pt-0" 9524 data-id="footer_column_2" 9525 x-bind="setToggleRoles" 9526 @click="toggle" 9527 @keyup.enter="toggle" 9528 @keyup.space="toggle" 9529 >
9530 <span>Porqué comprar aquÃ</span> 9531 <span 9532 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 9533 x-ref="toggleIcon" 9534 > 9535 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 9536 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 9537</svg> 9538 </span> 9539 </div> 9540 <div 9541 id="footer_column_2" 9542 class="aria-[hidden=true]:hidden" 9543 x-bind="setCollapseRoles" 9544 > 9545 <div class="pt-0.5 pb-2.5"> 9546 9547<li class="nav item mb-2 last:mb-0"> 9548 <a href="https://www.mueblesbonitos.com/comprar_es_muy_facil" 9549 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9550 " 9551 > 9552 Comprar es muy fácil </a> 9553</li> 9554<li class="nav item mb-2 last:mb-0"> 9555 <a href="https://www.mueblesbonitos.com/como-pagar" 9556 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9557 " 9558 > 9559 Formas de pago </a> 9560</li> 9561<li class="nav item mb-2 last:mb-0"> 9562 <a href="https://www.mueblesbonitos.com/envios-muebles-bonitos" 9563 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9564 " 9565 > 9566 EnvÃo gratuito </a> 9567</li> 9568<li class="nav item mb-2 last:mb-0"> 9569 <a href="https://www.mueblesbonitos.com/concurso" 9570 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9571 " 9572 > 9573 Consigue un 10% de descuento </a> 9574</li> 9575<li class="nav item mb-2 last:mb-0"> 9576 <a href="https://www.mueblesbonitos.com/black-friday-muebles" 9577 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9578 " 9579 > 9580 Black Friday muebles </a> 9581</li> </div> 9582 </div> 9583 </div> 9584 9585 <div 9586 x-data="mobileFooterCollpase" 9587 x-bind="eventListeners" 9588 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 9589 data-open="false" 9590 > 9591 <div 9592 class="group flex w-full items-center justify-between py-4 gap-2 font-bold text-slate-700 lg:pt-0" 9593 data-id="footer_column_3" 9594 x-bind="setToggleRoles" 9595 @click="toggle" 9596 @keyup.enter="toggle" 9597 @keyup.space="toggle" 9598 > 9599 <span>Quiénes somos</span> 9600 <span 9601 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 9602 x-ref="toggleIcon" 9603 > 9604 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 9605 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 9606</svg> 9607 </span> 9608 </div> 9609 <div 9610 id="footer_column_3" 9611 class="aria-[hidden=true]:hidden" 9612 x-bind="setCollapseRoles" 9613 > 9614 <div class="pt-0.5 pb-2.5"> 9615 9616<li class="nav item mb-2 last:mb-0"> 9617 <a href="https://www.mueblesbonitos.com/quienes-somos" 9618 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9619 " 9620 > 9621 Quiénes somos/contactar </a> 9622</li> 9623<li class="nav item mb-2 last:mb-0"> 9624 <a href="https://www.mueblesbonitos.com/customers" 9625 rel="nofollow" 9626 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9627 " 9628 > 9629 Comunicar una incidencia </a> 9630</li> 9631<li class="nav item mb-2 last:mb-0"> 9632 <a href="https://www.mueblesbonitos.com/preguntas-frecuentes" 9633 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dar
9633k:hover:text-blue-400 9634 " 9635 > 9636 Preguntas frecuentes </a> 9637</li> 9638<li class="nav item mb-2 last:mb-0"> 9639 <a href="https://www.mueblesbonitos.com/consejos-utiles" 9640 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9641 " 9642 > 9643 Consejos útiles </a> 9644</li> 9645<li class="nav item mb-2 last:mb-0"> 9646 <a href="https://www.mueblesbonitos.com/reviews_mb" 9647 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9648 " 9649 > 9650 Opiniones de clientes </a> 9651</li> 9652<li class="nav item mb-2 last:mb-0"> 9653 <a href="https://www.mueblesbonitos.com/mapa-del-sitio" 9654 class="text-gray-600 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 9655 " 9656 > 9657 Mapa del sitio </a> 9658</li> </div> 9659 </div> 9660 </div> 9661 9662 <div 9663 x-data="mobileFooterCollpase" 9664 x-bind="eventListeners" 9665 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 9666 data-open="false" 9667 > 9668 <div 9669 class="group flex w-full items-center justify-between py-4 gap-2 font-bold text-slate-700 lg:pt-0" 9670 data-id="footer_column_4" 9671 x-bind="setToggleRoles" 9672 @click="toggle" 9673 @keyup.enter="toggle" 9674 @keyup.space="toggle" 9675 > 9676 <span>Mi cuenta</span> 9677 <span 9678 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 9679 x-ref="toggleIcon" 9680 > 9681 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 9682 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 9683</svg> 9684 </span> 9685 </div> 9686 <div 9687 id="footer_column_4" 9688 class="aria-[hidden=true]:hidden" 9689 x-bind="setCollapseRoles" 9690 > 9691 <div class="pt-0.5 pb-2.5"> 9692 <!-- BLOCK footer.customer.menu --> 9693
9694<script> 9695 document.addEventListener('DOMContentLoaded', () => { 9696 document.getElementById('customer.footer.sign.in.link').addEventListener('click', () => { 9697 if (hyva.setCookie) { 9698 hyva.setCookie( 9699 'login_redirect', 9700 window.location.href, 9701 1 9702 ); 9703 } 9704 }); 9705 }); 9706</script>
9706 9707<a 9708 id="customer.footer.sign.in.link" 9709 class="block py-1.5 hover:underline" 9710 rel="nofollow" 9711 onclick="hyva.setCookie && hyva.setCookie( 9712 'login_redirect', 9713 window.location.href, 9714 1 9715 )" 9716 href="https://www.mueblesbonitos.com/customer/account/index/" 9717> 9718 Iniciar Sesión</a> 9719 9720 <a 9721 class="block py-1.5 hover:underline" 9722 rel="nofollow" 9723 href="https://www.mueblesbonitos.com/customer/account/create/" 9724 >Crear una Cuenta</a> 9725<!-- /BLOCK footer.customer.menu --> </div> 9726 </div> 9727 </div> 9728 </div> 9729 </div> 9730 <div class="space-y-10 bg-zinc-50 py-4"> 9731 9732<div 9733 class="container flex gap-4 flex-wrap justify-center" 9734 aria-label="Payment Providers"> 9735 <!-- --> 9736 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_7)"><path fill="#d9dff7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#1434cb" d="M19.108 10.212 14.243 21.82H11.07l-2.393-9.263c-.146-.57-.272-.78-.714-1.02-.722-.391-1.913-.759-2.962-.987l.071-.337h5.109c.651 0 1.237.434 1.385 1.184l1.264 6.715 3.124-7.9zm12.435 7.817c.013-3.063-4.236-3.232-4.206-4.6.009-.417.405-.86 1.273-.973.43-.056 1.616-.099 2.96.52l.527-2.461A8.1 8.1 0 0 0 29.29 10c-2.968 0-5.056 1.578-5.074 3.837-.019 1.67 1.491 2.603 2.629 3.158 1.17.569 1.563.934 1.558 1.443-.008.778-.933 1.122-1.798 1.135-1.509.024-2.385-.408-3.083-.733l-.544 2.543c.702.322 1.997.603 3.339.617 3.154 0 5.218-1.558 5.227-3.97m7.837 3.79h2.777l-2.424-11.607H37.17c-.577 0-1.063.336-1.278.852L31.387 21.82h3.152l.626-1.734h3.852zm-3.35-4.113 1.58-4.358.91 4.358zm-12.632-7.494L20.915 21.82h-3.002l2.483-11.607z"/></g><defs><clipPath id="a_7"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>visa</title></svg> 9737 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_8)"><path fill="#f1efeb" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#ff5f00" d="M28.376 8.139h-8.75v15.725h8.75z"/><path fill="#eb001b" d="M20.181 16a9.98 9.98 0 0 1 3.82-7.861A9.96 9.96 0 0 0 17.82 6c-5.522 0-10 4.478-10 10s4.478 10 10 10A9.96 9.96 0 0 0 24 23.861 9.98 9.98 0 0 1 20.182 16"/><path fill="#f79e1b" d="M40.178 16c0 5.522-4.477 10-10 10-2.333 0-4.477-.8-6.18-2.139A9.98 9.98 0 0 0 27.818 16a9.98 9.98 0 0 0-3.82-7.861A9.96 9.96 0 0 1 30.178 6c5.522 0 10 4.478 10 10"/></g><defs><clipPath id="a_8"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>mastercard</title></svg> 9738 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_9)"><path fill="#d6edff" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M43 10.5v9.523h-2.167V10.5zm-2.965 3.214v6.327H38.11v-.546a2.6 2.6 0 0 1-.83.546q-.465.201-1.006.203-.679 0-1.259-.253a3.2 3.2 0 0 1-1.006-.72 3.5 3.5 0 0 1-.682-1.06 3.7 3.7 0 0 1-.238-1.33q-.001-.708.238-1.313.252-.619.682-1.076a3 3 0 0 1 1.006-.708 3 3 0 0 1 1.26-.267q.539 0 1.006.203.466.19.83.545v-.545h1.925zm-3.414 4.604q.592.001.97-.407.39-.404.39-1.035c0-.42-.13-.769-.39-1.036a1.27 1.27 0 0 0-.97-.406c-.391 0-.722.134-.983.406q-.377.405-.377 1.036c0 .42.127.769.377 1.035q.391.406.983.407M29.996 10.5q.857 0 1.462.24.604.24 1.02.67.428.444.668 1.013.239.57.238 1.227.001.657-.238 1.227c-.157.377-.383.72-.667 1.013q-.415.43-1.021.67-.604.24-1.462.24h-1.044v3.238h-2.205V10.5zm-.316 4.34c.296 0 .519-.03.681-.09q.254-.103.415-.253.34-.316.34-.847t-.34-.847a1.2 1.2 0 0 0-.415-.24q-.239-.101-.681-.102h-.731v2.378zm-11.055-1.126h2.393l1.624 3.034h.027l1.447-3.034h2.216l-4.748 9.538h-2.205l2.167-4.363zm-.427 0v6.327h-1.926v-.546a2.6 2.6 0 0 1-.83.546q-.466.201-1.006.203-.679 0-1.259-.253a3.2 3.2 0 0 1-1.006-.72 3.6 3.6 0 0 1-.682-1.06 3.7 3.7 0 0 1-.238-1.33q0-.708.238-1.313.251-.619.682-1.076a3 3 0 0 1 1.006-.708 3 3 0 0 1 1.26-.267q.539 0 1.006.203.467.19.83.545v-.545h1.925zm-3.414 4.604q.591.001.972-.407.392-.404.392-1.035c0-.42-.13
9738-.769-.392-1.036a1.27 1.27 0 0 0-.972-.406q-.591-.001-.983.406-.378.405-.377 1.036c0 .42.128.769.377 1.035q.392.406.983.407M8.25 10.5q.857 0 1.462.24.604.24 1.02.67.428.444.668 1.013.239.57.238 1.227.001.657-.238 1.227c-.156.377-.383.72-.667 1.013q-.415.43-1.021.67-.604.24-1.462.24H7.205v3.238H5V10.5zm-.313 4.34c.295 0 .519-.03.681-.09a1.3 1.3 0 0 0 .415-.253q.34-.316.34-.847t-.34-.847a1.2 1.2 0 0 0-.415-.24q-.24-.101-.681-.102h-.731v2.378z"/></g><defs><clipPath id="a_9"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>paypal</title></svg> 9739 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_10)"><path fill="#fff1f7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M39.478 18.825c-.884 0-1.572-.724-1.572-1.603 0-.88.688-1.603 1.572-1.603s1.573.724 1.573 1.603c0 .88-.69 1.603-1.573 1.603m-.442 1.694c.754 0 1.716-.284 2.249-1.396l.052.025c-.234.608-.234.97-.234 1.06v.143H43v-6.258h-1.897v.142c0 .09 0 .453.233 1.06l-.051.026c-.533-1.112-1.495-1.396-2.249-1.396-1.806 0-3.08 1.422-3.08 3.297s1.274 3.297 3.08 3.297m-6.38-6.594c-.858 0-1.534.297-2.08 1.396l-.052-.026c.234-.607.234-.97.234-1.06v-.142H28.86v6.258h1.95v-3.297c0-.866.507-1.41 1.325-1.41.82 0 1.222.466 1.222 1.397v3.31h1.95v-3.982c0-1.423-1.118-2.444-2.652-2.444M26.04 15.32l-.052-.026c.234-.607.234-.97.234-1.06v-.142h-1.897v6.258h1.95l.012-3.013c0-.879.468-1.41 1.235-1.41.208 0 .377.027.572.078v-1.913c-.858-.181-1.625.142-2.054 1.228m-6.199 3.504c-.883 0-1.572-.724-1.572-1.603 0-.88.689-1.603 1.572-1.603s1.573.724 1.573 1.603c0 .88-.689 1.603-1.5
973973 1.603M19.4 20.52c.754 0 1.716-.284 2.249-1.396l.052.025c-.234.608-.234.97-.234 1.06v.143h1.897v-6.258h-1.897v.142c0 .09 0 .453.234 1.06l-.052.026c-.533-1.112-1.495-1.396-2.248-1.396-1.807 0-3.08 1.422-3.08 3.297s1.273 3.297 3.08 3.297m-5.796-.168h1.95V11.3h-1.95zm-1.43-9.051h-1.988c0 1.616-1 3.064-2.52 4.099l-.599.414V11.3H5v9.05h2.066v-4.486l3.418 4.487h2.521l-3.288-4.293c1.495-1.073 2.47-2.74 2.457-4.758"/></g><defs><clipPath id="a_10"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>klarna</title></svg> 9740 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_11)"><path fill="#e6e6e6" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#000" d="M13.422 11.356a2.62 2.62 0 0 0 .604-1.856 2.6 2.6 0 0 0-1.718.88 2.47 2.47 0 0 0-.615 1.793 2.12 2.12 0 0 0 1.729-.817m.605.944c-.955-.063-1.761.541-2.217.541s-1.157-.509-1.91-.498a2.81 2.81 0 0 0-2.397 1.453c-1.06 1.76-.265 4.38.732 5.823.488.71 1.06 1.496 1.835 1.464s1.008-.467 1.888-.467 1.146.467 1.91.456c.763-.01 1.293-.71 1.781-1.421a6.4 6.4 0 0 0 .796-1.644 2.57 2.57 0 0 1-1.549-2.344 2.61 2.61 0 0 1 1.252-2.207 2.73 2.73 0 0 0-2.121-1.156m8.305-1.983a3.34 3.34 0 0 1 3.51 3.51 3.393 3.393 0 0 1-3.563 3.48h-2.291v3.648h-1.666V10.317zm-2.344 5.643h1.92a2.005 2.005 0 0 0 2.259-2.122 1.983 1.983 0 0 0-2.249-2.121h-1.91zm6.29 2.821c0-1.358 1.06-2.196 2.895-2.302l2.122-.127v-.594c0-.87-.584-1.39-1.56-1.39a1.485 1.485 0 0 0-1.644 1.146h-1.506c.096-1.39 1.294-2.45 3.214-2.45s3.097 1.008 3.097 2.567v5.367H31.37v-1.283a2.76 2.76 0 0 1-2.46 1.41 2.364 2.364 0 0 1-2.631-2.344m5.027-.7v-.615l-1.92.116c-.954.064-1.495.488-1.495 1.157 0 .668.562 1.124 1.421 1.124a1.87 1.87 0 0 0 1.994-1.782m3.033 5.781V22.61q.26.024.52 0a1.305 1.305 0 0 0 1.39-1.06l.137-.478-2.81-7.86h1.728l1.973 6.365 1.962-6.365H41l-2.917 8.189c-.657 1.888-1.432 2.493-3.044 2.493-.18 0-.573-.011-.7-.032"/></g><defs><clipPath id="a_11"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>apple-pay</title></svg> 9741 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" fill="none" viewBox="0 0 48 32" role="img"><g clip-path="url(#a_12)"><path fill="#e4e5e7" d="M0 4a4 4 0 0 1 4-4h40a4 4 0 0 1 4 4v24a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4z"/><path fill="#3c4043" d="M22.869 16.488v3.933H21.62v-9.712h3.309q1.259 0 2.139.838.897.84.897 2.048c0 .826-.3 1.508-.898 2.06q-.869.828-2.138.827h-2.061zm0-4.583v3.387h2.087c.494 0 .91-.17 1.235-.5.331-.332.5-.735.5-1.19a1.62 1.62 0 0 0-.5-1.177q-.486-.516-1.235-.514h-2.087zm8.361 1.651q1.383 0 2.183.741.8.74.8 2.029v4.095h-1.19v-.923h-.052q-.771 1.139-2.06 1.138-1.1.001-1.84-.65-.741-.652-.741-1.626 0-1.033.78-1.638.781-.613 2.08-.611 1.113 0 1.827.41v-.287c0-.435-.17-.8-.514-1.105a1.76 1.76 0 0 0-1.209-.455c-.695 0-1.248.293-1.651.884l-1.099-.689q.909-1.314 2.685-1.313m-1.613 4.824c0 .325.136.598.416.812q.411.324.968.325.79 0 1.405-.585.616-.583.617-1.371-.584-.46-1.625-.462-.76.002-1.268.364-.515.381-.513.917M41 13.77l-4.16 9.57h-1.288l1.547-3.348-2.743-6.221h1.359l1.976 4.771h.026l1.924-4.771z"/><path fill="#4285f4" d="M17.904 15.695q-.001-.61-.104-1.171h-5.232v2.145l3.013.001a2.58 2.58 0 0 1-1.118 1.728v1.392h1.794c1.047-.97 1.647-2.402 1.647-4.095"/><path fill="#34a853" d="M14.464 18.398c-.5.337-1.142.534-1.895.534-1.453 0-2.685-.98-3.127-2.3h-1.85v1.436a5.57 5.57 0 0 0 4.977 3.067c1.505 0 2.768-.494 3.688-1.346z"/><path fill="#fabb05" d="M9.268 15.568c0-.37.062-.729.174-1.065v-1.436h-1.85A5.54 5.54 0 0 0 7 15.568c0 .9.214 1.749.592 2.501l1.85-1.435a3.4 3.4 0 0 1-.174-1.066"/><path fill="#e94235" d="M12.57 12.204c.82 0 1.556.283 2.136.835l1.59-1.588c-.966-.9-2.224-1.451-3.727-1.451a5.57 5.57 0 0 0-4.977 3.067l1.85 1.436c.442-1.32 1.674-2.3 3.127-2.3"/></g><defs><clipPath id="a_12"><path fill="#fff" d="M0 0h48v32H0z"/></clipPath></defs><title>google-pay</title></svg> 9742 9743</div> </div> 9744 <div class="container pt-7 pb-5 border-t border-zinc-200 flex justify-center items-center flex-col sm:flex-row text-sm"> 9745 9746<div class="border-t border-gray-200 bg-gray-50 py-6 mt-10"> 9747 <div class="container mx-auto px-4"> 9748 <div class="flex flex-col gap-6"> 9749 9750 <div class="text-center text-sm text-gray-700 border-b border-gray-200 pb-4">
9751 <span class="font-semibold text-gray-900">Muebles Bonitos S.L.</span> 9752 <span class="mx-2">|</span> 9753 <span>C/ Nieve 34, 03006 Alicante</span> 9754 <span class="mx-2">|</span> 9755 <span>Telf: +34 965 104 517</span> 9756 <span class="mx-2">|</span> 9757 <span>CIF: B54778238</span> 9758 </div> 9759 9760 <div class="flex flex-col md:flex-row justify-between items-center gap-4"> 9761 9762 <div class="flex items-center gap-4"> 9763 <span class="text-xs font-bold text-gray-500 uppercase tracking-widest">Colabora:</span> 9764 9765 <!-- <img src="/media/logo_generalitat.webp" 9766 alt="Logo Generalitat Valenciana" 9767 width="140" height="75" 9768 class="h-auto object-contain" 9769 loading="lazy"> --> 9770 9771 <a rel="noindex,nofollow" href="/media/labora.png" target="_blank" class="hover:opacity-80 transition-opacity"> 9772 <picture class="h-auto object-contain"><source type="image/webp" srcset="https://www.mueblesbonitos.com/media/labora.webp"><img src="/media/labora.png" alt="Cartel Labora" width="140" height="75" class="h-auto object-contain" loading="lazy" loading="lazy"></picture> 9773 </a> 9774 </div> 9775 9776 <div class="text-[10px] text-gray-500 text-center md:text-right max-w-md leading-tight"> 9777 <p>Suport a la promoció exterior de la Comunitat Valenciana 2025. Import rebut: 15.170,87â¬</p> 9778 <p class="mt-1">© 2026 Muebles Bonitos.</p> 9779 </div> 9780 9781 </div> 9782 </div> 9783 </div> 9784</div> 9785<!-- <nav class="text-slate-600" aria-label="Legal Menu"> 9786 <a 9787 href="https://www.mueblesbonitos.com/privacy-policy-cookie-restriction-mode/" 9788 class="inline-block py-1 px-2 sm:px-0 sm:mr-4 sm:last:mr-0 hover:underline" 9789 >Terms & Conditions</a> 9790 <a 9791 href="https://www.mueblesbonitos.com/privacy-policy-cookie-restriction-mode/" 9792 class="inline-block py-1 px-2 sm:px-0 sm:mr-4 sm:last:mr-0 hover:underline" 9793 >PolÃtica de privacidad</a> 9794 </nav> --> 9795 </div> 9796</div>
9797<script> 9798 function mobileFooterCollpase() { 9799 return { 9800 open: false, 9801 isMobile: false, 9802 init() { 9803 this.open = this.$root.dataset.open; 9804 this.checkIsMobileResolution(); 9805 }, 9806 checkIsMobileResolution() { 9807 this.isMobile = getComputedStyle(this.$refs.toggleIcon).display !== 'none' 9808 }, 9809 isOpen() { 9810 return this.isMobile ? this.open : true; 9811 }, 9812 toggle() { 9813 return this.isMobile ? this.open = !this.open : true; 9814 }, 9815 eventListeners: { 9816 ['@resize.window.debounce']() { 9817 this.checkIsMobileResolution(); 9818 }, 9819 ['@visibilitychange.window.debounce']() { 9820 this.checkIsMobileResolution(); 9821 } 9822 }, 9823 setToggleRoles: { 9824 [':role']() { 9825 return this.isMobile && 'button'; 9826 }, 9827 [':tabindex']() { 9828 return this.isMobile && '0'; 9829 }, 9830 [':aria-expanded']() { 9831 return this.isMobile ? this.open : null; 9832 }, 9833 [':aria-controls']() { 9834 return this.isMobile ? this.$el.dataset.id : null; 9835 } 9836 }, 9837 setCollapseRoles: { 9838 [':aria-hidden']() { 9839 return this.isMobile ? !!this.open : null; 9840 }, 9841 [':aria-labelledby']() { 9842 return this.isMobile ? this.$el.id : null; 9843 } 9844 } 9845 } 9846 } 9847 window.addEventListener('alpine:init', () => Alpine.data('mobileFooterCollpase', mobileFooterCollpase), { once: true }) 9848</script>
9848 9849 9850</div></footer>
9851<script type="text/javascript"> 9852 var oct8ne = document.createElement("script"); 9853 oct8ne.server = "backoffice-eu.oct8ne.com/"; 9854 oct8ne.type = "text/javascript"; 9855 oct8ne.async = true; 9856 oct8ne.license = "4DC4F0B70B4A312415678D0EE1F6CE11"; // Licencia fija 9857 oct8ne.src = (document.location.protocol == "https:" ? "https://" : "http://") + "static-eu.oct8ne.com/api/v2/oct8ne.js?" + (Math.round(new Date().getTime() / 86400000)); 9858 9859 // ** Inyección de Variables PHP ** 9860 oct8ne.locale = "es-ES"; 9861 oct8ne.baseUrl = "//www.mueblesbonitos.com"; 9862 oct8ne.allowedDepartmentsId = 1204; 9863 9864 var s = document.getElementsByTagName("script")[0]; 9865 insertOct8ne(); 9866 9867 function insertOct8ne() { 9868 // Mejor práctica: Inyectar al final del body (donde estamos) o usar un fallback robusto. 9869 // Dado que estamos en before.body.end, la lógica original está bien si funciona, 9870 // pero usar document.body.appendChild(oct8ne) es más seguro. 9871 s.parentNode.insertBefore(oct8ne, s); 9872 } 9873</script>
9873 9874
9875<script> 9876 (() => { 9877 function alpineSnapSlider(Alpine) { 9878 function roundUpIfGreaterThan(number, min = 8) { 9879 const decimalPart = number - Math.floor(number); 9880 return decimalPart >= min ? Math.ceil(number) : Math.floor(number); 9881 } 9882 Alpine.directive("snap-slider", (el, { modifiers }, { cleanup }) => { 9883 const track = el.querySelector("[data-track]"); 9884 if (!track) { 9885 console.warn( 9886 "No Slider track defined, reverting back to CSS slider.\nPlease create a wrapper element for your slides with the attribute data-track" 9887 ); 9888 return; 9889 } 9890 let initialLoad = true; 9891 let pager = el.querySelector("[data-pager]"); 9892 let slides = []; 9893 let inViewObserver, mutationObserver, resizeObserver; 9894 const navBtns = Array.from( 9895 el.querySelectorAll("[data-next], [data-prev]") 9896 ); 9897 const slideLabelSepparator = el.dataset.slideLabelSepparator || "of"; 9898 const useAutoPager = modifiers.includes("auto-pager"); 9899 const useGroupPager = modifiers.includes("group-pager"); 9900 const sliderLabel = el.hasAttribute("aria-label") && el.getAttribute("aria-label").toLowerCase().trim().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, ""); 9901 const sliderId = el.id || sliderLabel || "slider"; 9902 const markerIdName = "data-target-id"; 9903 const pagerClasses = el.dataset.pagerClass || "pager"; 9904 const markerClasses = el.dataset.markerClass || "pager-item"; 9905 function getInViewItems() { 9906 const inViewSlides = track.querySelectorAll("[data-in-view]"); 9907 const firstInViewSlide = inViewSlides[0] || null; 9908 const lastInViewSlide = inViewSlides[inViewSlides.length - 1] || null; 9909 const isAtStart = firstInViewSlide === slides[0]; 9910 const isAtEnd = lastInViewSlide === slides[slides.length - 1]; 9911 return { 9912 inViewSlides, 9913 totalInViewSlides: inViewSlides.length, 9914 firstInViewSlide, 9915 lastInViewSlide, 9916 isAtStart, 9917 isAtEnd, 9918 hasNoOverflow: isAtStart && isAtEnd 9919 }; 9920 } 9921 function groupPagerMarkers() { 9922 if (!pager || !useGroupPager) return; 9923 const totalVisibleSlides = roundUpIfGreaterThan( 9924 track.offsetWidth / slides[0].offsetWidth 9925 ); 9926 const markers = Array.from(pager.querySelectorAll("a, button")); 9927 markers.forEach((marker, index) => { 9928 marker.style.display = index % totalVisibleSlides === 0 ? null : "none"; 9929 }); 9930 } 9931 function handleInView(entries) { 9932 entries.forEach((entry) => { 9933 const marker = pager && (pager.querySelector(`[href="#${entry.target.id}"]`) || pager.querySelector( 9934 `[${markerIdName}="${entry.target.id}"]` 9935 )); 9936 entry.target.toggleAttribute( 9937 "data-in-view", 9938 entry.isIntersecting 9939 ); 9940 entry.target.toggleAttribute("inert", !entry.isIntersecting); 9941 marker?.setAttribute("aria-current", entry.isIntersecting); 9942 marker?.setAttribute( 9943 "tabindex", 9944 entry.isIntersecting ? "0" : "-1" 9945 ); 9946 }); 9947 const { isAtStart, isAtEnd, hasNoOverflow } = getInViewItems(); 9948 navBtns.forEach((btn) => { 9949 if (btn.hasAttribute("data-next")) { 9950 btn.style.visibility = hasNoOverflow ? "hidden" : null; 9951 isAtEnd ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled"); 9952 } 9953 if (btn.hasAttribute("data-prev")) { 9954 btn.style.visibility = hasNoOverflow ? "hidden" : null; 9955 isAtStart ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled"); 9956 } 9957 }); 9958 if (pager) { 9959 pager.style.visibility = hasNoOverflow ? "hidden" : null; 9960 } 9961 if (!initialLoad) { 9962 el.dispatchEvent( 9963 new CustomEvent("slideChange", { detail: getInViewItems() }) 9964 ); 9965 } else { 9966 initialLoad = false;
9967 } 9968 if (document.activeElement.parentElement.hasAttribute("data-pager")) { 9969 const activeItems = pager.querySelectorAll('[tabindex="0"]'); 9970 if (activeItems.length) { 9971 activeItems[0].focus(); 9972 } 9973 } 9974 } 9975 function getSlides() { 9976 if (!track) return []; 9977 return Array.from(track.children).filter( 9978 (child) => child.tagName.toLowerCase() !== "template" && child.tagName.toLowerCase() !== "script" 9979 ); 9980 } 9981 function refreshSlides() { 9982 initialLoad = true; 9983 slides = getSlides(); 9984 setupSlides(); 9985 if (useAutoPager) { 9986 createPager(); 9987 } else { 9988 setupPager(); 9989 } 9990 groupPagerMarkers(); 9991 setupObservers(); 9992 } 9993 function setupSlides() { 9994 slides = getSlides(); 9995 slides.forEach((slide, index) => { 9996 const totalSlides = slides.length; 9997 const currentSlide = index + 1; 9998 const existingLabel = slide.getAttribute("aria-label") || ""; 9999 const isImage = slide.tagName.toLowerCase() === "img" || slide.tagName.toLowerCase() === "picture"; 10000 const slideLabelTag = isImage ? "alt" : "aria-label"; 10001 const hasAutoLabel = existingLabel.startsWith(`${currentSlide} ${slideLabelSepparator} `); 10002 if (!slide.hasAttribute("id")) { 10003 slide.setAttribute("id", `${sliderId}-item-${currentSlide}`); 10004 } 10005 10006 if ((!slide.hasAttribute(slideLabelTag) || slide.getAttribute(slideLabelTag) === "") || hasAutoLabel) { 10007 slide.setAttribute(slideLabelTag, `${currentSlide} ${slideLabelSepparator} ${totalSlides}`); 10008 } 10009 10010 if (slide.tagName.toLowerCase() === "div" && !slide.hasAttribute("role")) { 10011 slide.setAttribute("role", "group"); 10012 } 10013 10014 if (pager && !isImage) { 10015 slide.setAttribute("role", "tabpanel"); 10016 } 10017 10018 if (slide.getAttribute('role') === "group") { 10019 slide.setAttribute("aria-roledescription", "item"); 10020 } 10021 }); 10022 if (!el.hasAttribute("role")) { 10023 el.setAttribute("role", "region"); 10024 } 10025 if (!el.hasAttribute("aria-roledescription")) { 10026 el.setAttribute("aria-roledescription", "carousel"); 10027 } 10028 track.setAttribute("tabindex", 0); 10029 track.setAttribute("aria-live", "polite"); 10030 } 10031 function setupNav() { 10032 navBtns.forEach((btn) => { 10033 btn.setAttribute("disabled", ""); 10034 btn.removeAttribute("hidden"); 10035 btn.classList.remove("invisible"); 10036 btn.style.visibility = null; 10037 }); 10038 } 10039 function createPager() { 10040 const newPager = document.createElement("nav"); 10041 newPager.setAttribute("data-pager", ""); 10042 newPager.setAttribute("role", "tablist"); 10043 newPager.classList.add(...pagerClasses.split(" ")); 10044 10045 slides.forEach((slide, index) => { 10046 const marker = document.createElement("button"); 10047 const slideId = slide.id || `${sliderId}-item-${index + 1}`; 10048 marker.setAttribute(markerIdName, slideId); 10049 marker.classList.add(...markerClasses.split(" ")); 10050 setupPagerMarker(marker, index); 10051 newPager.appendChild(marker); 10052 10053 if (slide.tagName.toLowerCase() !== "img" && slide.tagName.toLowerCase() !== "picture") { 10054 slide.removeAttribute("aria-roledescription"); 10055 slide.setAttribute("role", "tabpanel"); 10056 } 10057 }); 10058 10059 if (pager) { 10060 pager.setAttribute("role", "tablist"); 10061 pager.replaceChildren(...newPager.children); 10062 } else { 10063 track.after(newPager); 10064 pager = el.querySelector("[data-pager]"); 10065 } 10066 } 10067 function setupPager() { 10068 if (!pager) return; 10069 pager.setAttribute("role", "tablist"); 10070 const items = Array.from(pager.querySelectorAll("a, button"));
10071 items.forEach((marker, index) => setupPagerMarker(marker, index)); 10072 } 10073 function setupPagerMarker(marker, index) { 10074 const markerId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(markerIdName); 10075 const slideId = markerId || `${sliderId}-item-${index + 1}`; 10076 if (!markerId) { 10077 marker.setAttribute(markerIdName, slideId); 10078 } 10079 marker.setAttribute("role", "tab"); 10080 marker.setAttribute("aria-controls", slideId); 10081 marker.setAttribute("aria-posinset", index + 1); 10082 marker.setAttribute("aria-setsize", slides.length); 10083 marker.setAttribute("tabindex", "-1"); 10084 if (!marker.hasAttribute("aria-label")) { 10085 marker.setAttribute("aria-label", `Slide ${index + 1}`); 10086 } 10087 } 10088 function setupObservers() { 10089 if (inViewObserver) { 10090 inViewObserver.disconnect(); 10091 } 10092 inViewObserver = new IntersectionObserver( 10093 handleInView.bind(track), 10094 { root: track, threshold: 0.8 } 10095 ); 10096 slides.forEach((slide) => inViewObserver.observe(slide)); 10097 } 10098 function setupMutationObserver() { 10099 mutationObserver = new MutationObserver(refreshSlides.bind(track)); 10100 mutationObserver.observe(track, { 10101 childList: true, 10102 subtree: false 10103 }); 10104 } 10105 function setupResizeObserver() { 10106 resizeObserver = new ResizeObserver(groupPagerMarkers.bind(el)); 10107 resizeObserver.observe(el); 10108 } 10109 function goToSlideDir(dir = "next") { 10110 const { firstInViewSlide, lastInViewSlide } = getInViewItems(); 10111 const isPrev = dir === "prev"; 10112 let targetSlide = isPrev ? firstInViewSlide?.previousElementSibling : lastInViewSlide?.nextElementSibling; 10113 if (!targetSlide) return; 10114 if (targetSlide.tagName.toLowerCase() === "template") { 10115 targetSlide = isPrev ? targetSlide?.previousElementSibling : targetSlide?.nextElementSibling; 10116 } 10117 targetSlide.scrollIntoView({ 10118 block: "nearest", 10119 inline: isPrev ? "end" : "start", 10120 behavior: "smooth" 10121 }); 10122 } 10123 function pagerToSlide(event) { 10124 if (!event.target.closest("[data-pager]")) return; 10125 const marker = event.target.closest("a, button"); 10126 if (!marker) return; 10127 event.preventDefault(); 10128 const slideId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(markerIdName); 10129 const targetSlide = track.querySelector(`#${slideId}`); 10130 targetSlide?.scrollIntoView({ 10131 block: "nearest", 10132 inline: "start", 10133 behavior: "smooth" 10134 }); 10135 } 10136 setupSlides(); 10137 setupNav(); 10138 if (useAutoPager) { 10139 createPager(); 10140 } else { 10141 setupPager(); 10142 } 10143 setupObservers(); 10144 setupMutationObserver(); 10145 setupResizeObserver(); 10146 function eventHandler(event) { 10147 const target = event.target.closest( 10148 "[data-next], [data-prev], [data-pager]" 10149 ); 10150 if (!target) return; 10151 if (event.type === "click") { 10152 if (target.hasAttribute("data-next")) { 10153 goToSlideDir("next"); 10154 } else if (target.hasAttribute("data-prev")) { 10155 goToSlideDir("prev"); 10156 } else if (target.closest("[data-pager]")) { 10157 pagerToSlide(event); 10158 } 10159 } 10160 if (event.type === "keydown" && target.closest("[data-pager]")) { 10161 if (event.key === "ArrowRight") { 10162 goToSlideDir("next"); 10163 } else if (event.key === "ArrowLeft") { 10164 goToSlideDir("prev"); 10165 } 10166 } 10167 } 10168 el.addEventListener("click", eventHandler); 10169 el.addEventListener("keydown", eventHandler); 10170 cleanup(() => { 10171 inViewObserver?.disconnect(); 10172 mutationObserver?.disconnect(); 10173 resizeObserver?.disconnect(); 10174 el.removeEventListener("click", eventHandler); 10175 el.removeEventListener("keydown", eventHandler); 10176 }); 10177 }); 10178 } 10179 10180 document.addEventListener("alpine:init", () => { 10181 window.Alpine.plugin(alpineSnapSlider); 10182 }); 10183 })(); 10184</script>
vendor: 1 bytes, line 10184
10184
10185<script> 10186 (() => { 10187 // src/dialog.js 10188 function dialog_default(Alpine) { 10189 Alpine.directive("htmldialog", fylgjaAlpineDialog); 10190 function fylgjaAlpineDialog(el, { expression, modifiers }, { evaluateLater, cleanup }) { 10191 const evaluate = expression.length ? evaluateLater(expression) : () => {}; 10192 const canEvaluate = expression.length > 0; 10193 const lockPageScroll = modifiers.includes("noscroll"); 10194 const closeBy = el.getAttribute("closeby") || modifierValue(modifiers, "closeby", "closerequest"); 10195 el.style.display = null; 10196 el.style.length === 0 && el.removeAttribute("style"); 10197 if (el._x_isShown) { 10198 open(); 10199 } 10200 const closeBySupported = (() => { 10201 return "closedBy" in HTMLDialogElement.prototype; 10202 })(); 10203 function scrollLock(use = true) { 10204 document.body.style.overflow = use ? "hidden" : ""; 10205 } 10206 function dialogSubmit(event) { 10207 if (event.target.getAttribute("method") === "dialog" || event.submitter?.getAttribute("formmethod") === "dialog") { 10208 event.preventDefault(); 10209 evaluate(); 10210 } 10211 } 10212 function escapeDialog(event) { 10213 if (event.key !== "Escape") return; 10214 event.preventDefault(); 10215 if (closeBy === "none") return; 10216 evaluate(); 10217 } 10218 function handleCloseByEvent(event) { 10219 if (event.target !== el) return; 10220 const rect = el.getBoundingClientRect(); 10221 const isInDialog = rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width; 10222 if (!isInDialog) { 10223 if (closeBy === "any") { 10224 if (closeBySupported) { 10225 event.preventDefault(); 10226 } 10227 evaluate(); 10228 } 10229 } 10230 } 10231 function handleCloseEvent() { 10232 evaluate(); 10233 } 10234 function open() { 10235 if (el.hasAttribute("open")) return; 10236 el.showModal(); 10237 scrollLock(lockPageScroll); 10238 } 10239 function close() { 10240 if (!el.hasAttribute("open")) return; 10241 el.close(); 10242 scrollLock(false); 10243 } 10244 el._x_doShow = () => open(); 10245 el._x_doHide = () => close(); 10246 el.addEventListener("keydown", escapeDialog); 10247 el.addEventListener("submit", dialogSubmit); 10248 el.addEventListener("click", handleCloseByEvent); 10249 el.addEventListener("cancel", handleCloseEvent); 10250 cleanup(() => { 10251 el.removeEventListener("keydown", escapeDialog); 10252 el.removeEventListener("submit", dialogSubmit); 10253 el.removeEventListener("click", handleCloseByEvent); 10254 el.removeEventListener("cancel", handleCloseEvent); 10255 scrollLock(false); 10256 }); 10257 } 10258 } 10259 function modifierValue(modifiers, key, fallback) { 10260 if (modifiers.indexOf(key) === -1) return fallback; 10261 const rawValue = modifiers[modifiers.indexOf(key) + 1]; 10262 if (!rawValue) return fallback; 10263 if (key === "closeby") { 10264 const allowedValues = ["auto", "none", "closerequest", "any"]; 10265 const options = allowedValues.join(", "); 10266 if (!allowedValues.includes(rawValue)) { 10267 console.warn( 10268 `"${rawValue}" is not one of the allowed values for closeby: ${options}` 10269 ); 10270 return fallback; 10271 } 10272 } 10273 return rawValue; 10274 } 10275 10276 // src/cdn.js 10277 document.addEventListener("alpine:init", () => { 10278 window.Alpine.plugin(dialog_default); 10279 }); 10280 })(); 10281 //# sourceURL=alpine-htmldialog.js 10282</script>
vendor: 1 bytes, line 10282
10282
10283<script> 10284 (() => { 10285 function src_default(Alpine) { 10286 Alpine.directive("intersect", Alpine.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { 10287 let evaluate = evaluateLater(expression); 10288 let options = { 10289 rootMargin: getRootMargin(modifiers), 10290 threshold: getThreshold(modifiers) 10291 }; 10292 let observer = new IntersectionObserver((entries) => { 10293 entries.forEach((entry) => { 10294 if (entry.isIntersecting === (value === "leave")) 10295 return; 10296 evaluate(); 10297 modifiers.includes("once") && observer.disconnect(); 10298 }); 10299 }, options); 10300 observer.observe(el); 10301 cleanup(() => { 10302 observer.disconnect(); 10303 }); 10304 })); 10305 } 10306 function getThreshold(modifiers) { 10307 if (modifiers.includes("full")) 10308 return 0.99; 10309 if (modifiers.includes("half")) 10310 return 0.5; 10311 if (!modifiers.includes("threshold")) 10312 return 0; 10313 let threshold = modifiers[modifiers.indexOf("threshold") + 1]; 10314 if (threshold === "100") 10315 return 1; 10316 if (threshold === "0") 10317 return 0; 10318 return Number(`.${threshold}`); 10319 } 10320 function getLengthValue(rawValue) { 10321 let match = rawValue.match(/^(-?[0-9]+)(px|%)?$/); 10322 return match ? match[1] + (match[2] || "px") : void 0; 10323 } 10324 function getRootMargin(modifiers) { 10325 const key = "margin"; 10326 const fallback = "0px 0px 0px 0px"; 10327 const index = modifiers.indexOf(key); 10328 if (index === -1) 10329 return fallback; 10330 let values = []; 10331 for (let i = 1; i < 5; i++) { 10332 values.push(getLengthValue(modifiers[index + i] || "")); 10333 } 10334 values = values.filter((v) => v !== void 0); 10335 return values.length ? values.join(" ").trim() : fallback; 10336 } 10337 10338 document.addEventListener("alpine:init", () => { 10339 window.Alpine.plugin(src_default); 10340 }); 10341 })(); 10342 //# sourceURL=alpine-intersect.js 10343</script>
vendor: 1 bytes, line 10343
10343
10344<script> 10345 for (const [selector, deferUntil] of Object.entries({".product-slider section[x-data]:not([x-data] [x-data])":"intersect",".product-info [x-data]:not([x-data] [x-data])":"intersect","#filters-content [x-data]:not([x-data] [x-data])":"intersect","#review_form":"intersect","section[x-data^=initRecentlyViewedProductsComponent]":"intersect","div[x-data^=initBundleOptions]":"intersect","#product_addtocart_form [x-data]:not([x-data] [x-data])":"intersect","#notice-cookie-block":"idle"})) { 10346 document.querySelectorAll(selector).forEach(el => el.setAttribute('x-defer', `${deferUntil}`)); 10347 } 10348 //# sourceURL=alpine-defer-rules.js 10349</script>
vendor: 1 bytes, line 10349
10349
10350<script> 10351 (() => { 10352 const hasAlpine = new Promise(resolve => { 10353 window.addEventListener('alpine:initialized', resolve, {once: true, passive: true}); 10354 }); 10355 10356 const hasInteract = new Promise(resolve => { 10357 (events => { 10358 const onInteract = () => { 10359 resolve(); 10360 events.forEach(type => window.removeEventListener(type, onInteract)); 10361 } 10362 events.forEach(type => window.addEventListener(type, onInteract, {once: true, passive: true})) 10363 })(['touchstart', 'mouseover', 'wheel', 'scroll', 'keydown']) 10364 }); 10365 10366 const onIntersect = (el) => { 10367 return new Promise(resolve => { 10368 const observer = new IntersectionObserver(entries => { 10369 for (const entry of entries) { 10370 if (entry.isIntersecting) { 10371 observer.disconnect() 10372 resolve(); 10373 } 10374 } 10375 }, {}); 10376 observer.observe(el); 10377 }); 10378 } 10379 10380 function runComponent(el) { 10381 hasAlpine.then(() => { 10382 el.removeAttribute('x-ignore'); 10383 queueMicrotask(() => Alpine.initTree(el)); 10384 }); 10385 } 10386 10387 function initDeferredComponents() { 10388 document.querySelectorAll('[x-data][x-defer]').forEach(el => { 10389 el.setAttribute('x-ignore', ''); 10390 const deferUntil = (el.getAttribute('x-defer') || '').trim(); 10391 switch (deferUntil) { 10392 case 'interact': 10393 hasInteract.then(() => runComponent(el)); 10394 break; 10395 case 'intersect': 10396 onIntersect(el).then(() => runComponent(el)) 10397 break; 10398 case 'idle': 10399 window.requestIdleCallback 10400 ? window.requestIdleCallback(() => runComponent(el), {timeout: 4000}) 10401 : setTimeout(() => runComponent(el), 4000); 10402 break; 10403 case 'eager': 10404 runComponent(el); 10405 break; 10406 default: 10407 if (deferUntil.startsWith('event:') && deferUntil.length > 6) { 10408 window.addEventListener(deferUntil.substring(6), () => runComponent(el), {once: true, passive: true}); 10409 } 10410 } 10411 }); 10412 } 10413 10414 window.addEventListener('alpine:init', initDeferredComponents, {once: true, passive: true}); 10415 })(); 10416 //# sourceURL=alpine-defer.js 10417</script>
vendor: 1 bytes, line 10417
10417
10418<script src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js" defer="1"></script>
vendor: 1 bytes, line 10418
10418
10419<script type="module" 10420 src="https://www.mueblesbonitos.com/static/frontend/Mb/Hyva2/es_ES/Hyva_Theme/js/alpine3.min.js" 10421 defer 10422 crossorigin 10423></script>
vendor: 1 bytes, line 10423
10423
10424<script> 10425 function dispatchMessages(messages, hideAfter) { 10426 const messagesEvent = new CustomEvent("messages-loaded", { 10427 detail: { 10428 messages: messages, 10429 hideAfter: hideAfter 10430 } 10431 }); 10432 window.dispatchEvent(messagesEvent); 10433 } 10434 10435 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) { 10436 console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script"); 10437 } 10438 10439 (function( hyva, undefined ) { 10440 10441 hyva.initFormKey = () => { 10442 const inputSelector = 'input[name="form_key"]', 10443 formKey = hyva.getFormKey(); 10444 10445 Array.from(document.querySelectorAll(inputSelector)).map(function (input) { 10446 input.value = formKey 10447 }); 10448 } 10449 10450 hyva.initMessages = () => { 10451 try { 10452 const messages = hyva.getCookie('mage-messages'); 10453 window.mageMessages = messages ? JSON.parse(decodeURIComponent(messages).replace(/\+/g, ' ')) : []; 10454 10455 dispatchMessages(window.mageMessages); 10456 10457 // empty `mage-messages` cookie 10458 const skipSetDomain = true; 10459 hyva.setCookie('mage-messages','', -1, skipSetDomain); 10460 10461 } catch (error) { 10462 console.warn('Error parsing Cookie Messages:', error); 10463 } 10464 } 10465 10466 window.addEventListener('DOMContentLoaded', hyva.initFormKey); 10467 hyva.alpineInitialized(hyva.initMessages) 10468 10469 }( window.hyva = window.hyva || {} )); 10470 //# sourceURL=hyva-cookies.js 10471</script>
vendor: 1 bytes, line 10471
10471
10472<script> 10473 { 10474 const private_content_key = 'mage-cache-storage'; 10475 const private_content_expire_key = 'mage-cache-timeout'; 10476 const private_content_version_key = 'private_content_version'; 10477 const section_data_ids_key = 'section_data_ids'; 10478 const mage_cache_session_id_key = 'mage-cache-sessid'; 10479 const last_visited_store_key = 'last_visited_store'; 10480 10481 const ttl = 3600; 10482 10483 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) { 10484 console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script"); 10485 } 10486 10487 function loadSectionData () { 10488 const browserStorage = hyva.getBrowserStorage(); 10489 if (!browserStorage) { 10490 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 10491 [{ 10492 type: "warning", 10493 text: "Por favor, active LocalStorage en su navegador." 10494 }] 10495 ); 10496 return; 10497 } 10498 try { 10499 let isInvalid = false; 10500 10501 if (hyva.getCookie(last_visited_store_key) !== CURRENT_STORE_CODE) { 10502 isInvalid = true; 10503 } 10504 hyva.setCookie(last_visited_store_key, CURRENT_STORE_CODE, false, false); 10505 10506 if (!hyva.getCookie(mage_cache_session_id_key)) { 10507 isInvalid = true; 10508 browserStorage.removeItem(private_content_key); 10509 const skipSetDomain = true; 10510 const days = false; 10511 hyva.setCookie(mage_cache_session_id_key, true, days, skipSetDomain) 10512 } 10513 10514 const cookieVersion = hyva.getCookie(private_content_version_key); 10515 const storageVersion = browserStorage.getItem(private_content_version_key); 10516 10517 if (cookieVersion && !storageVersion || cookieVersion !== storageVersion) { 10518 isInvalid = true; 10519 } 10520 10521 const privateContentExpires = browserStorage.getItem(private_content_expire_key); 10522 if (privateContentExpires && new Date(privateContentExpires) < new Date()) { 10523 browserStorage.removeItem(private_content_key); 10524 } 10525 10526 if (isInvalid && cookieVersion) { 10527 fetchPrivateContent([]); 10528 } else if (cookieVersion && storageVersion && cookieVersion === storageVersion) { 10529 const privateContent = JSON.parse(browserStorage.getItem(private_content_key)); 10530 if ( 10531 privateContent && 10532 privateContentExpires && 10533 privateContent.cart && 10534 privateContent.customer 10535 ) { 10536 dispatchPrivateContent(privateContent); 10537 } else { 10538 fetchPrivateContent([]); 10539 } 10540 } else { 10541 if (document.getElementById('default-section-data')) { 10542 const privateContent = JSON.parse(document.getElementById('default-section-data').innerText.trim()); 10543 dispatchPrivateContent(privateContent); 10544 } else { 10545 dispatchPrivateContent({}); 10546 } 10547 } 10548 10549 } catch (error) { 10550 console.warn('Error retrieving Private Content:', error); 10551 } 10552 } 10553 10554 hyva.alpineInitialized(loadSectionData) 10555 window.addEventListener('reload-customer-section-data', loadSectionData); 10556 10557 window.processSectionDataBeforeDispatch = window.processSectionDataBeforeDispatch || (data => data); 10558 10559 function dispatchPrivateContent(data) { 10560 10561 const privateContentEvent = new CustomEvent("private-content-loaded", { 10562 detail: { 10563 data: window.processSectionDataBeforeDispatch(data) 10564 } 10565 }); 10566 window.dispatchEvent(privateContentEvent); 10567 } 10568 10569 function fetchPrivateContent(sections) { 10570 fetch(`${BASE_URL}customer/section/load/?sections=${encodeURIComponent(sections.join(','))}`, { 10571 method: 'GET', 10572 headers: { 10573 'Content-Type': 'application/json', 10574 'X-Requested-With': 'XMLHttpRequest' 10575 } 10576 }) 10577 .then(response => response.ok && response.json()) 10578 .then( 10579 data => { 10580 if (data) { 10581 try { 10582 const browserStorage = hyva.getBrowserStorage(); 10583 10584 // merge new data preserving non-invalidated sections 10585 const oldSectionData = JSON.parse(browserStorage.getItem(private_content_key) || '{}') || {}; 10586 10587 if ((! data.cart || ! data.cart.cartId) && oldSectionData['checkout-data']) { 10588 delete oldSectionData['checkout-data']; 10589 } 10590 const newSectionData = Object.assign(oldSectionData, data); 10591 10592 dispatchPrivateContent(newSectionData); 10593 10594 // don't persist messages, they've been dispatched already 10595 if (newSectionData.messages && newSectionData.messages.messages ) { 10596 newSectionData.messages.messages = []; 10597 } 10598 10599 browserStorage.setItem(private_content_key, JSON.stringify(newSectionData)); 10600 10601 const expiresAt = new Date(Date.now() + (ttl * 1000)).toISOString(); 10602 browserStorage.setItem(private_content_expire_key, expiresAt); 10603 10604 const newCookieVersion = hyva.getCookie(private_content_version_key); 10605 browserStorage.setItem(private_content_version_key, newCookieVersion); 10606 10607 // We don't need the section_data_ids in Hyvä, but we store them for compatibility 10608 // with Luma Fallback. Otherwise, not all sections are loaded in Luma Checkout 10609 hyva.setCookie( 10610 section_data_ids_key, 10611 JSON.stringify( 10612 Object.keys(data).reduce((sectionDataIds, sectionKey) => { 10613 sectionDataIds[sectionKey] = data[sectionKey]['data_id']; 10614 return sectionDataIds; 10615 }, {}) 10616 ), 10617 false, 10618 true 10619 ); 10620 } catch (error) { 10621 console.warn("Couldn't store privateContent", error); 10622 } 10623 } 10624 } 10625 ); 10626 } 10627 } 10628 //# sourceURL=hyva-private-content.js 10629</script>
vendor: 1 bytes, line 10629
10629
10630<script> 10631 (() => { 10632 document.addEventListener('submit', event => event.target.action = event.target.action.replace('%25uenc%25', hyva.getUenc())); 10633 })() 10634</script>
vendor: 1 bytes, line 10634
10634
10635<script> 10636 (events => { 10637 const dispatchUserInteractionEvent = () => { 10638 events.forEach(type => window.removeEventListener(type, dispatchUserInteractionEvent)) 10639 window.dispatchEvent(new Event('init-external-scripts')) 10640 }; 10641 events.forEach(type => window.addEventListener(type, dispatchUserInteractionEvent, {once: true, passive: true})) 10642 })(['touchstart', 'mousemove', 'wheel', 'scroll', 'keydown']); 10643 //# sourceURL=hyva-init-external-scripts.js 10644</script>
vendor: 1 bytes, line 10644
10644
10645<script> 10646 function initWishlist() { 10647 return { 10648 addToWishlist() { 10649 const productId = this.$el.dataset.productId; 10650 const formKey = hyva.getFormKey(); 10651 const postUrl = BASE_URL + 'wishlist/index/add/'; 10652 10653 fetch(postUrl, { 10654 "headers": { 10655 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 10656 }, 10657 "body": "form_key=" + formKey + "&product=" + productId + "&uenc=" + hyva.getUenc(), 10658 "method": "POST", 10659 "mode": "cors", 10660 "credentials": "include" 10661 }).then(function (response) { 10662 if (response.redirected) { 10663 window.location.href = response.url; 10664 } else if (response.ok) { 10665 return response.json(); 10666 } else { 10667 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 10668 [{ 10669 type: "warning", 10670 text: "No\u0020se\u0020ha\u0020podido\u0020a\u00F1adir\u0020el\u0020art\u00EDculo\u0020a\u0020la\u0020lista\u0020de\u0020deseos." 10671 }], 5000 10672 ); 10673 } 10674 }).then(function (response) { 10675 if (!response) { return } 10676 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 10677 [{ 10678 type: (response.success) ? "success" : "error", 10679 text: (response.success) 10680 ? "Producto\u0020has\u0020been\u0020added\u0020to\u0020your\u0020Wish\u0020List." 10681 : response.error_message 10682 }], 5000 10683 ); 10684 const reloadCustomerDataEvent = new CustomEvent("reload-customer-section-data"); 10685 window.dispatchEvent(reloadCustomerDataEvent); 10686 }).catch(function (error) { 10687 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 10688 [{ 10689 type: "error", 10690 text: error 10691 }], 5000 10692 ); 10693 }); 10694 } 10695 } 10696 } 10697 window.addEventListener('alpine:init', () => Alpine.data('initWishlist', initWishlist), {once: true}) 10698</script>
10698 10699
10699<script> 10700 function initProductItemImage() { 10701 return { 10702 updateImage() { 10703 const image = this.$event.detail.medium; 10704 if (!image) return; 10705 this.$el.src = image; 10706 } 10707 } 10708 } 10709 window.addEventListener('alpine:init', () => { 10710 Alpine.data('initProductItemImage', initProductItemImage); 10711 }, { once: true }); 10712</script>
vendor: 1 bytes, line 10712
10712
10713<script> 10714 function initPriceBox() 10715 { 10716 return { 10717 updatePrice() { 10718 const priceData = this.$event.detail; 10719 const regularPriceLabel = this.$root.querySelector('.normal-price .price-label'); 10720 const regularPriceElement = this.$root.querySelector('.normal-price [data-price-type=finalPrice].price-wrapper .price'); 10721 const basePriceElement = this.$root.querySelector('.normal-price [data-price-type=basePrice].price-wrapper .price'); 10722 if (priceData.finalPrice.amount < priceData.oldPrice.amount) { 10723 regularPriceLabel && regularPriceLabel.classList.add('hidden'); 10724 } else { 10725 regularPriceLabel && regularPriceLabel.classList.remove('hidden'); 10726 } 10727 regularPriceElement && (regularPriceElement.innerText = hyva.formatPrice(priceData.finalPrice.amount)); 10728 basePriceElement && (basePriceElement.innerText = hyva.formatPrice(priceData.basePrice.amount)); 10729 }, 10730 htmlPriceIdGroup() { 10731 return [this.$el.dataset.priceId]; 10732 }, 10733 htmlPriceId() { 10734 return this.$id(this.$el.closest('[data-price-id]').dataset.priceId); 10735 } 10736 } 10737 } 10738 window.addEventListener('alpine:init', () => Alpine.data('initPriceBox', initPriceBox), {once: true}) 10739</script>
vendor: 1 bytes, line 10739
10739
10740<script> 10741 function initPriceBox() 10742 { 10743 return { 10744 updatePrice() { 10745 const priceData = this.$event.detail; 10746 const regularPriceLabel = this.$root.querySelector('.normal-price .price-label'); 10747 const regularPriceElement = this.$root.querySelector('.normal-price [data-price-type=finalPrice].price-wrapper .price'); 10748 const basePriceElement = this.$root.querySelector('.normal-price [data-price-type=basePrice].price-wrapper .price'); 10749 if (priceData.finalPrice.amount < priceData.oldPrice.amount) { 10750 regularPriceLabel && regularPriceLabel.classList.add('hidden'); 10751 } else { 10752 regularPriceLabel && regularPriceLabel.classList.remove('hidden'); 10753 } 10754 regularPriceElement && (regularPriceElement.innerText = hyva.formatPrice(priceData.finalPrice.amount)); 10755 basePriceElement && (basePriceElement.innerText = hyva.formatPrice(priceData.basePrice.amount)); 10756 }, 10757 htmlPriceIdGroup() { 10758 return [this.$el.dataset.priceId]; 10759 }, 10760 htmlPriceId() { 10761 return this.$id(this.$el.closest('[data-price-id]').dataset.priceId); 10762 } 10763 } 10764 } 10765 window.addEventListener('alpine:init', () => Alpine.data('initPriceBox', initPriceBox), {once: true}) 10766</script>
vendor: 1 bytes, line 10766
10766
10767<script> 10768 function initConfigurableOptions(productId, optionConfig) { 10769 10770 function findPathParam(key) { 10771 const baseUrl = (BASE_URL.substring(0, 2) === '//' ? 'http:' : '') + BASE_URL; 10772 const baseUrlParts = (new URL(baseUrl)).pathname.replace(/\/$/, '').split('/'); 10773 const pathParts = window.location.pathname.split('/').slice(baseUrlParts.length + 3); 10774 for (let i = 0; i < pathParts.length; i += 2) { 10775 if (pathParts[i] === key && pathParts.length > i) { 10776 return pathParts[i + 1]; 10777 } 10778 } 10779 } 10780 10781 return { 10782 optionConfig, 10783 productId, 10784 itemId: (new URLSearchParams(window.location.search)).get('id') || findPathParam('id'), 10785 allowedAttributeOptions: [], 10786 selectedValues: [], 10787 init() { 10788 this.buildLookupMap(); 10789 this.findAllowedAttributeOptions(); 10790 this.$nextTick(() => { 10791 if (typeof this.optionConfig.defaultValues === 'object') { 10792 for (const [attributeId, value] of Object.entries(this.optionConfig.defaultValues)) { 10793 this.changeOption(attributeId, value + ''); 10794 } 10795 } 10796 this.preselectQuerystringItems(); 10797 this.preselectLocationHashItems(); 10798 }); 10799 }, 10800 productIndex: 0, 10801 productIndexForPrice: 0, 10802 productIndexesMap: null, 10803 productIndexesKeys: null, 10804 attributeCount: 0, 10805 optionIsActive() { 10806 const attributeId = this.getDataAttributeId(this.$el); 10807 return !!this.getAllowedAttributeOptions(attributeId).find( 10808 option => option.id === this.item.id 10809 ) 10810 }, 10811 ['!optionIsActive']() { 10812 return ! this.optionIsActive(); 10813 }, 10814 ['notOptionIsActive']() { 10815 return ! this.optionIsActive(); 10816 }, 10817 optionIsEnabled() { 10818 const attributeId = this.getDataAttributeId(this.$el); 10819 10820 for (const productId in this.optionConfig.index) { 10821 if (this.optionConfig.index[productId][attributeId] === this.item.id) { 10822 return true; 10823 } 10824 } 10825 return false; 10826 }, 10827 10828 isOptionEnabledAndInStock() { 10829 return this.optionIsEnabled() && this.optionIsActive(); 10830 }, 10831 isOptionEnabledAndOutOfStock() { 10832 return this.optionIsEnabled() && ! this.optionIsActive(); 10833 }, 10834 findSimpleIndex() { 10835 this.productIndex = this.calculateSimpleIndexForPartialSelection(this.selectedValues); 10836 this.productIndexForPrice = this.findCheapestProductForPartialSelection(this.selectedValues); 10837 }, 10838 calculateSimpleIndexForPartialSelection(selectedValues) { 10839 if (selectedValues.length === 0) return 0; 10840 return this.findProductIdsForPartialSelection(selectedValues)[0]; 10841 }, 10842 buildLookupMap() { 10843 this.productIndexesMap = new Map(); 10844 this.attributeCount = Object.keys(this.optionConfig.attributes).length; 10845 for (const id in this.optionConfig.index) { 10846 const options = this.optionConfig.index[id]; 10847 if (! this.productIndexesKeys) { 10848 this.productIndexesKeys = Object.keys(options).sort(); 10849 } 10850 const key = JSON.stringify(options, this.productIndexesKeys); 10851 this.productIndexesMap.set(key, id); 10852 } 10853 }, 10854 calculateSimpleIndexForFullSelection(selectedValues) { 10855 if (! this.isFullSelection(selectedValues)) return false; 10856 10857 const attrKeys = this.productIndexesKeys || []; 10858 const normalised = {}; 10859 for (let i = 0; i < attrKeys.length; i++) { 10860 normalised[attrKeys[i]] = selectedValues[attrKeys[i]]; 10861 } 10862 const queryKey = JSON.stringify(normalised, attrKeys); 10863 return this.productIndexesMap.get(queryKey); 10864 }, 10865 findAllowedAttributeOptions() { 10866 this.allowedAttributeOptions = this.calculateAllowedAttributeOptions(this.selectedValues); 10867 }, 10868 calculateAllowedAttributeOptions(selectedValues) { 10869 const allAttributes = this.optionConfig.attributes; 10870 const allAttributesSorted = Object.values(allAttributes).sort((a,b) => { 10871 return a.position - b.position 10872 }); 10873 10874 const newAllowedAttributeOptions = []; 10875 10876 allAttributesSorted.forEach(attribute => { 10877 const selectionWithoutAttr = Object.assign({}, this.removeAttrFromSelection(selectedValues, attribute.id)); 10878 const availableIndexes = this.calculateAvailableProductIndexes(selectionWithoutAttr); 10879 newAllowedAttributeOptions[attribute.id] = allAttributes[attribute.id].options.filter(option => { 10880 return !!option.products.find(product => { 10881 return availableIndexes.includes(product); 10882 }) 10883 }); 10884 }); 10885 return newAllowedAttributeOptions; 10886 }, 10887 calculateAvailableProductIndexes(selectedOptions) { 10888 if (Object.keys(selectedOptions).length === 0) { 10889 if (Object.values(this.optionConfig.salable || {}).length) { 10890 return [].concat.apply([], [].concat.apply([], Object.values(this.optionConfig.salable).map(Object.values))).filter((x, i, a) => a.indexOf(x) === i) 10891 } 10892 return Object.keys(this.optionConfig.index); 10893 } 10894 10895 const selectedIds = Object.keys(selectedOptions); 10896 if (Object.values(this.optionConfig.salable || {}).length) { 10897 const selectedOptionIndexes = selectedIds.map(attrId => { 10898 const optionValue = selectedOptions[attrId]; 10899 return this.optionConfig.salable[attrId] && this.optionConfig.salable[attrId][optionValue] || [] 10900 }) 10901 return selectedOptionIndexes.reduce((acc, optionIndexes) => { 10902 return acc.filter(index => optionIndexes.includes(index)); 10903 }); 10904 } else { 10905 const productIndexes = this.optionConfig.index; 10906 return Object.keys(productIndexes).filter(index => { 10907 for (const attrId of selectedIds) { 10908 if (productIndexes[index][attrId] !== `${selectedOptions[attrId]}`) return false 10909 } 10910 return true 10911 }); 10912 } 10913 }, 10914 findAttributeByOptionId(optionId) { 10915 for (const attributeId in this.optionConfig.attributes) { 10916 const attributeOptions = this.optionConfig.attributes[attributeId].options || []; 10917 if (attributeOptions.find(option => option.id === optionId)) { 10918 return attributeId; 10919 } 10920 } 10921 }, 10922 getAllowedAttributeOptions(attributeId) { 10923 return this.allowedAttributeOptions[attributeId] || [] 10924 }, 10925 getDataAttributeId(el) { 10926 return el.closest('[data-attribute-id]').dataset.attributeId; 10927 }, 10928 getDataOptionId(el) { 10929 return el.closest('[data-option-id]').dataset.optionId; 10930 }, 10931 getAllAttributeOptions(attributeId) { 10932 if (attributeId === undefined) { 10933 attributeId = this.getDataAttributeId(this.$el); 10934 } 10935 return ( 10936 this.optionConfig.attributes[attributeId] && 10937 this.optionConfig.attributes[attributeId].options 10938 ) || [] 10939 }, 10940 getProductIdsForOption(option) { 10941 const attributeId = this.findAttributeByOptionId(option.id); 10942 const allOptions = this.optionConfig.attributes[attributeId]; 10943 const opt = (allOptions && allOptions.options || []).find(o => o.id === option.id); 10944 return opt && opt.products 10945 ? opt.products 10946 : []; 10947 }, 10948 findProductIdsForPartialSelection(optionSelection) { 10949 const candidateProducts = Object.values(optionSelection).reduce((candidates, optionId) => { 10950 const newCandidates = this.getProductIdsForOption({id: optionId}); 10951 return candidates === null 10952 ? newCandidates 10953 : candidates.filter(productId => newCandidates.includes(productId)); 10954 }, null); 10955 return candidateProducts || []; 10956 },
10957 findCheapestProductForPartialSelection(optionSelection) { 10958 const candidateProducts = this.findProductIdsForPartialSelection(optionSelection); 10959 return candidateProducts.reduce((cheapest, simpleIdx) => { 10960 // in the first iteration we start with simpleIdx as the currently cheapest product 10961 if (! this.optionConfig.optionPrices[cheapest]) return simpleIdx; 10962 const knownCheapestPrice = this.optionConfig.optionPrices[cheapest].finalPrice.amount; 10963 return knownCheapestPrice > this.optionConfig.optionPrices[simpleIdx].finalPrice.amount 10964 ? simpleIdx 10965 : cheapest; 10966 }, 0) 10967 }, 10968 findProductIdToUseForOptionPrice(option) { 10969 // try to find a product for a complete selection 10970 const attributeId = this.findAttributeByOptionId(option.id); 10971 const optionSelection = Object.assign({}, this.selectedValues, {[attributeId]: option.id}); 10972 const matchingSimpleIndex = this.calculateSimpleIndexForFullSelection(optionSelection); 10973 // if there is no complete selection, use the cheapest product for the option 10974 return matchingSimpleIndex || this.findCheapestProductForPartialSelection(optionSelection); 10975 }, 10976 getAttributeOptionLabel() { 10977 const option = this.item; 10978 const optionProduct = this.findProductIdToUseForOptionPrice(option); 10979 10980 if ((! optionProduct) || (optionProduct === this.productIndexForPrice)) { 10981 return option.label; 10982 } 10983 10984 const currentPrice = this.getOptionPriceAdjustmentBasePrice(); 10985 10986 if (this.optionConfig.optionPrices[optionProduct]) { 10987 const optionPrice = this.optionConfig.optionPrices[optionProduct].finalPrice.amount; 10988 if (optionPrice !== currentPrice){ 10989 return option.label + ' ' + hyva.formatPrice(optionPrice - currentPrice, true); 10990 } 10991 } 10992 return option.label; 10993 }, 10994 getOptionPriceAdjustmentBasePrice() { 10995 if (this.optionConfig.optionPrices[this.productIndexForPrice]) { 10996 return this.optionConfig.optionPrices[this.productIndexForPrice].finalPrice.amount 10997 } 10998 return this.optionConfig.prices.finalPrice.amount; // default price if no option selection 10999 }, 11000 isSelected() { 11001 const attributeId = this.getDataAttributeId(this.$el); 11002 return this.selectedValues[attributeId] === this.item.id; 11003 }, 11004 clearOptionIfActive() { 11005 const attributeId = this.getDataAttributeId(this.$el); 11006 if (this.selectedValues[attributeId] === this.item.id) { 11007 this.blurLabel() 11008 this.changeOption(attributeId, '') 11009 } 11010 }, 11011 removeAttrFromSelection(selectedValues, attributeId) { 11012 attributeId = parseInt(attributeId); 11013 return selectedValues.reduce((newSelection, val, attr) => { 11014 if (attr !== attributeId) { 11015 newSelection[attr] = val; 11016 } 11017 return newSelection; 11018 }, []); 11019 }, 11020 onChangeOption() { 11021 const attributeId = this.getDataAttributeId(this.$event.target); 11022 const optionId = this.$event.target.value; 11023 this.changeOption(attributeId, optionId) 11024 }, 11025 changeOption(attributeId, value) { 11026 if (value === '') { 11027 this.selectedValues = this.removeAttrFromSelection(this.selectedValues, attributeId) 11028 } else if (value && this.getAllowedAttributeOptions(attributeId).find(option => option.id === value)) { 11029 this.selectedValues[attributeId] = value; 11030 } 11031 this.findSimpleIndex(); 11032 this.findAllowedAttributeOptions(); 11033 this.updatePrices(); 11034 this.updateGallery(); 11035 11036 const candidates = this.findProductIdsForPartialSelection(this.selectedValues); 11037 11038 window.dispatchEvent( 11039 new CustomEvent( 11040 'configurable-selection-changed', 11041 { 11042 detail: { 11043 productId: this.productId, 11044 optionId: attributeId, 11045 value: value, 11046 productIndex: this.productIndex, 11047 selectedValues: this.selectedValues, 11048 candidates: candidates, 11049 skuCandidates: Object.values(candidates).map(id =>
11049 this.optionConfig.sku?.[id] ?? null).filter(Boolean), 11050 } 11051 } 11052 ) 11053 ); 11054 }, 11055 calculateIsMinimalPrice() { 11056 return ! this.isFullSelection(this.selectedValues); 11057 }, 11058 isFullSelection(selectedValues) { 11059 return Object.keys(selectedValues).length === this.attributeCount; 11060 }, 11061 updatePrices() { 11062 const value = this.optionConfig.optionPrices[this.productIndexForPrice] || this.optionConfig.prices; 11063 window.dispatchEvent( 11064 new CustomEvent( 11065 "update-prices-" + this.productId, 11066 { 11067 detail: Object.assign( 11068 value, 11069 { isMinimalPrice: this.calculateIsMinimalPrice() } 11070 ) 11071 } 11072 ) 11073 ); 11074 }, 11075 updateGallery () { 11076 if (this.productIndex) { 11077 const images = this.optionConfig.images[this.productIndex]; 11078 images && window.dispatchEvent(new CustomEvent( 11079 "update-gallery", 11080 { detail: this.sortImagesByPosition(images) } 11081 )); 11082 } else { 11083 window.dispatchEvent(new Event("reset-gallery")); 11084 } 11085 }, 11086 sortImagesByPosition(images) { 11087 return images.sort((x, y) => { 11088 return x.position === y.position ? 0 : (parseInt(x.position) > parseInt(y.position) ? 1 : -1) 11089 }); 11090 }, 11091 onGetCartData() { 11092 const data = this.$event.detail.data; 11093 }, 11094 preselectCartItems(data) { 11095 // pre-select options based on cart data for current (quote) itemId 11096 const cart = data && data.cart; 11097 if (cart && cart.items) { 11098 const cartItem = cart.items.find((item) => { 11099 return ( 11100 item.item_id === this.itemId 11101 && item.product_id === this.productId 11102 ) 11103 }); 11104 if (cartItem && cartItem.options && cartItem.options.length) { 11105 cartItem.options.map(option => { 11106 this.changeOption(option.option_id, option.option_value); 11107 }) 11108 } 11109 } 11110 }, 11111 preselectQuerystringItems() { 11112 // pre-select option like ?size=167 11113 const urlQueryParams = new URLSearchParams(window.location.search.replace('?','')); 11114 this.preselectItemsBasedOnLocation(attribute => urlQueryParams.get(attribute.code)); 11115 }, 11116 preselectLocationHashItems() { 11117 // pre-select option like #144=167 11118 const urlHashParams = new URLSearchParams(window.location.hash.replace('#','')); 11119 this.preselectItemsBasedOnLocation(attribute => urlHashParams.get(attribute.id)); 11120 }, 11121 preselectItemsBasedOnLocation(getLocationValue) { 11122 Object.values(this.optionConfig.attributes).map(attribute => { 11123 const v = getLocationValue(attribute); 11124 v && this.changeOption(attribute.id, v) 11125 }); 11126 } 11127 } 11128 } 11129</script>
vendor: 1 bytes, line 11129
11129
11130<script> 11131 function initSwatchOptions(swatchConfig) { 11132 return { 11133 swatchConfig, 11134 getAttributeSwatchData(attributeId) { 11135 const swatchConfig = Object.assign({}, this.swatchConfig[attributeId]); 11136 swatchConfig['details'] = JSON.parse(swatchConfig['additional_data']); 11137 11138 return swatchConfig; 11139 }, 11140 mapSwatchTypeNumberToTypeCode(typeNumber) { 11141 switch ("" + typeNumber) { 11142 case "1": 11143 return "color" 11144 case "2": 11145 return "image" 11146 case "3": 11147 return "empty" 11148 case "0": 11149 default: 11150 return "text" 11151 } 11152 }, 11153 getTypeOfFirstOption(attributeId) { 11154 for (const optionId in this.swatchConfig[attributeId]) { 11155 const option = this.swatchConfig[attributeId][optionId]; 11156 if (typeof option.type !== 'undefined') { 11157 return this.mapSwatchTypeNumberToTypeCode(option.type); 11158 } 11159 } 11160 }, 11161 getVisualSwatchType(attributeId, targetOptionId) { 11162 // If a type configuration is present for the given option id, use it 11163 const config = this.swatchConfig[attributeId]; 11164 if (config[targetOptionId] && typeof config[targetOptionId].type !== 'undefined') { 11165 return this.mapSwatchTypeNumberToTypeCode(config[targetOptionId].type); 11166 } 11167 11168 // Otherwise - if no config is present for the target option - use the type of the first option 11169 // with a type property from the attribute, thus assuming its the same type as the target option. 11170 // (This edge case condition can occur on single swatch products if some options are not salable) 11171 return this.getTypeOfFirstOption(attributeId); 11172 }, 11173 getSwatchType(attributeId, optionId) { 11174 // Deserialize the attribute details the first time they are used 11175 if (this.swatchConfig[attributeId] && ! this.swatchConfig[attributeId].details) { 11176 this.swatchConfig[attributeId] = this.getAttributeSwatchData(attributeId); 11177 } 11178 const type = this.swatchConfig[attributeId] && 11179 this.swatchConfig[attributeId].details && 11180 this.swatchConfig[attributeId].details.swatch_input_type || 11181 "empty"; 11182 return type === 'visual' ? this.getVisualSwatchType(attributeId, optionId) : type; 11183 }, 11184 isTextSwatch() { 11185 const attributeId = this.getDataAttributeId(this.$el); 11186 return this.getSwatchType(attributeId, this.item.id) === 'text'; 11187 }, 11188 isVisualSwatch() { 11189 const attributeId = this.activeTooltipItem.attribute; 11190 const type = this.getSwatchType(attributeId, this.activeTooltipItem.item); 11191 11192 return ['image', 'color'].includes(type); 11193 }, 11194 getSwatchBackgroundStyle() { 11195 const attributeId = this.getDataAttributeId(this.$el); 11196 const config = this.getSwatchConfig(attributeId, this.item.id); 11197 const type = this.getSwatchType(attributeId, this.item.id); 11198 11199 if (type === "color") { 11200 return 'background-color:' + config.value; 11201 } else if (type === "image") { 11202 return "background: #fff url('" + config.value + "') no-repeat center"; 11203 } else { 11204 return ''; 11205 } 11206 }, 11207 getSwatchText() { 11208 const attributeId = this.getDataAttributeId(this.$el); 11209 const optionId = this.$el.dataset.optionId || this.selectedValues[attributeId]; 11210 const config = this.getSwatchConfig(attributeId, optionId); 11211 return config.label || config.value || this.getOptionLabelFromOptionConfig(attributeId, optionId); 11212 }, 11213 getOptionLabelFromOptionConfig(attributeId, optionId) { 11214 // Fallback if no value is present in swatchConfig data 11215 // Reference issue https://gitlab.hyva.io/hyva-themes/magento2-default-theme/-/issues/190 11216 const option = this.getAllAttributeOptions(attributeId).filter(option => option.id === optionId); 11217 return option && option[0] && option[0].label ||''; 11218 }, 11219 getSwatchConfig(attributeId, optionId) { 11220 return this.swatchConfig[attributeId] && this.swatchConfig[attributeId][optionId] 11221 ? this.swatchConfig[attributeId][optionId] 11222 : false;
11223 }, 11224 activeTooltipItem: false, 11225 tooltipPositionElement: false, 11226 isTooltipVisible() { 11227 return this.activeTooltipItem && 11228 this.getSwatchConfig( 11229 this.activeTooltipItem.attribute, 11230 this.activeTooltipItem.item 11231 ); 11232 }, 11233 isFirstItemCol() { 11234 return this.activeTooltipItem.index === 0; 11235 }, 11236 getTooltipImageStyle() { 11237 const attributeId = this.activeTooltipItem.attribute; 11238 const optionId = this.activeTooltipItem.item; 11239 const config = this.getSwatchConfig(attributeId, optionId); 11240 const type = this.getSwatchType(attributeId, optionId); 11241 11242 if (type === "color") { 11243 return 'background-color:' + config.value + '; width: 110px; height: 90px;'; 11244 } else if (type === "image") { 11245 return "background: #ffffff url('" + config.thumb + 11246 "') center center no-repeat; width: 110px; height: 90px;"; 11247 } else { 11248 return 'display:none'; 11249 } 11250 }, 11251 getTooltipWrapperClasses() { 11252 return { 11253 '-translate-x-5': this.isFirstItemCol() 11254 } 11255 }, 11256 getTooltipPosition() { 11257 return this.tooltipPositionElement ? 11258 `top: ${this.tooltipPositionElement.offsetTop}px;` + 11259 `left: ${ 11260 this.tooltipPositionElement.offsetLeft - ( 11261 this.tooltipPositionElement.closest('.snap') && 11262 this.tooltipPositionElement.closest('.snap').scrollLeft || 11263 0 11264 ) 11265 }px;` : '' 11266 }, 11267 getTooltipLabel() { 11268 return this.getSwatchConfig(this.activeTooltipItem.attribute, this.activeTooltipItem.item).label 11269 }, 11270 focusedLabel: false, 11271 focusLabel(optionId) { 11272 this.focusedLabel = optionId; 11273 }, 11274 blurLabel() { 11275 this.focusedLabel = false; 11276 }, 11277 getSwatchOptionHtmlId() { 11278 const productId = this.$el.closest('[data-product-id]').dataset.productId; 11279 return this.$id(`attribute-option-${productId}-${this.item.id}`) 11280 }, 11281 getSwatchOptionHtmlIdGroup() { 11282 const productId = this.$el.closest('[data-product-id]').dataset.productId; 11283 return [`attribute-option-${productId}-${this.item.id}`]; 11284 }, 11285 swatchOptionClasses() { 11286 const attributeId = this.getDataAttributeId(this.$el); 11287 return { 11288 'border-gray-100 ring ring-primary/50': (this.selectedValues[attributeId] === this.item.id), 11289 'border-gray-300': (this.selectedValues[attributeId] !== this.item.id), 11290 'w-6 h-6': !this.isTextSwatch(), 11291 'border-gray-100 ring ring-primary/75': this.focusedLabel === this.item.id, 11292 } 11293 }, 11294 outOfStockSwatchWrapperClasses() { 11295 return { 11296 'w-6 h-6': !this.isTextSwatch(), 11297 } 11298 }, 11299 outOfStockSwatchContentClasses() { 11300 return { 11301 'sr-only': !this.isTextSwatch() 11302 }; 11303 },
11304 setActiveTooltipItem() { 11305 this.activeTooltipItem = { 11306 attribute: this.getDataAttributeId(this.$el), 11307 item: this.item.id, 11308 index: this.index 11309 }; 11310 this.tooltipPositionElement = this.$event.target; 11311 }, 11312 unsetActiveTooltipItem() { 11313 this.activeTooltipItem = false; 11314 }, 11315 onFocusSwatchItem() { 11316 this.focusLabel(this.item.id); 11317 }, 11318 isSwatchRequired() { 11319 const attributeId = this.getDataAttributeId(this.$el); 11320 return this.getAllowedAttributeOptions(attributeId) 11321 .filter(attributeOption => this.selectedValues[attributeOption]) 11322 .length === 0 11323 }, 11324 modelBinding() { 11325 const attributeId = this.getDataAttributeId(this.$el); 11326 return this.selectedValues[attributeId]; 11327 } 11328 } 11329 } 11330</script>
vendor: 1 bytes, line 11330
11330
11331<script> 11332 function initPayPalInContextButton() { 11333 const renderTargetId = this.$root.dataset.renderTargetId; 11334 const config = JSON.parse(this.$root.dataset.clientConfig); 11335 const isMinicart = parseInt(this.$root.dataset.isMiniCart); 11336 11337 return { 11338 cartSection: false, 11339 actions: {}, 11340 paypalButtons: null, 11341 getData(sectionData) { 11342 this.cartSection = sectionData.cart; 11343 }, 11344 initMiniCartButtons() { 11345 this.cartSection = this.cart; 11346 }, 11347 initializePayPalScript() { 11348 if (!window.paypalScriptPromise) { 11349 window.paypalScriptPromise = new Promise((resolve, reject) => { 11350 const scriptId = 'paypal-script'; 11351 11352 const paypalScript = document.getElementById(scriptId); 11353 if (paypalScript) { 11354 if (window.paypal) { 11355 return resolve(window.paypal); 11356 } 11357 } 11358 11359 const script = document.createElement('script'); 11360 script.src = config.sdkUrl; 11361 script.id = scriptId; 11362 script.setAttribute('data-partner-attribution-id', config.dataAttributes['data-partner-attribution-id']); 11363 script.onload = () => resolve(window.paypal); 11364 script.onerror = () => reject(new Error('PayPal\u0020SDK\u0020could\u0020not\u0020be\u0020loaded')); 11365 document.body.appendChild(script); 11366 }); 11367 } 11368 11369 return window.paypalScriptPromise; 11370 }, 11371 async initializeButtons() { 11372 try { 11373 const paypal = await this.initializePayPalScript(); 11374 return paypal && paypal.Buttons({ 11375 style: Object.assign({}, config.styles, { 11376 height: 44, // Sets the style.height option to a value from 25 to 55. 11377 disableMaxWidth: false, // The button has a default maximum width of 750px, but you can make the button larger with true and set container size 11378 tagline: false // Set the style.layout to horizontal for taglines. 11379 }), 11380 onInit: (data, actions) => { 11381 this.actions = actions || this.actions; 11382 }, 11383 onClick: async (data, actions) => { 11384 this.actions = actions || this.actions; 11385 }, 11386 createOrder() { 11387 const params = 'quote_id=' + config.quoteId + 11388 '&customer_id=' + (config.customerId || '') + 11389 '&form_key=' + hyva.getFormKey() + 11390 '&button=' + config.button; 11391 11392 return window.fetch(config.getTokenUrl, { 11393 headers: { 11394 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 11395 'X-Requested-With': 'XMLHttpRequest', 11396 }, 11397 body: params, 11398 method: 'POST', 11399 mode: 'cors', 11400 credentials: 'include' 11401 }) 11402 .then(response => response.json()) 11403 .then(result => result.token) 11404 .catch(console.error); 11405 }, 11406 11407 onApprove(data, actions) { 11408 const params = 'paymentToken=' + (data.orderID || '') + 11409 '&payerId=' + (data.payerID || '') + 11410 '"eId=' + (config.quoteId || '') + 11411 '&customerId=' + (config.customerId || '') +
11412 '&form_key=' + hyva.getFormKey(); 11413 11414 return window.fetch(config.onAuthorizeUrl, { 11415 headers: { 11416 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 11417 'X-Requested-With': 'XMLHttpRequest', 11418 }, 11419 body: params, 11420 method: 'POST', 11421 mode: 'cors', 11422 credentials: 'include' 11423 }) 11424 .then(response => response.json()) 11425 .then(result => { 11426 if (result.success) { 11427 return actions.redirect(result.redirectUrl); 11428 } 11429 11430 throw new Error(result['error_message']); 11431 }) 11432 .catch(console.error).finally(() => { 11433 window.dispatchEvent(new Event('reload-customer-section-data')); 11434 }); 11435 }, 11436 onCancel(data, actions) { 11437 window.dispatchEvent(new Event('reload-customer-section-data')); 11438 11439 if (isMinicart) { 11440 window.dispatchEvent(new CustomEvent('toggle-cart', {detail: {isOpen: false}})); 11441 } 11442 11443 return window.dispatchMessages([{ 11444 type: 'error', 11445 text: 'Express\u0020Checkout\u0020has\u0020been\u0020canceled.' 11446 }]); 11447 }, 11448 onError(err) { 11449 window.dispatchEvent(new Event('reload-customer-section-data')); 11450 11451 // Alternative: forward to cart 11452 //window.location.href = config.onCancelUrl; 11453 11454 if (isMinicart) { 11455 window.dispatchEvent(new CustomEvent('toggle-cart', {detail: {isOpen: false}})); 11456 } 11457 11458 return window.dispatchMessages([{ 11459 type: 'error', 11460 text: 'Error\u0020al\u0020inicializar\u0020Express\u0020Checkout,\u0020int\u00E9ntelo\u0020de\u0020nuevo\u0020m\u00E1s\u0020tarde\u0020o\u0020elija\u0020otro\u0020m\u00E9todo\u0020de\u0020checkout.' 11461 }]); 11462 } 11463 }) 11464 } catch (error) { 11465 document.getElementById(renderTargetId).innerHTML = ''; 11466 console.error('Error loading PayPal SDK', error); 11467 } 11468 }, 11469 async checkAndInitializeButtons() { 11470 if (this.cartSection.items && this.cartSection.items.length) { 11471 if (! this.paypalButtons) { 11472 this.paypalButtons = await this.initializeButtons(); 11473 this.paypalButtons && this.paypalButtons.render(document.getElementById(renderTargetId)); 11474 } 11475 } 11476 } 11477 } 11478 } 11479 window.addEventListener('alpine:init', () => Alpine.data('initPayPalInContextButton', initPayPalInContextButton), {once: true}) 11480</script>
vendor: 1 bytes, line 11480
11480
11481<script> 11482 'use strict'; 11483 11484 const grecaptchaV2LoadCallbacks = []; 11485 11486 function executeRecaptchaLoadCallbacks () { 11487 while (window.grecaptcha && grecaptchaV2LoadCallbacks.length > 0) { 11488 const callback = grecaptchaV2LoadCallbacks.pop(); 11489 typeof callback === 'string' ? window[callback]() : callback(); 11490 } 11491 } 11492 11493 (function() { 11494 const loadRecaptchaScript = (event) => { 11495 11496 if (window.grecaptcha || !event.target.form) { 11497 return; 11498 } 11499 11500 const url = 'https://www.google.com/recaptcha/api.js?onload=executeRecaptchaLoadCallbacks'; 11501 const siteKey = '6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3'; 11502 const script = document.createElement('script'); 11503 script.type = 'text/javascript'; 11504 script.src = siteKey ? `${url}&render=${siteKey}` : `${url}&render=explicit`; 11505 script.async = true; 11506 document.head.appendChild(script); 11507 11508 script.addEventListener('load', () => { 11509 Array.from(document.querySelectorAll('button[data-recaptcha-btn]:disabled')).forEach(btn => btn.removeAttribute('disabled')); 11510 }); 11511 } 11512 11513 window.forceLoadRecaptchaScript = (form) => { 11514 loadRecaptchaScript({target: {form: form || 'dummy'}}); 11515 executeRecaptchaLoadCallbacks(); 11516 }; 11517 11518 document.body.addEventListener('input', loadRecaptchaScript, { once: true }); 11519 document.body.addEventListener('focus', loadRecaptchaScript, { once: true }); 11520 11521 }()); 11522 11523</script>
11523 11524
11525<script> 11526 function initLayeredSwatch() { 11527 return { 11528 getSwatchType(typeNumber) { 11529 switch ("" + typeNumber) { 11530 case '1': 11531 return "color" 11532 case '2': 11533 return "image" 11534 case '0': 11535 default: 11536 return "text" 11537 } 11538 }, 11539 getSwatchBackgroundStyle(type, value, image) { 11540 if (this.getSwatchType(type) === "color") { 11541 return 'background-color:' + value; 11542 } else if (this.getSwatchType(type) === "image") { 11543 return "background: #ffffff url('" + image + "') no-repeat center"; 11544 } else { 11545 return ''; 11546 } 11547 }, 11548 activeTooltipItem: false, 11549 tooltipPositionElement: false, 11550 isTooltipVisible() { 11551 return this.activeTooltipItem 11552 }, 11553 isFirstItemCol() { 11554 const left = this.tooltipPositionElement.offsetLeft; 11555 const leftParent = this.tooltipPositionElement.parentNode.offsetLeft; 11556 const width = this.tooltipPositionElement.offsetWidth; 11557 return left - leftParent < width; 11558 }, 11559 getTooltipImageStyle() { 11560 const type = this.activeTooltipItem.type; 11561 11562 if (this.getSwatchType(type) === "color") { 11563 return 'background-color:' + this.activeTooltipItem.value + '; width: 110px; height: 90px;'; 11564 } else if (this.getSwatchType(type) === "image") { 11565 return "background: #ffffff url('" + this.activeTooltipItem.thumb + 11566 "') center center no-repeat; width: 110px; height: 90px;"; 11567 } else { 11568 return 'display:none'; 11569 } 11570 }, 11571 getTooltipPosition() { 11572 return this.tooltipPositionElement ? 11573 ( 11574 `top: ${this.tooltipPositionElement.offsetTop}px;` + 11575 `left: ${this.tooltipPositionElement.offsetLeft}px;` 11576 ) : '' 11577 }, 11578 getTooltipLabel() { 11579 return this.activeTooltipItem.label || '' 11580 }, 11581 isVisualSwatch() { 11582 return this.getSwatchType(this.activeTooltipItem.type) !== 'text' 11583 }, 11584 getSwatchTypeClasses() { 11585 return { 11586 'w-6 h-6': this.getSwatchType(this.$el.dataset.swatchType) !== 'text' 11587 } 11588 }, 11589 getNonTextSwatchBackgroundStyle() { 11590 return this.getSwatchBackgroundStyle(this.$el.dataset.swatchType, this.$el.dataset.swatchValue, this.$el.dataset.swatchImage) 11591 }, 11592 onMouseEnter() { 11593 this.activeTooltipItem = { 11594 attribute: this.$el.dataset.swatchValue, 11595 type: this.$el.dataset.swatchType, 11596 id: this.$el.dataset.swatchOption, 11597 label: this.$el.dataset.swatchLabel, 11598 thumb: this.$el.dataset.swatchThumb, 11599 value: this.$el.dataset.swatchValue 11600 }; 11601 this.tooltipPositionElement = this.$event.target; 11602 }, 11603 onMouseLeave() { 11604 this.activeTooltipItem = false; 11605 }, 11606 getTooltipWrapperClasses() { 11607 return { 11608 '-translate-x-5': this.isFirstItemCol() 11609 } 11610 } 11611 } 11612 } 11613 window.addEventListener('alpine:init', () => Alpine.data('initLayeredSwatch', initLayeredSwatch), {once: true}) 11614</script>
vendor: 1 bytes, line 11614
11614
11615<script> 11616 (function () { 11617 const modals = []; 11618 const excludedFromFocusTrapping = new Set(); 11619 11620 function trapFocusInNextModalWithOverlay() { 11621 for (let idx = modals.length -1; idx >= 0; idx--) { 11622 const nextOnStack = modals[idx]; 11623 const nextDialogElement = nextOnStack.instance.$refs[nextOnStack.name]; 11624 if (! isOverlayDisabled(nextDialogElement)) { 11625 hyva.trapFocus(nextDialogElement); 11626 break; 11627 } 11628 } 11629 } 11630 11631 function focusables(dialogElement) { 11632 const selector = 'button, [href], input, textarea, select, details, [tabindex]:not([tabindex="-1"])'; 11633 return Array.from(dialogElement.querySelectorAll(selector)) 11634 .filter(el => !el.hasAttribute('disabled')); 11635 } 11636 11637 function firstVisible(elements) { 11638 const a = Array.from(elements); 11639 for (let i = 0; i < a.length; i++) { 11640 if (a[i].offsetWidth || a[i].offsetHeight || a[i].getClientRects().length) return a[i]; 11641 } 11642 return null; 11643 } 11644 11645 function isInViewport(element) { 11646 const rect = element && element.getBoundingClientRect(); 11647 return rect && 11648 rect.top >= 0 && 11649 rect.left >= 0 && 11650 rect.right <= window.innerWidth && 11651 rect.bottom <= window.innerHeight; 11652 } 11653 11654 function setFocusAfterTransition(dialogElement, duration) { 11655 const nested = Array.from(dialogElement.querySelectorAll('[role="dialog"]')); 11656 const candidates = Array.from(dialogElement.querySelectorAll('[x-focus-first]')); 11657 next: for (let candidate of candidates) { 11658 for (let child of nested) { 11659 if (child.contains(candidate)) continue next; 11660 } 11661 setTimeout(() => candidate.focus(), 50); 11662 break; 11663 } 11664 window.setTimeout(() => { 11665 const focusElement = firstVisible(dialogElement.querySelectorAll('[x-focus-first]')) || 11666 focusables(dialogElement)[0] || 11667 null; 11668 focusElement && isInViewport(focusElement) && focusElement.focus(); 11669 }, Math.max(1, duration)); 11670 } 11671 11672 function determineTrigger($refs, dialog, trigger) { 11673 if (typeof trigger === 'undefined' && typeof dialog === 'object' && dialog.target instanceof HTMLElement) { 11674 return dialog.target; 11675 } 11676 if (typeof dialog === 'string' && typeof trigger === 'object' && trigger.target instanceof HTMLElement) { 11677 return trigger.target; 11678 } 11679 if (typeof trigger === 'string') { 11680 try { 11681 return $refs[trigger] || document.querySelector(trigger) 11682 } catch (e) {} 11683 } 11684 if (trigger instanceof Element) { 11685 return trigger; 11686 } 11687 11688 return null; 11689 } 11690 11691 function isOverlayDisabled(dialog) { 11692 return dialog && dialog.hasAttribute('x-no-overlay') 11693 } 11694 11695 function areRemainingModalsWithoutOverlay(modals) 11696 { 11697 const overflowDisabled = modals.map(modal => modal.instance.$refs[modal.name]).filter(isOverlayDisabled); 11698 11699 return overflowDisabled.length === modals.length; 11700 } 11701 11702 window.hyva.modal = function(options = {}) { 11703 if (this.$el && this.$el.dataset && this.$el.dataset.options) { 11704 try { 11705 options = Object.assign(options, JSON.parse(this.$el.dataset.options || '{}')); 11706 } catch (e) { 11707 throw new Error('Cannot read the dialog options from the data-options attribute: not valid JSON'); 11708 } 11709 } 11710 11711 const config = Object.assign({ 11712 dialog: 'dialog', duration: 300, transitionEnter: 'transition ease-out duration-300', 11713 transitionEnterStart: 'opacity-0', 11714 transitionEnterEnd: 'opacity-100', 11715 transitionLeave: 'transition ease-in duration-300', 11716 transitionLeaveStart: 'opacity-100', 11717 transitionLeaveEnd: 'opacity-0', 11718 }, options); 11719 let lastHide = 0; 11720 11721 return { 11722 opened: {}, 11723 show(dialog, trigger) { 11724 const focusTargetAfterHide = determineTrigger(this.$refs, dialog, trigger); 11725 const name = typeof dialog === 'string' ? dialog : config.dialog; 11726 const dialogElement = this.$refs[name]; 11727 if (! dialogElement) { 11728 return; 11729 } 11730 const useOverlay = ! dialogElement.hasAttribute('x-no-overlay'); 11731 11732 dialogElement.scrollTop = 0; 11733 11734 if (this.opened[name]) { 11735 return; 11736 } 11737 11738 if (focusTargetAfterHide) { 11739 focusTargetAfterHide.setAttribute('aria-expanded', 'true'); 11740 } 11741 11742 this.opened[name] = true; 11743 useOverlay && this.$nextTick(() => hyva.trapFocus(dialogElement)); 11744 setFocusAfterTransition(dialogElement, config.duration); 11745 11746 const frame = {name, instance: this, focusTarget: focu
11746sTargetAfterHide, time: Date.now()}; 11747 11748 modals.push(frame); 11749 if (useOverlay) { 11750 document.body.classList.add('overflow-hidden'); 11751 } 11752 return new Promise(resolve => frame.resolve = resolve); 11753 }, 11754 cancel() { 11755 this.hide(false); 11756 }, 11757 ok() { 11758 this.hide(true); 11759 }, 11760 hide(value) { 11761 if (Date.now() - lastHide < config.duration) { 11762 return; 11763 } 11764 lastHide = Date.now(); 11765 11766 const modal = modals.pop() || {}; 11767 if (! modal.instance) { 11768 return; 11769 } 11770 11771 const name = modal.name; 11772 this.opened[name] = false; 11773 hyva.releaseFocus(modal.instance.$refs[modal.name]) 11774 trapFocusInNextModalWithOverlay(); 11775 11776 const nextFocusAfterHide = modal.focusTarget; 11777 nextFocusAfterHide && setTimeout(() => { 11778 nextFocusAfterHide.setAttribute('aria-expanded', 'false'); 11779 nextFocusAfterHide.focus() 11780 }, config.duration); 11781 11782 if (modals.length === 0 || areRemainingModalsWithoutOverlay(modals)) { 11783 document.body.classList.remove('overflow-hidden'); 11784 } 11785 11786 modal.resolve(value); 11787 }, 11788 overlay(dialog) { 11789 dialog = this.$el.dataset.dialogRefName || dialog; 11790 const name = typeof dialog === 'string' ? dialog : config.dialog; 11791 return { 11792 ['x-show']() { 11793 return this.opened[name] 11794 }, 11795 ['x-transition:enter']: config.transitionEnter, 11796 ['x-transition:enter-start']: config.transitionEnterStart, 11797 ['x-transition:enter-end']: config.transitionEnterEnd, 11798 ['x-transition:leave']: config.transitionLeave, 11799 ['x-transition:leave-start']: config.transitionLeaveStart, 11800 ['x-transition:leave-end']: config.transitionLeaveEnd, 11801 ['@hyva-modal-show.window'](event) { 11802 event.detail && event.detail.dialog === name && this.show(name, event.detail.focusAfterHide) 11803 } 11804 }; 11805 }, 11806 showDialogOnInit() { 11807 const parent = this.$el.closest('[data-dialog-ref-name]'); 11808 if (parent && parent.dataset.dialogRefName) { 11809 this.$dispatch('hyva-modal-show', {dialog: parent.dataset.dialogRefName}) 11810 } 11811 } 11812 }; 11813 } 11814 11815 window.hyva.modal.peek = () => modals.length > 0 && modals[modals.length -1] 11816 11817 window.hyva.modal.pop = function () { 11818 if (modals.length > 0) { 11819 const modal = modals[modals.length -1]; 11820 modal.instance.hide(); 11821 } 11822 } 11823 11824 window.hyva.modal.excludeSelectorsFromFocusTrap = function (selectors) { 11825 typeof selectors === 'string' || selectors instanceof String 11826 ? excludedFromFocusTrapping.add(selectors) 11827 : selectors.map(selector => excludedFromFocusTrapping.add(selector)); 11828 } 11829 11830 window.hyva.modal.eventListeners = { 11831 keydown: event => { 11832 if (event.key === 'Escape') { 11833 window.hyva.modal.pop(); 11834 } 11835 }, 11836 click: event => { 11837 if (modals.length > 0) { 11838 const modal = modals[modals.length -1]; 11839 const dialog = modal.instance.$refs[modal.name]; 11840 if (modal.time + 50 < Date.now() && // if last click processing is more than 50ms ago 11841 ! isOverlayDisabled(dialog) && // if dialog has overlay 11842 ! dialog.contains(event.target)) { // if click is outside of dialog 11843 modal.instance.hide(); 11844 } 11845 } 11846 } 11847 }; 11848 11849 document.addEventListener('keydown', window.hyva.modal.eventListeners.keydown); 11850 11851 document.addEventListener('click', window.hyva.modal.eventListeners.click); 11852 })(); 11853 window.addEventListener('alpine:init', () => { 11854 Alpine.data('hyvaModal', window.hyva.modal); 11855 }, {once: true}); 11856</script>
vendor: 1 bytes, line 11856
11856
11857<script> 11858 function initAmBundlePackGallery() { 11859 return { 11860 "active": 0, 11861 "initialImages": [], 11862 "images": [], 11863 "isSelected" : false, 11864 "currentElement": false, 11865 "appendOnReceiveImages": false, 11866 receiveImages(images) { 11867 if (this.appendOnReceiveImages) { 11868 const initialUrls = this.initialImages.map(image => image.full); 11869 const newImages = images.filter(image => ! initialUrls.includes(image.full)); 11870 this.images = [].concat(this.initialImages, newImages); 11871 this.setActive(newImages.length ? this.initialImages.length : 0); 11872 } else { 11873 this.images = images; 11874 } 11875 }, 11876 init() { 11877 this.appendOnReceiveImages = this.$el.dataset.appendOnReceiveImages; 11878 this.currentElement = this.$el; 11879 let active = this.images.findIndex(function(image) { 11880 return image.isMain === true 11881 }); 11882 if (active === -1) { 11883 active = 0; 11884 } 11885 this.setActive(active); 11886 },
11887 setActive(index) { 11888 this.active = index; 11889 }, 11890 resetGallery() { 11891 this.images = this.initialImages; 11892 this.setActive(0); 11893 }, 11894 imageCaption() { 11895 return this.image.caption || this.$el.dataset.productName; 11896 }, 11897 imageSrc() { 11898 return this.image.img; 11899 }, 11900 typeLoading() { 11901 return this.active !== this.index ? 'lazy' : 'eager'; 11902 }, 11903 showImg() { 11904 return this.active === this.index; 11905 }, 11906 eventListeners: { 11907 ['@update-gallery.window'](event) { 11908 setTimeout(() => { 11909 if (this.isSelected) { 11910 this.receiveImages(event.detail); 11911 } 11912 this.isSelected = false; 11913 }, 0) 11914 }, 11915 ['@bundle-popup-gallery-option-selected.window'](event) { 11916 let product = this.currentElement.closest('.amrelated-product-info'); 11917 let currentId = event.detail.getAttribute('id'); 11918 if (product.querySelector('#' + currentId)){ 11919 this.isSelected = true; 11920 } 11921 }, 11922 ['@reset-gallery.window'](event) { 11923 this.resetGallery(); 11924 } 11925 } 11926 } 11927 } 11928 11929 window.addEventListener( 11930 'alpine:init', 11931 () => Alpine.data('initAmBundlePackGallery', initAmBundlePackGallery), 11932 { once: true } 11933 ); 11934</script>
11934 11935
11935<script> 11936 function amBundlePackAddPopupData() { 11937 return { 11938 popupData: '', 11939 forms: false, 11940 formsData: '', 11941 popupWrapper: '', 11942 selectors: { 11943 forms: '.amrelated-product-info form.info-container-form', 11944 innerForm: 'form[id*="product_addtocart_form"]', 11945 body: 'body', 11946 productPageClass: 'catalog-product-view', 11947 cartPageClass: 'checkout-cart-index', 11948 popupWrapper: '[x-ref="bundlePopup"]', 11949 hidePopupButtonClass: '.hide-bundle-popup', 11950 swatchInputs: '.amrelated-product-info.configurable .product-option-value-input, .amrelated-product-info.configurable select' 11951 }, 11952 11953 init() { 11954 this.popupData = JSON.parse(this.$el.dataset.config); 11955 this.isOsnHyvaEnabled = Boolean(Number(this.$el.dataset.isOsnHyvaEnabled)); 11956 this.forms = this.$el.querySelectorAll(this.selectors.forms); 11957 this.popupWrapper = this.$el.closest(this.selectors.popupWrapper); 11958 this.$nextTick(() => { 11959 this.$el.addEventListener('change', (event) => { 11960 if (event.target.closest(this.selectors.swatchInputs)) { 11961 window.dispatchEvent(new CustomEvent('bundle-popup-gallery-option-selected', { detail: event.target })); 11962 } 11963 }); 11964 }) 11965 }, 11966 11967 serializeForm(form) { 11968 const data = new FormData(form) 11969 let array = []; 11970 this._setInputsToArray(data, array); 11971 11972 if (this.isOsnHyvaEnabled) { 11973 if (form.querySelector(this.selectors.innerForm)) { 11974 const data = new FormData(form.querySelector(this.selectors.innerForm)); 11975 this._setInputsToArray(data, array); 11976 } 11977 } 11978 11979 return array; 11980 }, 11981 11982 _setInputsToArray(data, arrayToSet) { 11983 for (let [key, value] of data) { 11984 arrayToSet.push({ 11985 name: key, 11986 value: value 11987 }); 11988 } 11989 }, 11990 11991 getIsProductPage() { 11992 return !!document.querySelector(this.selectors.body) 11993 .classList.contains(this.selectors.productPageClass); 11994 }, 11995 11996 getIsCartPage() { 11997 return !!document.querySelector(this.selectors.body) 11998 .classList.contains(this.selectors.cartPageClass); 11999 }, 12000 12001 scrollToElement(el) { 12002 el.scrollIntoView({ 12003 behavior: "smooth", 12004 block: "start" 12005 }); 12006 }, 12007 12008 scrollToTop() { 12009 window.scrollTo({ top: 0, behavior: 'smooth' }); 12010 }, 12011 12012 validateProductForm(form) { 12013 let flag = false; 12014 let isValid = form.reportValidity(); 12015 if (isValid) { 12016 flag = true; 12017 } else { 12018 this.scrollToElement(form); 12019 } 12020 return flag; 12021 }, 12022 12023 prepareData() { 12024 const inCartResponse = this.popupData.productsInCart; 12025 let data = false; 12026 let serializedForms = []; 12027 let formsData = ''; 12028 let isFormsValid = true; 12029 12030 this.forms.forEach((form) => { 12031 if (this.isOsnHyvaEnabled) { 12032 if (form.querySelector(this.selectors.innerForm)) { 12033 if (!this.validateProductForm(form.querySelector(this.selectors.innerForm))) { 12034 isFormsValid = false;
12035 return false; 12036 } 12037 } 12038 } 12039 12040 if (!this.validateProductForm(form)) { 12041 isFormsValid = false; 12042 return false; 12043 } 12044 }); 12045 12046 if (isFormsValid) { 12047 //forms data collect 12048 this.forms.forEach((form) => { 12049 serializedForms.push(this.serializeForm(form)); 12050 }); 12051 12052 serializedForms.forEach((form) => { 12053 formsData += 'amrelated_products_popup[]='; 12054 form.forEach((fileld, index, currentForm) => { 12055 formsData += fileld.name + '=' + fileld.value 12056 + (currentForm.length > (index + 1) ? encodeURIComponent('&') : ''); 12057 }) 12058 formsData += '&'; 12059 }) 12060 12061 data = formsData; 12062 12063 //product in cart data 12064 for (let productId in inCartResponse) { 12065 data += 'products_in_cart[' + productId + '][qty]=' + inCartResponse[productId]['qty'] + '&'; 12066 } 12067 12068 data += 'ajax_cart=' + this.popupData.isAjaxCartEnabled; 12069 data += '&form_key=' + hyva.getFormKey(); 12070 data += '&product_page=' + this.getIsProductPage(); 12071 data += '&pack_id=' + this.popupData.packId; 12072 } 12073 12074 return data; 12075 }, 12076 12077 addToCart() { 12078 const data = this.prepareData(); 12079 if (!data) { 12080 return; 12081 } 12082 this.isLoading = true; 12083 fetch(this.popupData.url, { 12084 headers: { 12085 "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 12086 }, 12087 body: new URLSearchParams(data), 12088 method: "POST", 12089 mode: "cors", 12090 credentials: "include" 12091 }).then( 12092 response => response.json() 12093 ).then((result) => { 12094 if (result.backUrl) { 12095 window.location.href = result.backUrl; 12096 } else { 12097 window.dispatchEvent(new CustomEvent('mostviewed-items-added')); 12098 const ref = this.$el.closest('[x-ref]').getAttribute('x-ref'); 12099 if (ref) { 12100 window.dispatchEvent(new CustomEvent('amrelated-modal-hide', {detail: ref})); 12101 } 12102 } 12103 }).catch(() => { 12104 dispatchMessages([{ 12105 type: "error", 12106 text: "Something went wrong. Please try again later." 12107 }], 2000); 12108 const ref = this.$el.closest('[x-ref]').getAttribute('x-ref'); 12109 if (ref) { 12110 window.dispatchEvent(new CustomEvent('amrelated-modal-hide', {detail: ref})); 12111 } 12112 }).finally(() => { 12113 this.isLoading = false; 12114 this.scrollToTop(); 12115 }) 12116 } 12117 } 12118 } 12119 12120 window.addEventListener( 12121 'alpine:init', 12122 () => Alpine.data('amBundlePackAddPopupData', amBundlePackAddPopupData), 12123 { once: true } 12124 ); 12125 </script>
vendor: 1 bytes, line 12125
12125
12126<script> 12127 function initAmBundlePackWishlist() { 12128 return { 12129 addToWishlist() { 12130 const productId = this.$el.dataset.productId; 12131 const postParams = { 12132 action: BASE_URL + "wishlist/index/add/", 12133 data: { 12134 product: productId, 12135 uenc: hyva.getUenc() 12136 } 12137 } 12138 12139 postParams.data['form_key'] = hyva.getFormKey(); 12140 postParams.data['qty'] = document.getElementById(`qty[${productId}]`) 12141 ? document.getElementById(`qty[${productId}]`).value || 1 12142 : 1; 12143 12144 let postData = Object.keys(postParams.data).map(key => { 12145 return `${key}=${postParams.data[key]}`; 12146 }).join('&'); 12147 12148 // take the all the input fields that configure this product 12149 // includes custom, configurable, grouped and bundled options 12150 Array.from(document.querySelectorAll( 12151 '[name^=options], [name^=super_attribute], [name^=bundle_option], [name^=super_group], [name^=links]') 12152 ).map(input => { 12153 if (input.type === "select-multiple") { 12154 Array.from(input.selectedOptions).forEach(option => { 12155 postData += `&${input.name}=${option.value}` 12156 }) 12157 } else { 12158 // skip "checkable inputs" that are not checked 12159 if(!(['radio', 'checkbox', 'select'].includes(input.type) && !input.checked)) { 12160 postData += `&${input.name}=${input.value}` 12161 } 12162 } 12163 }); 12164 fetch(postParams.action, { 12165 "headers": { 12166 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 12167 }, 12168 "body": postData, 12169 "method": "POST", 12170 "mode": "cors", 12171 "credentials": "include" 12172 }).then((response) => { 12173 if (response.redirected) { 12174 window.location.href = response.url; 12175 } else if (response.ok) { 12176 return response.json(); 12177 } else { 12178 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 12179 [{ 12180 type: "warning", 12181 text: "No se ha podido añadir el artÃculo a la lista de deseos." 12182 }], 5000 12183 ); 12184 } 12185 }).then((response) => { 12186 if (!response) { 12187 return; 12188 } 12189 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 12190 [{ 12191 type: (response.success) ? "success" : "error", 12192 text: (response.success) 12193 ? "Producto has been added to your Wish List." 12194 : response.error_message 12195 }], 5000 12196 ); 12197 const reloadCustomerDataEvent = new CustomEvent("reload-customer-section-data"); 12198 window.dispatchEvent(reloadCustomerDataEvent); 12199 }).catch((error) => { 12200 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 12201 [{ 12202 type: "error", 12203 text: error 12204 }], 5000 12205 ); 12206 }); 12207 } 12208 } 12209 } 12210 window.addEventListener('alpine:init', () => Alpine.data('initAmBundlePackWishlist', initAmBundlePackWishlist), {once: true}) 12211</script>
12211 12212
12212<script> 12213 function initAmBundlePackCompareOnProductView() { 12214 return { 12215 addToCompare: function () { 12216 const productId = 1; 12217 const formKey = hyva.getFormKey(); 12218 const postUrl = BASE_URL + 'catalog/product_compare/add/'; 12219 12220 fetch(postUrl, { 12221 "headers": { 12222 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 12223 }, 12224 "body": "form_key=" + formKey + "&product=" + productId + "&uenc=" + hyva.getUenc(), 12225 "method": "POST", 12226 "mode": "cors", 12227 "credentials": "include" 12228 }).then(function (response) { 12229 if (response.redirected) { 12230 window.location.href = response.url; 12231 } 12232 }).catch(function (error) { 12233 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 12234 [{ 12235 type: "error", 12236 text: error 12237 }], 5000 12238 ); 12239 }); 12240 } 12241 }; 12242 } 12243 window.addEventListener('alpine:init', () => Alpine.data('initAmBundlePackCompareOnProductView', initAmBundlePackCompareOnProductView), {once: true}) 12244 </script>
vendor: 1 bytes, line 12244
12244
12245<script> 12246 'use strict'; 12247 12248 function initAmRelatedSplide() { 12249 return { 12250 isLoading: true, 12251 sliderDefaultConfig: { 12252 perPage: Number(this.$el.dataset.slidesPerView), 12253 focus: 0, 12254 type: 'loop', 12255 breakpoints: { 12256 1280: { 12257 perPage: 3 12258 }, 12259 992: { 12260 perPage: 2 12261 }, 12262 576: { 12263 perPage: 1 12264 } 12265 }, 12266 classes: { 12267 arrow: 'splide__arrow bg-neutral-700! [&_svg]:fill-white! size-8! top-1/2! -translate-y-1/2! absolute!', 12268 prev: 'splide__arrow--prev left-0!', 12269 next: 'splide__arrow--next right-0!', 12270 pagination: 'splide__pagination flex! lg:gap-5!', 12271 page: 'splide__pagination__page hover:bg-neutral-700! bg-stone-300! size-2! [&.is-active]:transform-none! [&.is-active]:bg-neutral-700!', 12272 } 12273 }, 12274 init() { 12275 window.addEventListener('amsplide-loaded', () => { 12276 this.initializeSplide(); 12277 }, { once: true }); 12278 window.dispatchEvent(new CustomEvent('load-amsplide')); 12279 this.$watch('isLoading', (isLoading) => { 12280 !isLoading && this.$nextTick(this.lazyloadCallback); 12281 }); 12282 }, 12283 initializeSplide() { 12284 const splideContainer = this.$refs.splideContainer; 12285 const splideInstance = new Splide(splideContainer, this.adjustPageItemsConfig(this.sliderDefaultConfig)); 12286 12287 splideInstance.on('moved', this.lazyloadCallback); 12288 splideInstance.mount(); 12289 this.isLoading = false; 12290 }, 12291 adjustPageItemsConfig: function (config) { 12292 const slideCount = Number(this.$el.dataset.itemsCount); 12293 const breakpointsData = Object.entries(config.breakpoints) 12294 .map(([breakpoint, option]) => 12295 [ 12296 breakpoint, 12297 { ...config.breakpoints?.[breakpoint], ...this.getItemsPerPageConfig(option, slideCount) } 12298 ] 12299 ); 12300 12301 return { 12302 ...config, 12303 ...this.getItemsPerPageConfig(config, slideCount), 12304 breakpoints: { 12305 ...Object.fromEntries(breakpointsData) 12306 } 12307 } 12308 }, 12309 getItemsPerPageConfig: function (config, slideCount) { 12310 const { perPage } = config; 12311 if (!perPage) { 12312 return config; 12313 } 12314 const shouldHideControls = perPage >= slideCount; 12315 const itemsPerPage = shouldHideControls ? slideCount : perPage; 12316 12317 return { 12318 perPage: itemsPerPage, 12319 clones: shouldHideControls ? 0 : 2 * itemsPerPage, 12320 pagination: !shouldHideControls, 12321 arrows: !shouldHideControls, 12322 drag: !shouldHideControls, 12323 ...(shouldHideControls && { width: 'fit-content' }) 12324 } 12325 }, 12326 isNotLoading() { 12327 return !this.isLoading; 12328 }, 12329 lazyloadCallback: function () { 12330 window.amlazycallback?.(); 12331 } 12332 }; 12333 } 12334 12335 window.addEventListener( 12336 'alpine:init', 12337 () => Alpine.data('initAmRelatedSplide', initAmRelatedSplide), 12338 { once: true } 12339 ); 12340</script>
12340 12341
12342<script> 12343 'use strict'; 12344 (() => { 12345 function _calculateStrength({elementID, valid}) { 12346 const password = document.getElementById(elementID), 12347 emailElm = document.getElementById('email_address'); 12348 let displayScore; 12349 // Display score is based on combination of whether password is empty, valid, and zxcvbn strength 12350 if (!password || !password.value) { 12351 displayScore = 0; 12352 } else { 12353 // We should only perform this check in case there is an email field on screen 12354 if (emailElm && password.value && emailElm.value && 12355 password.value.toLowerCase() === emailElm.value.toLowerCase()) { 12356 displayScore = 1; 12357 } else { 12358 const zxcvbnScore = zxcvbn(password.value).score; 12359 displayScore = valid && zxcvbnScore > 0 ? zxcvbnScore : 1; 12360 } 12361 } 12362 12363 _displayStrength(displayScore); 12364 } 12365 12366 function _displayStrength(displayScore) { 12367 let strengthLabel = '', 12368 className; 12369 12370 switch (displayScore) { 12371 case 0: 12372 strengthLabel = "Ninguna\u0020contrase\u00F1a"; 12373 className = 'password-none'; 12374 break; 12375 12376 case 1: 12377 strengthLabel = "D\u00E9bil"; 12378 className = 'password-weak'; 12379 break; 12380 12381 case 2: 12382 strengthLabel = "Medio"; 12383 className = 'password-medium'; 12384 break; 12385 12386 case 3: 12387 strengthLabel = "Fuerte"; 12388 className = 'password-strong'; 12389 break; 12390 12391 case 4: 12392 strengthLabel = "Muy\u0020fuerte"; 12393 className = 'password-very-strong'; 12394 break; 12395 } 12396 const meterElm = document.getElementById('password-strength-meter-container'), 12397 meterLabelElm = document.getElementById('password-strength-meter-label'); 12398 meterElm.className = ''; 12399 meterElm.classList.add(className); 12400 meterLabelElm.textContent = strengthLabel; 12401 } 12402 12403 let loading = false; 12404 const callbacks = []; 12405 12406 function loadZxcvbn(cb) { 12407 callbacks.push(cb); 12408 if (loading) return; 12409 loading = true; 12410 12411 const script = document.createElement('script'); 12412 script.type = 'text/javascript'; 12413 script.src = 'https\u003A\u002F\u002Fwww.mueblesbonitos.com\u002Fstatic\u002Ffrontend\u002FMb\u002FHyva2\u002Fes_ES\u002Fjs\u002Fzxcvbn.js'; 12414 script.async = true; 12415 script.onload = () => callbacks.forEach(cb => cb()); 12416 document.head.appendChild(script); 12417 } 12418 12419 window.addEventListener('password-validate', function (evt) { 12420 const meterElm = document.getElementById('password-strength-meter-container'), 12421 meterLabelElm = document.getElementById('password-strength-meter-label'); 12422 if (meterElm && meterLabelElm) { 12423 if (evt.detail && evt.detail.elementID) { 12424 const cb = () => _calculateStrength(evt.detail); 12425 window.zxcvbn ? cb() : loadZxcvbn(cb) 12426 } 12427 } 12428 }); 12429 12430 12431 document.addEventListener('DOMContentLoaded', () => { 12432 hyva && hyva.formValidation && hyva.formValidation.addRule('password-strength', function(value, options, field, context) { 12433 let counter = 0; 12434 const minCharacterSets = options.minCharacterSets !== undefined ? options.minCharacterSets : 1; 12435 if (value.match(/\d+/)) { 12436 counter++; 12437 } 12438 12439 if (value.match(/[a-z]+/)) { 12440 counter++; 12441 } 12442 12443 if (value.match(/[A-Z]+/)) { 12444 counter++; 12445 } 12446 12447 if (value.match(/[^a-zA-Z0-9]+/)) { 12448 counter++; 12449 } 12450 12451 queueMicrotask(() => { 12452 window.dispatchEvent(new CustomEvent('password-validate', { detail: {
12453 elementID: field.element.id || 'password', 12454 valid: field.state.valid 12455 }})); 12456 }); 12457 12458 if (counter < minCharacterSets) { 12459 const missing = minCharacterSets - counter; 12460 return hyva.str('La\u0020contrase\u00F1a\u0020debe\u0020incluir\u0020al\u0020menos\u0020\u00251\u0020o\u0020m\u00E1s\u0020de\u0020los\u0020siguientes\u003A\u0020may\u00FAsculas\u0020\u0028A\u002DZ\u0029,\u0020min\u00FAsculas\u0020\u0028a\u002Dz\u0029,\u0020n\u00FAmero\u0020y\u0020s\u00EDmbolo.', missing); 12461 } 12462 return true; 12463 }); 12464 }) 12465 })(); 12466 12467</script>
vendor: 1 bytes, line 12467
12467
12468<script type="text/json" id="default-section-data"> 12469 {"messages":[],"customer":[],"compare-products":[],"last-ordered-items":[],"cart":[],"directory-data":{"ES":{"name":"Espa\u00f1a","regions":{"130":{"code":"A Coru\u0441a","name":"A Coru\u00f1a"},"131":{"code":"Alava","name":"Alava"},"132":{"code":"Albacete","name":"Albacete"},"133":{"code":"Alicante","name":"Alicante"},"134":{"code":"Almeria","name":"Almeria"},"135":{"code":"Asturias","name":"Asturias"},"136":{"code":"Avila","name":"Avila"},"137":{"code":"Badajoz","name":"Badajoz"},"138":{"code":"Baleares","name":"Baleares"},"139":{"code":"Barcelona","name":"Barcelona"},"140":{"code":"Burgos","name":"Burgos"},"141":{"code":"Caceres","name":"Caceres"},"142":{"code":"Cadiz","name":"Cadiz"},"143":{"code":"Cantabria","name":"Cantabria"},"144":{"code":"Castellon","name":"Castellon"},"145":{"code":"Ceuta","name":"Ceuta"},"146":{"code":"Ciudad Real","name":"Ciudad Real"},"147":{"code":"Cordoba","name":"Cordoba"},"148":{"code":"Cuenca","name":"Cuenca"},"149":{"code":"Girona","name":"Girona"},"150":{"code":"Granada","name":"Granada"},"151":{"code":"Guadalajara","name":"Guadalajara"},"152":{"code":"Guipuzcoa","name":"Guipuzcoa"},"153":{"code":"Huelva","name":"Huelva"},"154":{"code":"Huesca","name":"Huesca"},"155":{"code":"Jaen","name":"Jaen"},"156":{"code":"La Rioja","name":"La Rioja"},"157":{"code":"Las Palmas","name":"Las Palmas"},"158":{"code":"Leon","name":"Leon"},"159":{"code":"Lleida","name":"Lleida"},"160":{"code":"Lugo","name":"Lugo"},"161":{"code":"Madrid","name":"Madrid"},"162":{"code":"Malaga","name":"Malaga"},"163":{"code":"Melilla","name":"Melilla"},"164":{"code":"Murcia","name":"Murcia"},"165":{"code":"Navarra","name":"Navarra"},"166":{"code":"Ourense","name":"Ourense"},"167":{"code":"Palencia","name":"Palencia"},"168":{"code":"Pontevedra","name":"Pontevedra"},"169":{"code":"Salamanca","name":"Salamanca"},"170":{"code":"Santa Cruz de Tenerife","name":"Santa Cruz de Tenerife"},"171":{"code":"Segovia","name":"Segovia"},"172":{"code":"Sevilla","name":"Sevilla"},"173":{"code":"Soria","name":"Soria"},"174":{"code":"Tarragona","name":"Tarragona"},"175":{"code":"Teruel","name":"Teruel"},"176":{"code":"Toledo","name":"Toledo"},"177":{"code":"Valencia","name":"Valencia"},"178":{"code":"Valladolid","name":"Valladolid"},"179":{"code":"Vizcaya","name":"Vizcaya"},"180":{"code":"Zamora","name":"Zamora"},"181":{"code":"Zaragoza","name":"Zaragoza"}}},"data_id":1791444297},"captcha":[],"instant-purchase":[],"loggedAsCustomer":[],"persistent":[],"review":[],"payments":[],"wishlist":{"items":[]},"amfacebook-pixel":[],"hyva_checkout":[],"multisafepay-payment-request":[],"recently_viewed_product":[],"recently_compared_product":[],"product_data_storage":[],"paypal-billing-agreement":[],"paypal-buyer-country":[]}</script>
12469 12470
12470<script> 12471 const AmAuthPopupReloadContent = function () { 12472 const customerMenuSelector = '\u0023customer\u002Dmenu\u0020\u007E\u0020nav'; 12473 12474 return { 12475 contentUpdaters: [], 12476 12477 initContentUpdaters() { 12478 window.addEventListener('amsl-register-content-updater', (event) => { 12479 event.stopPropagation(); 12480 if (typeof event.detail === 'function') { 12481 this.registerContentUpdater(event.detail); 12482 } 12483 }, true) 12484 }, 12485 12486 reloadContent() { 12487 return Promise.all([ 12488 this.reloadHeader(), 12489 ...this.contentUpdaters.map(updater => updater()) 12490 ]).then(this.updateFormKey); 12491 }, 12492 12493 registerContentUpdater(updater) { 12494 this.contentUpdaters.push(updater); 12495 }, 12496 12497 async reloadHeader() { 12498 const response = await fetch( 12499 `${BASE_URL}amsociallogin_hyva\u002Fheader\u002Fupdate?isAjax=1`, 12500 { 12501 method: 'GET', 12502 headers: { 12503 'Content-type': 'application/json' 12504 } 12505 } 12506 ); 12507 12508 const result = await response.json(); 12509 const {customer_menu_html: customerMenuHtml} = result; 12510 const container = document.createElement('div'); 12511 container.innerHTML = customerMenuHtml; 12512 const currentMenu = document.querySelector(customerMenuSelector); 12513 const newMenu = container.querySelector(customerMenuSelector); 12514 12515 if (currentMenu && newMenu) { 12516 currentMenu.replaceWith(newMenu); 12517 } 12518 }, 12519 12520 updateFormKey() { 12521 const formKeyInputs = document.querySelectorAll('input[name="form_key"]'); 12522 formKeyInputs.forEach(input => input.value = hyva.getFormKey()); 12523 } 12524 } 12525 } 12526</script>
vendor: 1 bytes, line 12526
12526
12527<script> 12528 const AmAuthPopupRedirect = function () { 12529 const redirectTimeout = 2000; 12530 const redirectUrl = 'https://www.mueblesbonitos.com/customer/account/'; 12531 12532 return { 12533 processRedirect(forceRedirectUrl) { 12534 if (forceRedirectUrl) { 12535 setTimeout(() => { 12536 this.resetSessionCookie(); 12537 window.location.assign(forceRedirectUrl); 12538 }, redirectTimeout); 12539 return; 12540 } 12541 this.reloadViaAjax(); 12542 }, 12543 12544 reloadCustomerData() { 12545 this.resetSessionCookie(); 12546 window.dispatchEvent(new CustomEvent("reload-customer-section-data")); 12547 }, 12548 12549 resetSessionCookie() { 12550 hyva.setCookie('mage-cache-sessid', '', -1, true); 12551 }, 12552 12553 reloadPage() { 12554 setTimeout(() => { 12555 this.resetSessionCookie(); 12556 window.location.reload(true) 12557 }, redirectTimeout) 12558 }, 12559 12560 reloadViaAjax() { 12561 window.addEventListener('private-content-loaded', () => { 12562 this.reloadContent().then(() => { 12563 window.dispatchEvent( 12564 new CustomEvent('amsl-content-updated') 12565 ); 12566 }).catch( 12567 (error) => { 12568 console.error(error); 12569 this.reloadPage(); 12570 } 12571 ); 12572 }, {once: true}); 12573 this.reloadCustomerData(); 12574 window.dispatchEvent( 12575 new CustomEvent('amsl-popup-ajax-login-success') 12576 ); 12577 } 12578 } 12579 } 12580</script>
vendor: 1 bytes, line 12580
12580
12581<script> 12582 const AmAuthPopupNotification = function () { 12583 const modalName = 'amsl\u002Dpopup\u002Dnotification'; 12584 12585 return { 12586 ...AmAuthPopupModal(modalName), 12587 notification: '', 12588 12589 initialize() { 12590 this.initModalSettings(); 12591 }, 12592 12593 // x-on:amsl-popup-show-notification.window="onShowNotification" 12594 onShowNotification(event) { 12595 this.showNotification(event && event.detail); 12596 }, 12597 12598 showNotification(messages) { 12599 if (!messages) { 12600 return; 12601 } 12602 12603 this.notification = Array.isArray(messages) ? messages.join('<br>') : messages; 12604 12605 window.dispatchEvent(new CustomEvent('amsl-hide-popup')); 12606 12607 this.show(modalName); 12608 }, 12609 12610 // Para el botón de cerrar del contenido: x-on:click="closeNotification" 12611 closeNotification() { 12612 this.hide(); 12613 }, 12614 12615 hasNotification() { 12616 return !!this.notification; 12617 } 12618 } 12619 } 12620 12621 ;(() => { 12622 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 12623 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 12624 const register = () => Alpine.data('AmAuthPopupNotification', AmAuthPopupNotification); 12625 (document.readyState === 'loading' || !window.Alpine) 12626 ? window.addEventListener('alpine:init', register, {once: true}) 12627 : register(); 12628 })(); 12629</script>
vendor: 1 bytes, line 12629
12629
12630<script> 12631 const AmAuthPopupModal = function (modalName) { 12632 const canCloseByOverlayClick = true; 12633 12634 return { 12635 ...hyva.modal(), 12636 animationDuration: 500, 12637 12638 initModalSettings() { 12639 if (!canCloseByOverlayClick) { 12640 this.restrictOverlayClick(); 12641 } 12642 }, 12643 12644 restrictOverlayClick() { 12645 document.addEventListener('click', (event) => { 12646 const modal = this.$refs[modalName]; 12647 const isVisible = this.opened[modalName]; 12648 if (isVisible && !modal.contains(event.target) && !modal.hasAttribute('x-no-overlay')) { 12649 event.stopPropagation(); 12650 } 12651 }, {capture: true}); 12652 } 12653 } 12654 } 12655</script>
12655 12656
12656<script> 12657 function AmSocialLogin() { 12658 return { 12659 socialErrorMessage: '', 12660 isPopupEnabled: '1', 12661 12662 initializeSocialLogin() { 12663 this.initContentUpdaters(); 12664 }, 12665 12666 socialLoginClick(event) { 12667 const form = event.currentTarget; 12668 12669 if (this.isPopupEnabled) { 12670 form.target = '_blank'; 12671 form.action = form.action + '&isAjax=true'; 12672 } 12673 12674 const channel = new BroadcastChannel('amSocialLoginData'); 12675 channel.addEventListener('message', this.onMessageEvent.bind(this)); 12676 12677 event.stopPropagation(); 12678 event.preventDefault(); 12679 form.submit(); 12680 12681 return false; 12682 }, 12683 12684 onSocialResponse(data) { 12685 const isSuccessfulResult = data.result === 1; 12686 12687 if (isSuccessfulResult) { 12688 window.dispatchEvent( 12689 new CustomEvent( 12690 'amsl-popup-show-notification', 12691 { 12692 detail: data.messages 12693 } 12694 ) 12695 ); 12696 this.processRedirect(); 12697 } else { 12698 const redirectData = data?.redirect_data; 12699 12700 this.socialErrorMessage = data.messages.pop(); 12701 setTimeout(() => { 12702 this.socialErrorMessage = ''; 12703 }, 5000); 12704 12705 if (this.shouldCustomUrlRedirectWithError(redirectData)) { 12706 return this.processRedirect(redirectData?.url); 12707 } 12708 12709 if (redirectData?.redirectWithError) { 12710 this.processRedirect(); 12711 } 12712 } 12713 }, 12714 12715 // Helper CSP: x-if="hasSocialError" 12716 hasSocialError() { 12717 return !!this.socialErrorMessage; 12718 }, 12719 12720 shouldCustomUrlRedirectWithError(redirectData) { 12721 return ( 12722 redirectData && 12723 redirectData.redirect && 12724 redirectData.redirectWithError && 12725 redirectData.url 12726 ); 12727 }, 12728 12729 onMessageEvent(event) { 12730 if (event.origin !== window.location.origin) { 12731 return; 12732 } 12733 12734 const data = JSON.parse(event.data); 12735 if (data['redirect_data']) { 12736 this.onSocialResponse(data); 12737 } 12738 }, 12739 12740 ...AmAuthPopupRedirect(), 12741 ...AmAuthPopupReloadContent() 12742 } 12743 } 12744 12745 ;(() => { 12746 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 12747 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 12748 const register = () => Alpine.data('AmSocialLogin', AmSocialLogin); 12749 (document.readyState === 'loading' || !window.Alpine) 12750 ? window.addEventListener('alpine:init', register, {once: true}) 12751 : register(); 12752 })(); 12753</script>
12753 12754 12755
12755<script> 12756 const AmAuthPopup = function () { 12757 const TAB_ID_LOGIN = 'amsl\u002Dlogin'; 12758 const TAB_ID_REGISTER = 'amsl\u002Dregister'; 12759 const TAB_ID_FORGOT = 'amsl\u002Dforgot'; 12760 const IS_KNOWN_CUSTOMER = false; 12761 const modalName = 'social\u002Dlogin\u002Dpopup'; 12762 let componentInitialized = false; 12763 12764 const reCaptchaStatusBySection = { 12765 login: '1', 12766 register: '1', 12767 forgotPassword: '1', 12768 } 12769 12770 const reCaptchaStatusFor = section => reCaptchaStatusBySection[section]; 12771 12772 return { 12773 isGuestCheckoutAllowed: true, 12774 isAccountForgotPasswordPage: false, 12775 activeTab: TAB_ID_LOGIN, 12776 tabs: [TAB_ID_LOGIN, TAB_ID_REGISTER], 12777 socialIconsExpansionState: { 12778 [TAB_ID_LOGIN]: false, 12779 [TAB_ID_REGISTER]: false 12780 }, 12781 isLoading: false, 12782 modalName, 12783 isLogged: false, 12784 socialIconsExpanded: false, 12785 12786 initializeAuthPopup(privateData) { 12787 if (privateData?.data?.customer?.firstname && !IS_KNOWN_CUSTOMER) { 12788 componentInitialized = false; 12789 this.reloadExpiredCustomerData(); 12790 return; 12791 } 12792 12793 if (componentInitialized) { 12794 return; 12795 } 12796 12797 componentInitialized = true; 12798 12799 const origShow = this.show; 12800 const origHide = this.hide; 12801 this.show = (name, event, activeTabName) => { 12802 origShow.call(this, name, event); 12803 this.activeTab = activeTabName || TAB_ID_LOGIN; 12804 } 12805 this.hide = (...args) => { 12806 origHide.call(this, args); 12807 setTimeout(() => { 12808 this.clearForms(); 12809 this.clearFormMessages(); 12810 }, this.animationDuration + 1) 12811 } 12812 12813 this.initModalSettings(); 12814 this.bindLinksEvents(privateData); 12815 this.initContentUpdaters(); 12816 if (!this.isGuestCheckoutAllowed) { 12817 this.bindAuthenticationEvent(privateData); 12818 } 12819 }, 12820 12821 bindAuthenticationEvent(privateData) { 12822 window.addEventListener('toggle-authentication', (event) => { 12823 event.stopPropagation(); 12824 12825 if (!this.isLoggedIn(privateData)) { 12826 this.show( 12827 this.modalName, 12828 event 12829 ); 12830 } else { 12831 window.location.assign(event.detail.url) 12832 } 12833 }, true) 12834 }, 12835 12836 bindLinksEvents(privateData) { 12837 if (!this.isLoggedIn(privateData)) { 12838 this.bindOpeningEvents(); 12839 this.bindForgotLinkEvent(); 12840 requestAnimationFrame(() => { 12841 this.processForms(); 12842 }) 12843 } else { 12844 this.initLogout(); 12845 } 12846 }, 12847 12848 bindOpeningEvents() { 12849 const accountLinks = document.querySelectorAll(`#header nav a[href^="${BASE_URL}customer/account"], .columns a[href^="${BASE_URL}customer/account"]`) || []; 12850 12851 accountLinks.forEach(elem => { 12852 const isRegisterLink = /\/create\/?(\?.+)?(\#.+)*/.test(elem.href); 12853 elem.removeAttribute('onclick'); 12854 elem.setAttribute('aria-haspopup', 'dialog'); 12855 elem.addEventListener('click', (event) => { 12856 event.preventDefault(); 12857 this.show( 12858 this.modalName, 12859 event, 12860 isRegisterLink ? TAB_ID_REGISTER : TAB_ID_LOGIN 12861 ); 12862 }) 12863 }); 12864 12865 if (reCaptchaStatusFor('register')) {
12866 this.moveRecaptchaElement('.recaptcha-create-wrapper'); 12867 } 12868 12869 if (reCaptchaStatusFor('login')) { 12870 this.moveRecaptchaElement('.recaptcha-login-wrapper'); 12871 } 12872 }, 12873 12874 bindForgotLinkEvent() { 12875 const modalContainer = this.$el || this.$root; 12876 const forgotLinks = modalContainer.querySelectorAll( 12877 `a[href^="${BASE_URL}customer/account/forgotpassword"]` 12878 ) || []; 12879 12880 forgotLinks.forEach((element) => { 12881 element.addEventListener('click', (event) => { 12882 event.preventDefault(); 12883 element.setAttribute('aria-haspopup', 'dialog'); 12884 this.activeTab = TAB_ID_FORGOT; 12885 }) 12886 }) 12887 12888 if (reCaptchaStatusFor('forgotPassword') && !this.isAccountForgotPasswordPage) { 12889 this.moveRecaptchaElement('.recaptcha-forgot-wrapper'); 12890 } 12891 }, 12892 12893 isLoggedIn(privateData) { 12894 try { 12895 privateData = privateData?.data ?? JSON.parse(hyva.getBrowserStorage()?.['mage-cache-storage'] || '{}'); 12896 this.isLogged = !!(privateData.customer && privateData.customer.firstname); 12897 } catch (error) { 12898 console.error('Error parsing privateData:', error); 12899 this.isLogged = false; 12900 } 12901 return this.isLogged; 12902 }, 12903 12904 showOnExternalEvent(event) { 12905 const eventData = event.detail || {}; 12906 const message = eventData?.message; 12907 const tabName = eventData?.tabName || TAB_ID_LOGIN; 12908 12909 this.show(this.modalName, event, tabName); 12910 if (message) { 12911 this.setFormMessages(tabName, [message]); 12912 } 12913 }, 12914 12915 canShowAllSocialIcons() { 12916 return this.socialIconsExpansionState[this.activeTab]; 12917 }, 12918 12919 showAllSocialIcons() { 12920 this.socialIconsExpanded = true; 12921 this.socialIconsExpansionState[this.activeTab] = true; 12922 }, 12923 12924 setLoading(isLoading) { 12925 const formButtons = this.$refs[this.modalName].querySelectorAll('[type="submit"]'); 12926 formButtons.forEach(button => { 12927 if (isLoading) { 12928 button.setAttribute('disabled', 'disabled') 12929 } else { 12930 button.removeAttribute('disabled'); 12931 } 12932 }) 12933 this.isLoading = isLoading; 12934 }, 12935 12936 reloadExpiredCustomerData() { 12937 const sections = ['mage-cache-storage', 'private_content_version', 'mage-cache-timeout']; 12938 sections.forEach(section => localStorage.removeItem(section)); 12939 12940 hyva.setCookie('mage-cache-sessid', '', -1); 12941 window.dispatchEvent(new CustomEvent("reload-customer-section-data")); 12942 }, 12943 12944 moveRecaptchaElement(element) { 12945 const captchaElement = document.querySelector(element); 12946 if (!captchaElement) { 12947 return; 12948 } 12949 12950 const container = captchaElement.closest('.amsl-form').querySelector('.actions-toolbar'); 12951 container.prepend(captchaElement); 12952 }, 12953 12954 onKeypress(event) { 12955 const activeTabIndex = this.tabs.indexOf(this.activeTab); 12956 12957 if (activeTabIndex < 0 || event.code === 'Tab') { 12958 return; 12959 } 12960 12961 switch (event.code) { 12962 case 'Enter': 12963 case 'Space': 12964 this.activeTab = event.target.id.replace('tab-', ''); 12965 break; 12966 12967 case 'ArrowRight': 12968 this.activeTab = this.tabs[(activeTabIndex + 1) % this.tabs.length] 12969 break; 12970 12971 case 'ArrowLeft': 12972 this.activeTab = this.tabs[(activeTabIndex + this.tabs.length - 1) % this.tabs.length] 12973 break; 12974 12975 case 'End': 12976 this.activeTab = this.tabs[this.tabs.length - 1] 12977 break; 12978 12979 case 'Home': 12980 this.activeTab = this.tabs[0] 12981 break; 12982 } 12983 12984 document.getElementById('tab-' + this.activeTab).focus(); 12985 }, 12986 12987 /* ================================================================ 12988 * Helpers CSP (Mb/Hyva2): Alpine CSP solo admite nombres de 12989 * propiedades/métodos en el HTML, sin argumentos ni operadores. 12990 * ================================================================ */ 12991 12992 // Eventos del contenedor (modals/authentication-popup.phtml) 12993 onPrivateContentLoaded(event) { 12994 this.initializeAuthPopup(event && event.detail); 12995 }, 12996 onHidePopup() { 12997 this.hide(this.modalName); 12998 }, 12999 onContentUpdated() { 13000 this.bindLinksEvents(); 13001 }, 13002 closePopup() { 13003 this.hide(); 13004 }, 13005 13006 // Pestañas 13007 isLoginTab() { 13008 return this.activeTab === TAB_ID_LOGIN; 13009 }, 13010 isRegisterTab() { 13011 return this.activeTab === TAB_ID_REGISTER; 13012 }, 13013 isForgotTab() { 13014 return this.activeTab === TAB_ID_FORGOT; 13015 }, 13016 isNotForgotTab() { 13017 return this.activeTab !== TAB_ID_FORGOT; 13018 }, 13019 selectLoginTab() { 13020 this.activeTab = TAB_ID_LOGIN; 13021 }, 13022 selectRegisterTab() { 13023 this.activeTab = TAB_ID_REGISTER; 13024 }, 13025 tabClasses(tabId) { 13026 const active = this.activeTab === tabId; 13027 return {
13028 '-active border-primary text-blue-800 hover:bg-transparent': active, 13029 'border-transparent text-primary-lighter hover:bg-gray-100': !active 13030 }; 13031 }, 13032 loginTabClasses() { 13033 return this.tabClasses(TAB_ID_LOGIN); 13034 }, 13035 registerTabClasses() { 13036 return this.tabClasses(TAB_ID_REGISTER); 13037 }, 13038 13039 // Mensajes de cada formulario 13040 hasLoginMessages() { 13041 return this.formMessages.has(TAB_ID_LOGIN); 13042 }, 13043 loginMessages() { 13044 return this.formMessages.get(TAB_ID_LOGIN) || []; 13045 }, 13046 hasRegisterMessages() { 13047 return this.formMessages.has(TAB_ID_REGISTER); 13048 }, 13049 registerMessages() { 13050 return this.formMessages.get(TAB_ID_REGISTER) || []; 13051 }, 13052 hasForgotMessages() { 13053 return this.formMessages.has(TAB_ID_FORGOT); 13054 }, 13055 forgotMessages() { 13056 return this.formMessages.get(TAB_ID_FORGOT) || []; 13057 }, 13058 13059 // Estado de sesión y botones sociales 13060 isNotLogged() { 13061 return !this.isLogged; 13062 }, 13063 socialButtonsClasses() { 13064 return {'-show-all': this.canShowAllSocialIcons()}; 13065 }, 13066 cannotShowAllSocialIcons() { 13067 return !this.canShowAllSocialIcons(); 13068 }, 13069 // Valores por defecto (AmSocialLogin los sobrescribe al hacer spread) 13070 socialErrorMessage: '', 13071 hasSocialError() { 13072 return !!this.socialErrorMessage; 13073 }, 13074 13075 ...AmAuthPopupModal(modalName), 13076 ...AmAuthPopupForms(), 13077 ...AmAuthPopupRedirect(), 13078 ...AmAuthPopupReloadContent(), 13079 ...AmAuthPopupLogout(), 13080 ...(typeof AmSocialLogin === 'function' ? AmSocialLogin() : {}) 13081 } 13082 } 13083 13084 ;(() => { 13085 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 13086 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 13087 const register = () => Alpine.data('AmAuthPopup', AmAuthPopup); 13088 (document.readyState === 'loading' || !window.Alpine) 13089 ? window.addEventListener('alpine:init', register, {once: true}) 13090 : register(); 13091 })(); 13092</script>
vendor: 1 bytes, line 13092
13092
13093<script> 13094 (function () { 13095 const resetPasswordForms = document.querySelectorAll('form[action*="/forgotpasswordpost"]'); 13096 resetPasswordForms.forEach(form => { 13097 form.classList.add('form','password', 'forget'); 13098 }); 13099 })(); 13100 13101 const AmAuthPopupForms = function () { 13102 const TAB_ID_LOGIN = 'amsl\u002Dlogin'; 13103 const TAB_ID_REGISTER = 'amsl\u002Dregister'; 13104 const TAB_ID_FORGOT = 'amsl\u002Dforgot'; 13105 const formsConfig = JSON.parse(`\u007B\u0022amsl\u002Dlogin\u0022\u003A\u007B\u0022formType\u0022\u003A\u0022amsl\u002Dlogin\u0022,\u0022formId\u0022\u003A\u0022customer\u002Dlogin\u002Dform\u0022,\u0022successMessage\u0022\u003A\u0022You\u0020have\u0020successfully\u0020logged\u0020in.\u0022,\u0022submitUrlReplacement\u0022\u003A\u0022amsociallogin\u005C\u002Faccount\u0022\u007D,\u0022amsl\u002Dregister\u0022\u003A\u007B\u0022formType\u0022\u003A\u0022amsl\u002Dregister\u0022,\u0022formId\u0022\u003A\u0022accountcreate\u0022,\u0022successMessage\u0022\u003A\u0022Thank\u0020you\u0020for\u0020registering\u0020with\u0020us.\u0022,\u0022submitUrlReplacement\u0022\u003A\u0022amsociallogin\u005C\u002Faccount\u0022\u007D,\u0022amsl\u002Dforgot\u0022\u003A\u007B\u0022formType\u0022\u003A\u0022amsl\u002Dforgot\u0022,\u0022formId\u0022\u003A\u0022user_forgotpassword\u0022,\u0022customSubmitUrl\u0022\u003A\u0022customer\u005C\u002Faccount\u005C\u002Fforgotpasswordpost\u0022\u007D\u007D`); 13106 13107 return { 13108 formMessages: new Map(), 13109 13110 processForms() { 13111 Object.values(formsConfig).forEach((formOptions) => { 13112 this.processForm(formOptions); 13113 }) 13114 }, 13115 13116 processForm(formOptions) { 13117 const { formId } = formOptions; 13118 const formElement = document.querySelector(`#social-login-popup #${formId}`); 13119 13120 if (formElement) { 13121 this.bindFormSubmit(formElement, formOptions); 13122 } 13123 }, 13124 13125 bindFormSubmit(formElement, formOptions) { 13126 const { formType, successMessage, submitUrlReplacement, customSubmitUrl } = formOptions; 13127 13128 let submitUrl = formElement.action; 13129 if (submitUrlReplacement) { 13130 submitUrl = submitUrl.replace('customer/account', submitUrlReplacement); 13131 } 13132 13133 if (customSubmitUrl) { 13134 let baseUrl = 'https://www.mueblesbonitos.com/'; 13135 submitUrl = baseUrl + customSubmitUrl; 13136 } 13137 13138 13139 formElement.submit = () => { 13140 this.clearFormMessages(); 13141 this.setLoading(true); 13142 13143 this.formAjaxSubmit( 13144 formElement, 13145 submitUrl 13146 ).then((result) => { 13147 if (!result.errors.length) { 13148 this.hide(this.modalName); 13149 const notification = result.success || successMessage; 13150 if (notification) { 13151 window.dispatchEvent( 13152 new CustomEvent( 13153 'amsl-popup-show-notification', 13154 { 13155 detail: notification 13156 } 13157 ) 13158 ); 13159 } 13160 } 13161 if (result.errors.length) { 13162 this.setFormMessages(formType, result.errors); 13163 return; 13164 } 13165 this.processRedirect(); 13166 }).finally(() => { 13167 this.setLoading(false); 13168 }) 13169 } 13170 }, 13171 13172 async formAjaxSubmit(form, url) { 13173 let errors = []; 13174 let success = ''; 13175 13176 try { 13177 await fetch(url, { 13178 method: 'POST', 13179 body: new FormData(form) 13180 }); 13181 13182 const messages = this.extractMageMessages(); 13183 const errorMessages = messages.filter(({ type }) => type === 'error'); 13184 const successMessages = messages.filter(({ type }) => type === 'success'); 13185 13186 errors = errorMessages.map(({ text }) => text); 13187 if (successMessages.length) { 13188 success = successMessages.pop().text || ''; 13189 } 13190 } catch (error) { 13191 console.error(error); 13192 errors.push('Sorry,\u0020something\u0020went\u0020wrong.\u0020Please\u0020try\u0020again\u0020later.'); 13193 } 13194 13195 return { errors, success }; 13196 }, 13197 13198 extractMageMessages() { 13199 const messagesCookie = hyva.getCookie('mage-messages'); 13200 const messages = messagesCookie 13201 ? JSON.parse(decodeURIComponent(messagesCookie).replace(/\+/g, ' ')) 13202 : []; 13203 hyva.setCookie('mage-messages','', -1, true); 13204 13205 return messages; 13206 }, 13207 13208 clearFormMessages() { 13209 this.formMessages = new Map(); 13210 }, 13211 13212 setFormMessages(formType, messages) { 13213 const formMessages = new Map(this.formMessages); 13214 13215 formMessages.set(formType, messages); 13216 this.formMessages = formMessages; 13217 }, 13218 13219 clearForms() { 13220 const forms = this.$refs[this.modalName].querySelectorAll('form') || [];
13221 forms.forEach((form) => form.reset()); 13222 } 13223 } 13224 } 13225</script>
vendor: 1 bytes, line 13225
13225
13226<script> 13227 const AmAuthPopupLogout = function () { 13228 return { 13229 initLogout() { 13230 const logoutLinks = document.querySelectorAll(`a[href*="customer/account/logout"]`) || []; 13231 13232 logoutLinks.forEach(elem => { 13233 elem.addEventListener('click', (event) => { 13234 event.preventDefault(); 13235 this.sendLogOut() 13236 }) 13237 }) 13238 }, 13239 13240 sendLogOut() { 13241 fetch(BASE_URL + "customer/account/logout", { 13242 method: 'GET', 13243 credentials: "include" 13244 }).then(response => { 13245 window.dispatchEvent( 13246 new CustomEvent( 13247 'amsl-popup-show-notification', 13248 { 13249 detail: 'Ha\u0020cerrado\u0020sesi\u00F3n\u0020correctamente.' 13250 } 13251 ) 13252 ); 13253 this.processRedirect(this.isInAccountSection() ? BASE_URL : ''); 13254 }) 13255 .catch(error => { 13256 console.error(error); 13257 this.processRedirect(); 13258 }) 13259 }, 13260 13261 isInAccountSection() { 13262 return document.querySelector('body').classList.contains('account'); 13263 } 13264 } 13265 } 13266</script>
13266 13267 <div x-data="AmAuthPopup" 13268 x-on:private-content-loaded.window="onPrivateContentLoaded" 13269 x-on:amsl-show-popup.window="showOnExternalEvent" 13270 x-on:amsl-hide-popup.window="onHidePopup" 13271 x-on:amsl-content-updated.window="onContentUpdated" 13272 > 13273 <div x-cloak data-dialog-ref-name="social-login-popup" 13274 x-bind="overlay" 13275 class="fixed inset-0 bg-black/50 z-50"> 13276 <div class="fixed flex justify-center items-center text-left z-40 amsl-popup-modal p-6 inset-0"> 13277 <div x-ref="social-login-popup" role="dialog" aria-modal="true" 13278 aria-labelledby="social-login-popup" 13279 class="inline-block bg-white shadow-xl rounded-lg p-10 max-h-screen overflow-auto overscroll-y-contain"> 13280 <div id="social-login-popup" 13281 class="amsl-popup-block relative focus:outline-none focus-within:outline-none 13282 -social-right" 13283 role="dialog" 13284 aria-labelledby="amsl-popup-dialog" 13285 tabindex="0" 13286 x-on:click.stop 13287 > 13288 <button type="button" 13289 class="amsl-close absolute right-0 top-0 -mt-2 text-gray-400 hover:text-blue-800 transform md:translate-x-full" 13290 title="Cerrar" 13291 aria-label="Cerrar" 13292 role="button" 13293 x-on:click="closePopup" 13294 > 13295 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" role="img"> 13296 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 13297<title>x</title></svg> 13298 </button> 13299 <h2 class="amsl-dialog-title sr-only" id="amsl-popup-dialog"> 13300 Login and Registration Form </h2> 13301 <div class="amsl-tabs-wrapper" 13302 title="Login and Registration Form" 13303 > 13304 <ul class="amsl-tablist flex space-x-4" 13305 role="tablist" 13306 x-on:keydown="onKeypress" 13307 x-show="isNotForgotTab" 13308 > 13309 <li class="amsl-title" 13310 id="tab-amsl-login" 13311 role="tab" aria-controls="amsl-login-content" 13312 tabindex="0" 13313 > 13314 <span class="amsl-link block p-4 text-lg cursor-pointer border-b" 13315 data-toggle="switch" 13316 x-on:click.prevent="selectLoginTab" 13317 :class="loginTabClasses" 13318 > 13319 Iniciar Sesión </span> 13320 </li> 13321 <li class="amsl-title" 13322 id="tab-amsl-register" 13323 role="tab" aria-controls="amsl-register-content" 13324 tabindex="0" 13325 > 13326 <span class="amsl-link block p-4 text-lg cursor-pointer border-b" 13327 x-on:click.prevent="selectRegisterTab" 13328 :class="registerTabClasses" 13329 > 13330 RegÃstrate </span> 13331 </li> 13332 </ul> 13333 <div id="amsl-login-content" 13334 x-show="isLoginTab" 13335 x-cloak 13336 role="tabpanel" 13337 aria-labelledby="tab-amsl-login" 13338 > 13339 <template x-if="hasLoginMessages"> 13340 <div class="mt-4"> 13341 <template x-for="message in loginMessages" :key="message"> 13342 <div class="message error"> 13343 <span x-html="message"></span> 13344 </div> 13345 </template> 13346 </div> 13347 </template> 13348 <div class="amsl-content amsl-login-content mt-6 amsl-position-variations " 13349 > 13350 <template x-if="isNotLogged"> 13351 <div class="amsl-form"> 13352 <style> 13353 /* ---------- Tokens ---------- */ 13354 .mb-login { 13355 --mb-primary: #35515E; 13356 --mb-soft: #F4F8F9; 13357 --mb-border: #d6dfe3; 13358 --mb-text: #1f2d33; 13359 --mb-muted: #5f7179; 13360 --mb-radius: 0.75rem; 13361 13362 } 13363 13364 /* ---------- Contenedor ---------- */ 13365 .mb-login { 13366 max-width: 40rem; 13367 margin: 0 auto; 13368 padding: 0 1rem; 13369 color: var(--mb-text); 13370 box-sizing: border-box; 13371 } 13372 @media (min-width: 768px) { 13373 .mb-login__card { 13374 background: #fff; border: 1px solid var(--mb-border); 13375 border-radius: var(--mb-radius); padding: 1.5rem; 13376 } 13377 } 13378 .mb-login__title { 13379 font-size: 1.5rem; font-weight: 700; color: var(--mb-primary); 13380 margin: 0 0 1rem; 13381 } 13382 13383 .mb-notice { 13384 background: var(--mb-soft); 13385 border-left: 4px solid var(--mb-primary); 13386 border-radius: 0 0.5rem 0.5rem 0; 13387 padding: 0.875rem 1rem; 13388 margin-bottom: 1.25rem; 13389 font-size: 0.9rem; 13390 line-height: 1.5; 13391 color: var(--mb-primary); 13392 } 13393 .mb-notice a { font-weight: 700; text-decoration: underline;
13393 color: inherit; } 13394 13395 .mb-login__lead { text-align: center; font-size: 1rem; line-height: 1.5; margin: 0.25rem 0 1.25rem; } 13396 .mb-login__hint { color: var(--mb-muted); font-size: 0.9rem; margin: 0 0 1rem; } 13397 13398 .mb-entry { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 0.5rem; } 13399 .mb-back { 13400 display: inline-flex; align-items: center; gap: 0.35rem; 13401 background: none; border: 0; padding: 0; margin: 0 0 1rem; 13402 font-size: 0.875rem; color: var(--mb-primary); text-decoration: underline; cursor: pointer; 13403 } 13404 13405 /* ---------- Campos ---------- */ 13406 .mb-login .field { margin-bottom: 1rem; } 13407 .mb-login .field .label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.35rem; } 13408 .mb-login .form-input { 13409 width: 100%; 13410 min-height: 3rem; 13411 font-size: 16px; /* evita el zoom automático en iOS */ 13412 border: 1px solid var(--mb-border); 13413 border-radius: 0.5rem; 13414 padding: 0.65rem 0.875rem; 13415 background: #fff; 13416 } 13417 .mb-login .form-input:focus { 13418 border-color: var(--mb-primary); 13419 box-shadow: 0 0 0 3px rgba(53, 81, 94, 0.15); 13420 outline: none; 13421 } 13422 .mb-password { position: relative; } 13423 .mb-password .form-input { padding-right: 3rem; } 13424 .mb-password__toggle { 13425 position: absolute; top: 0; right: 0; height: 3rem; width: 3rem; 13426 display: flex; align-items: center; justify-content: center; 13427 color: var(--mb-muted); 13428 } 13429 13430 /* ---------- Botones ---------- */ 13431 .mb-submit { 13432 width: 100%; min-height: 3.25rem; font-size: 1.05rem; font-weight: 700; 13433 justify-content: center; border-radius: 0.5rem; 13434 } 13435 .mb-forgot { display: block; text-align: center; margin-top: 1rem; font-size: 0.9rem; color: var(--mb-muted); text-decoration: underline; } 13436 .mb-forgot:hover { color: var(--mb-primary); } 13437 .mb-error { 13438 display: flex; align-items: center; gap: 0.5rem; margin-top: 1rem; 13439 background: #fef2f2; border: 1px solid #fee2e2; color: #b91c1c; 13440 border-radius: 0.5rem; padding: 0.75rem; font-size: 0.9rem; 13441 } 13442 13443 /* ---------- Nuevo cliente: visible pero secundario ---------- */ 13444 .mb-new { display: none; } 13445 .mb-new.is-moved { 13446 display: block; 13447 margin-top: 1.25rem; padding-top: 1.25rem; 13448 border-top: 1px solid var(--mb-border); 13449 text-align: center; 13450 } 13451 #mb-newcustomer-slot .btn, 13452 #mb-newcustomer-slot .action.create,
13453 #mb-newcustomer-slot .action.primary, 13454 #mb-newcustomer-slot a.primary, 13455 #mb-newcustomer-slot button { 13456 display: flex !important; align-items: center; justify-content: center; 13457 width: 100%; min-height: 3rem; margin-top: 0.75rem; 13458 background: var(--mb-soft) !important; color: var(--mb-primary) !important; 13459 border: 1.5px solid var(--mb-primary) !important; border-radius: 0.5rem !important; 13460 box-shadow: none !important; font-size: 1rem; font-weight: 700; 13461 text-decoration: none; 13462 transition: background-color .15s, color .15s; 13463 } 13464 #mb-newcustomer-slot .btn:hover, 13465 #mb-newcustomer-slot .action.create:hover, 13466 #mb-newcustomer-slot .action.primary:hover, 13467 #mb-newcustomer-slot a.primary:hover, 13468 #mb-newcustomer-slot button:hover { 13469 background: var(--mb-primary) !important; color: #fff !important; 13470 } 13471 #mb-newcustomer-slot .btn *, 13472 #mb-newcustomer-slot a.primary *, 13473 #mb-newcustomer-slot button * { color: inherit !important; } 13474 /* El bloque movido pierde su "card" para integrarse */ 13475 #mb-newcustomer-slot > * { 13476 background: none !important; border: 0 !important; box-shadow: none !important; 13477 padding: 0 !important; margin: 0 !important; height: auto !important; 13478 } 13479 #mb-newcustomer-slot h2, 13480 #mb-newcustomer-slot h3, 13481 #mb-newcustomer-slot .block-title { 13482 font-size: 1rem !important; font-weight: 700; color: var(--mb-primary); 13483 border: 0 !important; padding: 0 !important; margin: 0 0 0.5rem !important; 13484 } 13485 #mb-newcustomer-slot p, 13486 #mb-newcustomer-slot li { font-size: 0.9rem; color: var(--mb-muted); } 13487 13488 /* ---------- Amasty Social Login (se mueve al hueco #mb-social-slot) ---------- */ 13489 #mb-social-slot .amsl-social-wrapper, 13490 #mb-social-slot .amsl-login-page, 13491 #mb-social-slot .amsl-social-login { 13492 max-width: none; margin: 0; padding: 0; border: 0; background: none; 13493 } 13494 #maincontent .amsl-separator, 13495 #maincontent .amsl-title,
13496 #mb-social-slot .amsl-separator, 13497 #mb-social-slot .amsl-title { display: none; } 13498 #mb-social-slot .amsl-buttons { display: flex; flex-direction: column; gap: 0.75rem; width: 100%; } 13499 #mb-social-slot .amsl-button-wrapper { width: 100% !important; max-width: none !important; margin: 0 !important; } 13500 #mb-social-slot .amsl-button { 13501 position: relative; 13502 width: 100% !important; max-width: none !important; margin: 0 !important; 13503 min-height: 3.25rem; padding: 0.5rem 3rem !important; 13504 display: flex !important; align-items: center; justify-content: center; 13505 font-size: 1rem !important; font-weight: 500; 13506 background: #fff !important; color: var(--mb-text) !important; 13507 border: 1px solid var(--mb-text) !important; border-radius: 0.5rem !important; 13508 box-shadow: none !important; 13509 } 13510 #mb-social-slot .amsl-button:hover { background: var(--mb-soft) !important; } 13511 #mb-social-slot .mb-social-orig { display: none !important; } 13512 #mb-social-slot .mb-social-label { 13513 display: inline !important; color: var(--mb-text) !important; 13514 font-size: 1rem; font-weight: 500; line-height: 1.2; 13515 visibility: visible !important; opacity: 1 !important; position: static !important; 13516 width: auto !important; height: auto !important; text-indent: 0 !important; 13517 } 13518 #mb-social-slot .amsl-button > img, 13519 #mb-social-slot .amsl-button > svg, 13520 #mb-social-slot .amsl-button [class*="icon"] { 13521 position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); 13522 width: 22px; height: 22px; 13523 display: block !important; visibility: visible !important; opacity: 1 !important; 13524 } 13525 #mb-social-slot .amsl-button [class*="icon"] svg, 13526 #mb-social-slot .amsl-button [class*="icon"] img { width: 100%; height: 100%; display: block; } 13527 13528 /* ---------- Campo email (clase propia: el popup oculta .field.email) ---------- */ 13529 .mb-login .mb-field-email { display: block; } 13530 13531 /* ---------- Popup Ajax de Amasty: mismo aspecto que la página ---------- */ 13532 .amsl-popup-block .amsl-content.amsl-position-variations { display: block !important; } 13533 .amsl-popup-block .amsl-content .amsl-separator, 13534 .amsl-popup-block .amsl-content > .amsl-social-wrapper { display: none !important; } 13535 .amsl-popup-block .amsl-form { width: 100% !important; max-width: none !important; } 13536 .amsl-popup-block .mb-login, 13537 .amsl-popup-block .mb-register { max-width: 32rem; padding: 0; } 13538 .amsl-popup-block .mb-login__card { border: 0 !important; padding: 0 !important; background: none !important; } 13539 .amsl-popup-block .mb-login__title { display: none; } 13540 /* Aviso legal de reCAPTCHA duplicado que añade Amasty fuera del formulario */ 13541 .amsl-popup-block .amsl-form > .recaptcha-wrapper { display: none !important; } 13542</style> 13543 13544<div class="mb-login" x-data="mbLoginPanel" data-open="false"> 13545 <div class="mb-login__card"> 13546 <h2 class="mb-login__title" id="am-block-customer-login-heading"> 13547 Ya soy cliente </h2> 13548 13549 <!-- Pantalla de entrada: social login + email --> 13550 <div x-show="isEmailClosed" x-transition.opacity> 13551 13552 <div class="mb-entry"> 13553 <!-- Aquà se recoloca el bloque de Amasty Social Login --> 13554 <div id="mb-social-slot"></div> 13555 13556 <button type="button" 13557 class="btn btn-primary mb-submit" 13558 aria-controls="mb-email-panel" 13559 :aria-expanded="emailExpanded" 13560 @click="openEmail"> 13561 Continuar con email </button> 13562 </div> 13563 13564 <!-- Nuevo cliente: aquà se recoloca el bloque "Crear cuenta" de la página (con el mensaje VIP) --> 13565 <div class="mb-new"> 13566 <div id="mb-newcustomer-slot"></div> 13567 </div> 13568 </div> 13569 13570 <!-- Panel desplegable: login con email --> 13571 <div id="mb-email-panel" x-show="isEmailOpen" x-transition x-cloak aria-labelledby="am-block-customer-login-heading"> 13572 <button type="button" class="mb-back" @click="closeEmail">
13573 <span aria-hidden="true">←</span> 13574 <span>Otras opciones de acceso</span> 13575 </button> 13576 13577 <!-- Aviso clientes de la web anterior (solo al elegir email) --> 13578 <!-- <div class="mb-notice"> 13579 ¡Hemos actualizado nuestra web! Si tenÃas cuenta antes de abril de 2026, pulsa en ¿Has olvidado tu contraseña? para actualizarla. Si lo haces y no recibes el email, significa que no estás registrado: simplemente crea una cuenta nueva. Si tienes dudas, <a href="mailto:info2@mueblesbonitos.com?subject=Dudas sobre el acceso o registro">escrÃbenos aquÃ.</a> 13580 </div> --> 13581 13582 <p class="mb-login__hint"> 13583 Si ya tienes una cuenta, inicia sesión con tu email. </p> 13584 13585 <form class="form form-login" 13586 action="https://www.mueblesbonitos.com/customer/account/loginPost/" 13587 method="post" 13588 x-data="initCustomerLoginForm" 13589 @submit.prevent="submitForm" 13590 id="customer-login-form"> 13591 <input name="form_key" type="hidden" value="GoQ6wnK4Gflfjncs" /> <fieldset class="fieldset login"> 13592 <legend class="sr-only">Ya soy cliente</legend> 13593 13594 <div class="field mb-field-email required"> 13595 <label class="label" for="email"> 13596 <span>Email</span> 13597 </label> 13598 <div class="control"> 13599 <input name="login[username]" 13600 class="form-input" 13601 required 13602 value="" 13603 autocomplete="off" 13604 id="email" 13605 type="email" 13606 inputmode="email" 13607 autocapitalize="off" 13608 spellcheck="false" 13609 placeholder="tu@email.com" 13610 title="Email"> 13611 </div> 13612 </div> 13613 13614 <div class="field password required"> 13615 <label for="am-pass" class="label"> 13616 <span>Contraseña</span> 13617 </label> 13618 <div class="control mb-password"> 13619 <input name="login[password]" 13620 class="form-input" 13621 required 13622 type="password" 13623 :type="pwType" 13624 autocomplete="off" 13625 id="am-pass" 13626 title="Contraseña"> 13627 <button type="button" 13628 class="mb-password__toggle" 13629 :aria-pressed="pwPressed" 13630 @click="togglePw" 13631 :aria-label="pwLabel"> 13632 <span x-show="pwIsHidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 13633 <path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/> 13634 <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/> 13635</svg> 13636</span> 13637 <span x-show="pwIsVisible" x-cloak><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 13638 <path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/> 13639 <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/> 13640</svg> 13641</span> 13642 </button> 13643 </div> 13644 </div> 13645 13646 <div class="control"> 13647 <input type="hidden" 13648 value="" 13649 name="g-recaptcha-response" 13650 > 13651</div> 13652 13653 <div class="actions-toolbar"> 13654 <button type="submit" 13655 class="btn btn-primary mb-submit" 13656 name="send" 13657 >
13658 <span>Entrar a mi cuenta</span> 13659 </button> 13660 </div> 13661 13662 <a class="mb-forgot" rel="nofollow" href="https://www.mueblesbonitos.com/customer/account/forgotpassword/"> 13663 <span>¿Has olvidado tu contraseña?</span> 13664 </a> 13665 13666 <template x-if="displayErrorMessage"> 13667 <p class="mb-error"> 13668 <span class="inline-block w-5 h-5 shrink-0"> 13669 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20" aria-hidden="true"> 13670 <path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> 13671</svg> 13672 </span> 13673 <template x-for="errorMessage in errorMessages"> 13674 <span x-html="errorMessage"></span> 13675 </template> 13676 </p> 13677 </template> 13678 </fieldset> 13679 </form> 13680 13681 <div class="mt-3 text-xs text-center" style="color: var(--mb-muted)"> 13682 <p class="prose my-4 text-sm"> 13683 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 13684</p> 13685 </div> 13686 </div> 13687 </div> 13688 13689
13689<script> 13690 (function () { 13691 // Bloque .mb-login al que pertenece este script (puede haber otro en el popup de Amasty) 13692 const root = document.currentScript && document.currentScript.closest('.mb-login'); 13693 if (!root) return; 13694 // Dentro del popup de Amasty: los botones sociales están en la misma pestaña (.amsl-content) 13695 const popupContent = root.closest('.amsl-popup-block') ? root.closest('.amsl-content') : null; 13696 13697 const labels = { 13698 google: 'Continuar\u0020con\u0020Google', 13699 facebook: 'Continuar\u0020con\u0020Facebook', 13700 apple: 'Continuar\u0020con\u0020Apple', 13701 twitter: 'Continuar\u0020con\u0020X', 13702 linkedin: 'Continuar\u0020con\u0020LinkedIn', 13703 amazon: 'Continuar\u0020con\u0020Amazon', 13704 paypal: 'Continuar\u0020con\u0020PayPal' 13705 }; 13706 const outsidePopup = (el) => !el.closest('.amsl-popup-block'); 13707 const wrapText = (node) => { 13708 const w = document.createElement('span'); 13709 w.className = 'mb-social-orig'; 13710 node.replaceWith(w); 13711 w.appendChild(node); 13712 }; 13713 const addLabels = () => { 13714 root.querySelectorAll('#mb-social-slot .amsl-button').forEach((btn) => { 13715 if (btn.querySelector('.mb-social-label')) return; 13716 const hint = (btn.className + ' ' + (btn.getAttribute('href') || '') + ' ' + 13717 (btn.getAttribute('title') || '') + ' ' + (btn.dataset.amslType || '') + ' ' + 13718 (btn.parentElement ? btn.parentElement.className : '')).toLowerCase(); 13719 const key = Object.keys(labels).find((k) => hint.includes(k)); 13720 if (!key) return; 13721 // Ocultamos solo el texto original de Amasty, nunca el elemento que lleva el logo 13722 btn.querySelectorAll('*').forEach((el) => { 13723 if (el.closest('svg') || el.tagName === 'IMG') return; 13724 if (el.querySelector('svg, img')) return; 13725 const cs = getComputedStyle(el); 13726 const before = getComputedStyle(el, '::before'); 13727 const hasIcon = (cs.backgroundImage && cs.backgroundImage !== 'none') || 13728 (cs.maskImage && cs.maskImage !== 'none') || 13729 (before.content && before.content !== 'none' && before.content !== 'normal'); 13730 const ownText = Array.from(el.childNodes) 13731 .filter((n) => n.nodeType === 3) 13732 .map((n) => n.textContent).join('').trim(); 13733 if (!ownText) return; 13734 if (hasIcon) { 13735 Array.from(el.childNodes).forEach((n) => { 13736 if (n.nodeType === 3 && n.textContent.trim()) wrapText(n); 13737 }); 13738 } else { 13739 el.classList.add('mb-social-orig'); 13740 } 13741 }); 13742 Array.from(btn.childNodes).forEach((n) => { 13743 if (n.nodeType === 3 && n.textContent.trim()) wrapText(n); 13744 }); 13745 const label = document.createElement('span'); 13746 label.className = 'mb-social-label'; 13747 label.textContent = labels[key]; 13748 btn.appendChild(label); 13749 }); 13750 }; 13751 const move = () => { 13752 const slot = root.querySelector('#mb-social-slot'); 13753 if (!slot) return; 13754 if (popupContent) { 13755 const popupButtons = Array.from(popupContent.querySelectorAll('.amsl-buttons')) 13756 .find((el) => !slot.contains(el));
13757 if (popupButtons) slot.appendChild(popupButtons); 13758 addLabels(); 13759 return; 13760 } 13761 // Solo buscamos el bloque de Amasty dentro del contenido principal (nunca en la cabecera ni en el popup) 13762 const main = document.getElementById('maincontent') || document.querySelector('main') || document.body; 13763 const buttons = Array.from(main.querySelectorAll('.amsl-buttons')) 13764 .find((el) => !slot.contains(el) && outsidePopup(el) && !el.closest('header, .page-header, #header')); 13765 if (buttons) { 13766 let social = buttons; 13767 const wrapper = buttons.closest('.amsl-social-login, .amsl-social-wrapper, .amsl-login-page'); 13768 if (wrapper && main.contains(wrapper) && !wrapper.contains(slot) && outsidePopup(wrapper) && 13769 !wrapper.querySelector('header, .page-header, nav, form')) { 13770 social = wrapper; 13771 } 13772 slot.appendChild(social); 13773 } 13774 addLabels(); 13775 }; 13776 const moveNewCustomer = () => { 13777 const slot = root.querySelector('#mb-newcustomer-slot'); 13778 const login = root; 13779 if (!slot || slot.children.length) return; 13780 const main = document.getElementById('maincontent') || document.querySelector('main') || document.body; 13781 const safe = (el) => el && !el.contains(login) && !login.contains(el) && outsidePopup(el) && 13782 !el.closest('header, .page-header, #header, nav') && 13783 !el.querySelector('form, header, nav'); 13784 13785 let block = null; 13786 // 1) Clases estándar del bloque de nuevo cliente 13787 const byClass = Array.from(main.querySelectorAll('.block-new-customer, .block.new-customer, .customer-new')) 13788 .find(outsidePopup); 13789 if (byClass) block = byClass.closest('.card') || byClass; 13790 // 2) Enlace a la página de registro (sea cual sea la URL traducida del registro) 13791 if (!safe(block)) { 13792 const createUrl = "https:\/\/www.mueblesbonitos.com\/customer\/account\/create\/"; 13793 const link = Array.from(main.querySelectorAll('a[href]')).find((a) => 13794 !login.contains(a) && outsidePopup(a) && !a.closest('header, .page-header, #header, nav') && 13795 (a.href.indexOf('customer/account/create') !== -1 || a.href.split('?')[0] === createUrl.split('?')[0])); 13796 if (link) block = link.closest('.card') || link.parentElement; 13797 } 13798 // 3) La otra columna de la rejilla del login 13799 if (!safe(block)) { 13800 let node = login; 13801 while (node.parentElement && node.parentElement !== main) { 13802 const parent = node.parentElement; 13803 const display = getComputedStyle(parent).display; 13804 if ((display === 'grid' || display === 'flex') && parent.children.length > 1) { 13805 block = Array.from(parent.children).find((c) => c !== node && c.querySelector('a, button')); 13806 break; 13807 } 13808 node = parent; 13809 } 13810 } 13811 if (!safe(block)) return; 13812 13813 const parent = block.parentElement; 13814 slot.appendChild(block); 13815 slot.parentElement.classList.add('is-moved'); 13816 // La rejilla de 2 columnas se queda con una sola: que ocupe todo el ancho 13817 if (parent && getComputedStyle(parent).display === 'grid') { 13818 parent.style.gridTemplateColumns = 'minmax(0, 1fr)'; 13819 } 13820 }; 13821 const init = () => { move(); if (!popupContent) moveNewCustomer(); }; 13822 init(); 13823 window.addEventListener('DOMContentLoaded', init); 13824 })(); 13825 13826 // Panel "Continuar con email" / "Otras opciones de acceso" 13827 function mbLoginPanel() { 13828 return { 13829 emailOpen: false, 13830 init() { 13831 this.emailOpen = this.$el.dataset.open === 'true'; 13832 }, 13833 isEmailOpen() { 13834 return this.emailOpen; 13835 }, 13836 isEmailClosed() { 13837 return !this.emailOpen; 13838 }, 13839 emailExpanded() { 13840 return this.emailOpen ? 'true' : 'false'; 13841 }, 13842 openEmail() { 13843 this.emailOpen = true; 13844 this.$nextTick(() => { 13845 const f = this.$root.querySelector('[name="login[username]"]');
13846 f && f.focus(); 13847 }); 13848 }, 13849 closeEmail() { 13850 this.emailOpen = false; 13851 } 13852 } 13853 } 13854 13855 function initCustomerLoginForm() { 13856 return { 13857 errors: 0, 13858 hasCaptchaToken: 0, 13859 pwVisible: false, 13860 displayErrorMessage: false, 13861 errorMessages: [], 13862 togglePw() { 13863 this.pwVisible = !this.pwVisible; 13864 }, 13865 pwType() { 13866 return this.pwVisible ? 'text' : 'password'; 13867 }, 13868 pwPressed() { 13869 return this.pwVisible ? 'true' : 'false'; 13870 }, 13871 pwIsHidden() { 13872 return !this.pwVisible; 13873 }, 13874 pwIsVisible() { 13875 return this.pwVisible; 13876 }, 13877 pwLabel() { 13878 return this.pwVisible 13879 ? 'Ocultar\u0020contrase\u00F1a' 13880 : 'Mostrar\u0020Contrase\u00F1a'; 13881 }, 13882 setErrorMessages(messages) { 13883 this.errorMessages = [messages]; 13884 this.displayErrorMessage = this.errorMessages.length; 13885 }, 13886 submitForm() { 13887 // $form = este formulario (página o popup). No usar el id: puede estar duplicado. 13888 const $form = this.$root; 13889 // Exactamente un campo g-recaptcha-response dentro del formulario 13890 // (si hay dos, el token no se guarda; si no hay ninguno, se envÃa sin token) 13891 const tokenInputs = $form.querySelectorAll('[name="g-recaptcha-response"]'); 13892 tokenInputs.forEach((input, i) => { if (i > 0) input.remove(); }); 13893 if (!tokenInputs.length) { 13894 const input = document.createElement('input'); 13895 input.type = 'hidden'; 13896 input.name = 'g-recaptcha-response'; 13897 $form.appendChild(input); 13898 } 13899 if (!this.hasCaptchaToken) { 13900 this.errors = 1; 13901 13902 13903 const executeGreCaptcha = () => { 13904 grecaptcha.ready(() => { 13905 grecaptcha.execute( 13906 '6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3', 13907 {action: 'submit'} 13908 ).then((token) => { 13909 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 13910 13911 if (tokenElement && token && token.length > 0) { 13912 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 13913 this.errors = 0; 13914 this.hasCaptchaToken = 1; 13915 (this.submitForm || $form.submit).call(this); 13916 } else { 13917 this.errors = 1; 13918 const error = tokenElement 13919 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 13920 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 13921 if (this.setErrorMessages) { 13922 this.setErrorMessages([error]) 13923 this.displayErrorMessage = true; 13924 } else { 13925 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 13926 } 13927 } 13928 }).catch(exception => { 13929 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 13930 }); 13931 }) 13932 } 13933 13934 if (window.grecaptcha) { 13935 executeGreCaptcha(); 13936 } else { 13937 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3"; 13938 const script = document.createElement('script'); 13939 script.setAttribute('type', 'text/javascript'); 13940 script.setAttribute('src', recaptchaUrl); 13941 document.head.appendChild(script); 13942 13943 script.addEventListener("load", executeGreCaptcha, false); 13944 } 13945 } 13946 if (this.errors === 0) { 13947 $form.submit(); 13948 } 13949 } 13950 } 13951 } 13952 13953 ;(() => { 13954 const register = () => { 13955 Alpine.data('mbLoginPanel', mbLoginPanel); 13956 Alpine.data('initCustomerLoginForm', initCustomerLoginForm); 13957 }; 13958 (document.readyState === 'loading' || !window.Alpine) 13959 ? window.addEventListener('alpine:init', register, {once: true}) 13960 : register(); 13961 })(); 13962 </script>
13962 13963 </div> 13964 13965 <div class="recaptcha-login-wrapper recaptcha-wrapper w-full"> 13966 <div class="control"> 13967 <input type="hidden" 13968 value="" 13969 name="g-recaptcha-response" 13970 > 13971</div> 13972 </div> 13973 <div class="recaptcha-login-wrapper recaptcha-wrapper w-full"> 13974 <p class="prose my-4 text-sm"> 13975 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 13976</p> 13977 </div> 13978 </div> 13979 </template> 13980 <span class="amsl-separator bg-gray-500 hidden text-secondary text-sm font-bold relative w-0.5"> 13981 <span 13982 class="amsl-icon absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 13983 border border-gray-500 rounded-full bg-white overflow-hidden w-8 h-8 13984 min-w-8 flex items-center justify-center pb-[3px]" 13985 >o bien</span> 13986 </span> 13987 <div class="amsl-social-wrapper" 13988 > 13989 <div class="amsl-title text-base font-medium text-gray-70 mb-2"> 13990 Inicia sesión con tus redes sociales </div> 13991 <div class="amsl-title text-base font-medium text-gray-70 mb-2 -short"> 13992 Iniciar Sesión con </div> 13993 <div class="amsl-social-login "> 13994 <template x-if="hasSocialError"> 13995 <p class="amsl-error -social message error mb-4" x-text="socialErrorMessage"></p> 13996 </template> 13997 <div class="amsl-buttons flex flex-wrap justify-center gap-7" 13998 :class="socialButtonsClasses" 13999 > 14000 <div 14001 class="amsl-button-wrapper 14002 " 14003 > 14004 <form method="POST" 14005 action="https://www.mueblesbonitos.com/amsociallogin/social/login/?type=google" 14006 class="amsl-button-form" 14007 aria-label="Sign in with Google" 14008 x-on:submit="socialLoginClick" 14009 > 14010 <input name="form_key" type="hidden" value="lYvGLDMwoyHIBAad" /> <button 14011 type="submit" 14012 class="amsl-button rounded-full overflow-hidden bg-white 14013 shadow-md hover:shadow-lg transition-amsl-social-button 14014 block w-16 h-16 p-4 -google " 14015 title="Sign in with Google" 14016 > 14017 <span 14018 class="amsl-social-icon pointer-events-none 14019 " role="img" 14020 aria-label="Sign in with Google" 14021 > 14022 <svg xmlns="http://www.w3.org/2000/svg" xmlns:v="https://vecta.io/nano" viewBox="0 0 31 33" fill="none" width="24" height="24" role="img"><path d="M1.125 10.662c-.726 1.85-1.1 3.841-1.023 5.869-.061 3.005.825 5.947 2.383 8.465l4.781-3.654c-.261-.501-.478-1.03-.643-1.586-.625-1.678-.712-3.469-.371-5.174l-5.127-3.92z" fill="#fbbc05"/><path d="M15.832.502l-.775.045c-6.14.075-11.7 4.435-13.93 10.115l5.125 3.918c.711-3.552 3.289-6.733 6.809-7.75 3.23-1.155 6.557.145 9.322 1.85 1.399-1.331 2.71-2.751 3.998-4.189C23.437 1.989 19.706.395 15.832.502zm.016 13.736v.041l.047-.041c-.016 0-.031 0-.047 0z" fill="#ea4335"/><path d="M23.387 14.219c-2.298-.001-4.595.006-6.891.01l-.648.496.008 4.953 9.035.107c-.76 2.645-2.493 5.106-5.121 6.061-4.56 2.039-10.247-.148-12.514-4.533l-4.777 3.662c1.906 3.086 4.822 5.537 8.256 6.682 5.873 2.003 13.093.505 17.002-4.602 2.853-3.577 3.502-8.348 3.193-12.805l-7.543-.031z" fill="#34a853"/><path d="M23.385 14.219c-2.514-.001-5.026.006-7.537.01l.008 5.449 9.035.107c-.69 2.401-2.185 4.647-4.42 5.756l4.959 3.84c.852-.669 1.63-1.442 2.307-2.326 2.853-3.577 3.502-8.348 3.193-12.805l-7.545-.031z" fill="#4285f4"/><title>google</title></svg> 14023 </span> 14024 </button> 14025 </form> 14026 </div> 14027 <div 14028 class="amsl-button-wrapper 14029 " 14030 > 14031 <form method="POST" 14032 action="https://www.mueblesbonitos.com/amsociallogin/social/login/?type=facebook" 14033 class="amsl-button-form" 14034 aria-label="Sign in with Facebook" 14035 x-on:submit="socialLoginClick" 14036 > 14037 <input name="form_key" type="hidden" value="lYvGLDMwoyHIBAad" /> <button 14038 type="submit" 14039 class="amsl-button rounded-full overflow-hidden bg-white 14040 shadow-md hover:shadow-lg transition-amsl-social-button 14041 block w-16 h-16 p-4 -facebook " 14042 title="Sign in with Facebook" 14043 >
14044 <span 14045 class="amsl-social-icon pointer-events-none 14046 " role="img" 14047 aria-label="Sign in with Facebook" 14048 > 14049 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 38" fill="none" width="24" height="24" role="img"><path d="M12.37 37.28V20.668h5.576l.835-6.474H12.37V10.06c0-1.875.52-3.152 3.209-3.152l3.428-.002v-5.79c-.593-.08-2.628-.256-4.996-.256-4.943 0-8.327 3.017-8.327 8.558v4.775H.094v6.475h5.59V37.28h6.686z" fill="currentColor"/><title>facebook</title></svg> 14050 </span> 14051 </button> 14052 </form> 14053 </div> 14054 </div> 14055 </div> 14056 </div> 14057 14058
14058<script> 14059 function AmSocialLogin() { 14060 return { 14061 socialErrorMessage: '', 14062 isPopupEnabled: '1', 14063 14064 initializeSocialLogin() { 14065 this.initContentUpdaters(); 14066 }, 14067 14068 socialLoginClick(event) { 14069 const form = event.currentTarget; 14070 14071 if (this.isPopupEnabled) { 14072 form.target = '_blank'; 14073 form.action = form.action + '&isAjax=true'; 14074 } 14075 14076 const channel = new BroadcastChannel('amSocialLoginData'); 14077 channel.addEventListener('message', this.onMessageEvent.bind(this)); 14078 14079 event.stopPropagation(); 14080 event.preventDefault(); 14081 form.submit(); 14082 14083 return false; 14084 }, 14085 14086 onSocialResponse(data) { 14087 const isSuccessfulResult = data.result === 1; 14088 14089 if (isSuccessfulResult) { 14090 window.dispatchEvent( 14091 new CustomEvent( 14092 'amsl-popup-show-notification', 14093 { 14094 detail: data.messages 14095 } 14096 ) 14097 ); 14098 this.processRedirect(); 14099 } else { 14100 const redirectData = data?.redirect_data; 14101 14102 this.socialErrorMessage = data.messages.pop(); 14103 setTimeout(() => { 14104 this.socialErrorMessage = ''; 14105 }, 5000); 14106 14107 if (this.shouldCustomUrlRedirectWithError(redirectData)) { 14108 return this.processRedirect(redirectData?.url); 14109 } 14110 14111 if (redirectData?.redirectWithError) { 14112 this.processRedirect(); 14113 } 14114 } 14115 }, 14116 14117 // Helper CSP: x-if="hasSocialError" 14118 hasSocialError() { 14119 return !!this.socialErrorMessage; 14120 }, 14121 14122 shouldCustomUrlRedirectWithError(redirectData) { 14123 return ( 14124 redirectData && 14125 redirectData.redirect && 14126 redirectData.redirectWithError && 14127 redirectData.url 14128 ); 14129 }, 14130 14131 onMessageEvent(event) { 14132 if (event.origin !== window.location.origin) { 14133 return; 14134 } 14135 14136 const data = JSON.parse(event.data); 14137 if (data['redirect_data']) { 14138 this.onSocialResponse(data); 14139 } 14140 }, 14141 14142 ...AmAuthPopupRedirect(), 14143 ...AmAuthPopupReloadContent() 14144 } 14145 } 14146 14147 ;(() => { 14148 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 14149 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 14150 const register = () => Alpine.data('AmSocialLogin', AmSocialLogin); 14151 (document.readyState === 'loading' || !window.Alpine) 14152 ? window.addEventListener('alpine:init', register, {once: true}) 14153 : register(); 14154 })(); 14155</script>
14155 14156 </div> 14157 </div> 14158 <div id="amsl-register-content" 14159 x-show="isRegisterTab" 14160 x-cloak 14161 role="tabpanel" 14162 aria-labelledby="tab-amsl-register" 14163 > 14164 <template x-if="hasRegisterMessages"> 14165 <div class="mt-4"> 14166 <template x-for="message in registerMessages" :key="message"> 14167 <div class="message error"> 14168 <span x-html="message"></span> 14169 </div> 14170 </template> 14171 </div> 14172 </template> 14173 <div class="amsl-content amsl-register-content mt-6"> 14174 <template x-if="isNotLogged"> 14175 <div class="amsl-form mb-12"> 14176 <style> 14177 /* ---------- Tokens ---------- */ 14178 /* También en .mb-register: en el popup Ajax no existe .customer-account-create */ 14179 .customer-account-create, 14180 .mb-register { 14181 --mb-primary: #35515E; 14182 --mb-primary-hover: #2a414b; 14183 --mb-soft: #F4F8F9; 14184 --mb-border: #d6dfe3; 14185 --mb-text: #1f2d33; 14186 --mb-muted: #5f7179; 14187 --mb-radius: 0.75rem; 14188 } 14189 14190 /* ---------- Contenedor general ---------- */ 14191 .mb-register { 14192 max-width: 40rem; 14193 margin: 0 auto; 14194 padding: 0 1rem; 14195 color: var(--mb-text); 14196 box-sizing: border-box; 14197 } 14198 14199 .mb-notice { 14200 background: var(--mb-soft); 14201 border-left: 4px solid var(--mb-primary); 14202 border-radius: 0 0.5rem 0.5rem 0; 14203 padding: 0.875rem 1rem; 14204 margin-bottom: 1.25rem; 14205 font-size: 0.9rem; 14206 line-height: 1.5; 14207 color: var(--mb-primary); 14208 } 14209 .mb-notice a { font-weight: 700; text-decoration: underline; color: inherit; } 14210 14211 /* ---------- Bloques (sin "cards" pesadas en móvil) ---------- */ 14212 .mb-section { border: 0; padding: 0; margin: 0 0 1.5rem; min-width: 0; } 14213 .mb-section__title { 14214 display: flex; align-items: center; gap: 0.5rem; 14215 font-size: 1rem; font-weight: 700; margin-bottom: 0.75rem; 14216 color: var(--mb-primary); 14217 } 14218 .mb-consents { margin-top: 1.25rem; } 14219 @media (min-width: 768px) { 14220 .mb-section { 14221 background: #fff; border: 1px solid var(--mb-border); 14222 border-radius: var(--mb-radius); padding: 1.5rem; 14223 } 14224 } 14225 14226 /* ---------- Campos ---------- */ 14227 .mb-register .field { margin-bottom: 1rem; } 14228 .mb-register .field .label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.35rem; } 14229 .mb-register .form-input, 14230 .mb-register .form-select, 14231 .mb-register input[type="text"], 14232 .mb-register input[type="email"], 14233 .mb-register input[type="tel"], 14234 .mb-register input[type="password"], 14235 .mb-register select { 14236 width: 100%; 14237 min-height: 3rem; 14238 font-size: 16px; /* evita el zoom automático en iOS */ 14239 border: 1px solid var(--mb-border); 14240 border-radius: 0.5rem; 14241 padding: 0.65rem 0.875rem; 14242 background: #fff; 14243 } 14244 .mb-register .form-input:focus, 14245 .mb-register .form-select:focus { 14246 border-color: var(--mb-primary); 14247 box-shadow: 0 0 0 3px rgba(53, 81, 94, 0.15); 14248 outline: none; 14249 } 14250 /* Nombre y apellidos lado a lado a partir de ~480px */ 14251 @media (min-width: 480px) { 14252 .mb-register .field-name-firstname, 14253 .mb-register .field-name-lastname { display: inline-block; width: calc(50% - 0.375rem); vertical-align: top; } 14254 .mb-register .field-name-firstname { margin-right: 0.5rem; } 14255 } 14256 14257 /* ---------- Contraseña con ojo dentro del campo ---------- */ 14258 .mb-password { position: relative; } 14259 .mb-password .form-input { padding-right: 3rem; } 14260 .mb-password__toggle { 14261 position: absolute; top: 0; right: 0; height: 3rem; width: 3rem; 14262 display: flex; align-items: center; justify-content: center; 14263 color: var(--mb-muted); 14264 } 14265 .mb-hint { font-size: 0.8rem; color: var(--mb-muted); margin-top: 0.35rem; } 14266 .mb-register .password-strength-meter { font-size: 0.8rem; color: var(--mb-muted); margin-top: 0.35rem; } 14267 14268 /* ---------- Consentimientos ---------- */ 14269 .mb-check { display: flex; gap: 0.75rem; align-items: flex-start; margin-bottom: 0.875rem; } 14270 .mb-check input { width: 1.25rem; height: 1.25rem; margin-top: 0.1rem; flex-shrink: 0; accent-color: var(--mb-primary); } 14271 .mb-check label { font-size: 0.9rem; line-height: 1.4; } 14272 .mb-check a { color: var(--mb-primary); text-decoration: underline; } 14273 14274 /* ---------- Botón ---------- */ 14275 .mb-submit { 14276 width: 100%; min-height: 3.25rem; font-size: 1.05rem; font-weight: 700; 14277 justify-content: center; border-radius: 0.5rem; 14278 } 14279 .mb-register__footer { text-align: center; margin-top: 1rem; font-size: 0.9rem; color: var(--mb-muted); } 14280 .mb-register__footer a { color: var(--mb-primary); font-weight: 600; text-decoration: underline; } 14281 14282 /* ---------- Pantalla de entrada (tipo Sklum) ---------- */ 14283 .mb-register__lead { 14284 text-align: center; color: var(--mb-text); font-size: 1rem; line-height: 1.5; 14285 margin: 0.75rem 0 1.25rem; 14286 } 14287 .mb-entry { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 1.25rem; } 14288 .mb-social-note { font-size: 0.8rem; color: var(--mb-muted); text-align: center; margin: 0.25rem 0 0; } 14289 .mb-social-note a { color: var(--mb-primary); text-decoration: underline; } 14290 .mb-back { 14291 display: inline-flex; align-items: center; gap: 0.35rem; 14292 background: none; border: 0; padding: 0; margin: 0.25rem 0 1rem; 14293 font-size: 0.875rem; color: var(--mb-primary); text-decoration: underline; cursor: pointer; 14294 } 14295 14296 /* ---------- Amasty Social Login (se mueve debajo de "Continuar con email") ---------- 14297 Revisa en el inspector que las clases coinciden con tu versión del módulo. */ 14298 #mb-social-slot .amsl-social-wrapper,
14299 #mb-social-slot .amsl-login-page, 14300 #mb-social-slot .amsl-social-login { 14301 max-width: none; margin: 0; padding: 0; border: 0; background: none; 14302 } 14303 #maincontent .amsl-separator, 14304 #maincontent .amsl-title, 14305 #mb-social-slot .amsl-separator, 14306 #mb-social-slot .amsl-title { display: none; } 14307 #mb-social-slot .amsl-buttons { 14308 display: flex; flex-direction: column; gap: 0.75rem; width: 100%; 14309 } 14310 #mb-social-slot .amsl-button-wrapper { 14311 width: 100% !important; max-width: none !important; margin: 0 !important; 14312 } 14313 #mb-social-slot .amsl-button { 14314 position: relative; 14315 width: 100% !important; max-width: none !important; margin: 0 !important; 14316 min-height: 3.25rem; padding: 0.5rem 3rem !important; 14317 display: flex !important; align-items: center; justify-content: center; 14318 font-size: 1rem !important; font-weight: 500; 14319 background: #fff !important; color: var(--mb-text) !important; 14320 border: 1px solid var(--mb-text) !important; border-radius: 0.5rem !important; 14321 box-shadow: none !important; 14322 } 14323 #mb-social-slot .amsl-button:hover { background: var(--mb-soft) !important; } 14324 /* Textos de los botones sociales (Amasty a veces los pinta en blanco o solo muestra el icono) */ 14325 #mb-social-slot .mb-social-orig { display: none !important; } 14326 #mb-social-slot .mb-social-label { 14327 display: inline !important; color: var(--mb-text) !important; 14328 font-size: 1rem; font-weight: 500; line-height: 1.2; 14329 visibility: visible !important; opacity: 1 !important; position: static !important; 14330 width: auto !important; height: auto !important; text-indent: 0 !important; 14331 } 14332 /* Icono anclado a la izquierda, como Sklum */ 14333 #mb-social-slot .amsl-button > img, 14334 #mb-social-slot .amsl-button > svg, 14335 #mb-social-slot .amsl-button [class*="icon"] { 14336 position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); 14337 width: 22px; height: 22px; 14338 display: block !important; visibility: visible !important; opacity: 1 !important; 14339 } 14340 #mb-social-slot .amsl-button [class*="icon"] svg, 14341 #mb-social-slot .amsl-button [class*="icon"] img { width: 100%; height: 100%; display: block; } 14342 14343 /* ---------- Popup Ajax de Amasty: mismo aspecto que la página ---------- */ 14344 .amsl-popup-block .mb-register__footer { display: none; } /* ya está la pestaña "Iniciar sesión" */ 14345 .amsl-popup-block .mb-register__lead { display: none; } /* igual que el login: sin texto de entrada */ 14346 .amsl-popup-block .mb-section { border: 0 !important; padding: 0 !important; background: none !important; } 14347 .amsl-popup-block .amsl-form > .recaptcha-wrapper { display: none !important; } 14348</style> 14349 14350<div class="mb-register" x-data="mbRegisterPanel" data-open="false"> 14351 14352 <!-- Pantalla de entrada: email + login social --> 14353 <div x-show="isEmailClosed" x-transition.opacity> 14354 <p class="mb-register__lead"> 14355 Crea tu cuenta en un momento con tu email o con tu cuenta de Google. </p> 14356 14357 <div class="mb-entry"> 14358 <!-- Aquà se recoloca el bloque de Amasty Social Login --> 14359 <div id="mb-social-slot"></div> 14360 14361 <button type="button" 14362 class="btn btn-primary mb-submit" 14363 aria-controls="mb-email-panel" 14364 :aria-expanded="emailExpanded" 14365 @click="openEmail"> 14366 Continuar con email </button> 14367 14368 <p class="mb-social-note"> 14369 Al registrarte aceptas nuestra <a href="https://www.mueblesbonitos.com/privacidad/" target="_blank" rel="noopener">PolÃtica de privacidad</a> 14370 </p> 14371 </div> 14372 </div> 14373
14373<script> 14374 (function () { 14375 // Bloque .mb-register de este script (puede haber otro en el popup de Amasty) 14376 const root = document.currentScript && document.currentScript.closest('.mb-register'); 14377 if (!root) return; 14378 // Dentro del popup de Amasty: los botones sociales están en la misma pestaña (.amsl-content) 14379 const popupContent = root.closest('.amsl-popup-block') ? root.closest('.amsl-content') : null; 14380 const move = () => { 14381 const slot = root.querySelector('#mb-social-slot'); 14382 if (!slot) return; 14383 if (popupContent) { 14384 const popupButtons = Array.from(popupContent.querySelectorAll('.amsl-buttons')) 14385 .find((el) => !slot.contains(el)); 14386 if (popupButtons) slot.appendChild(popupButtons); 14387 addLabels(); 14388 return; 14389 } 14390 // Solo buscamos el bloque de Amasty dentro del contenido principal (nunca en la cabecera) 14391 const main = document.getElementById('maincontent') || document.querySelector('main') || document.body; 14392 const buttons = Array.from(main.querySelectorAll('.amsl-buttons')) 14393 .find((el) => !slot.contains(el) && !el.closest('.amsl-popup-block') && !el.closest('header, .page-header, #header')); 14394 if (buttons) { 14395 let social = buttons; 14396 const wrapper = buttons.closest('.amsl-social-login, .amsl-social-wrapper, .amsl-login-page'); 14397 // Solo usamos el contenedor si es pequeño: no contiene nuestro hueco ni la cabecera 14398 if (wrapper && main.contains(wrapper) && !wrapper.contains(slot) && 14399 !wrapper.querySelector('header, .page-header, nav, form')) { 14400 social = wrapper; 14401 } 14402 slot.appendChild(social); 14403 } 14404 addLabels(); 14405 }; 14406 const labels = { 14407 google: 'Continuar\u0020con\u0020Google', 14408 facebook: 'Continuar\u0020con\u0020Facebook', 14409 apple: 'Continuar\u0020con\u0020Apple', 14410 twitter: 'Continuar\u0020con\u0020X', 14411 linkedin: 'Continuar\u0020con\u0020LinkedIn', 14412 amazon: 'Continuar\u0020con\u0020Amazon', 14413 paypal: 'Continuar\u0020con\u0020PayPal' 14414 }; 14415 const addLabels = () => { 14416 root.querySelectorAll('#mb-social-slot .amsl-button').forEach((btn) => { 14417 if (btn.querySelector('.mb-social-label')) return; 14418 const hint = (btn.className + ' ' + (btn.getAttribute('href') || '') + ' ' + 14419 (btn.getAttribute('title') || '') + ' ' + (btn.dataset.amslType || '') + ' ' + 14420 (btn.parentElement ? btn.parentElement.className : '')).toLowerCase(); 14421 const key = Object.keys(labels).find((k) => hint.includes(k)); 14422 if (!key) return; 14423 // Ocultamos solo el texto original de Amasty, nunca el elemento que lleva el logo 14424 // (svg, img, fondo o ::before), para no perder el icono. 14425 btn.querySelectorAll('*').forEach((el) => { 14426 if (el.closest('svg') || el.tagName === 'IMG') return; 14427 if (el.querySelector('svg, img')) return; 14428 const cs = getComputedStyle(el); 14429 const before = getComputedStyle(el, '::before'); 14430 const hasIcon = (cs.backgroundImage && cs.backgroundImage !== 'none') || 14431 (cs.maskImage && cs.maskImage !== 'none') || 14432 (before.content && before.content !== 'none' && before.content !== 'normal'); 14433 const ownText = Array.from(el.childNodes) 14434 .filter((n) => n.nodeType === 3) 14435 .map((n) => n.textContent).join('').trim(); 14436 if (!ownText) return; 14437 if (hasIcon) { 14438 // El texto comparte elemento con el icono: lo ocultamos sin tocar el icono
14439 Array.from(el.childNodes).forEach((n) => { 14440 if (n.nodeType === 3 && n.textContent.trim()) { 14441 const w = document.createElement('span'); 14442 w.className = 'mb-social-orig'; 14443 n.replaceWith(w); 14444 w.appendChild(n); 14445 } 14446 }); 14447 } else { 14448 el.classList.add('mb-social-orig'); 14449 } 14450 }); 14451 // Texto suelto directamente dentro del botón 14452 Array.from(btn.childNodes).forEach((n) => { 14453 if (n.nodeType === 3 && n.textContent.trim()) { 14454 const w = document.createElement('span'); 14455 w.className = 'mb-social-orig'; 14456 n.replaceWith(w); 14457 w.appendChild(n); 14458 } 14459 }); 14460 const label = document.createElement('span'); 14461 label.className = 'mb-social-label'; 14462 label.textContent = labels[key]; 14463 btn.appendChild(label); 14464 }); 14465 }; 14466 move(); 14467 window.addEventListener('DOMContentLoaded', move); 14468 })(); 14469 </script>
14469 14470 14471 <!-- Panel desplegable: formulario de registro con email --> 14472 <div id="mb-email-panel" x-show="isEmailOpen" x-transition x-cloak> 14473 <button type="button" class="mb-back" @click="closeEmail"> 14474 <span aria-hidden="true">←</span> 14475 <span>Otras opciones de registro</span> 14476 </button> 14477 14478 14479 <form class="form create account form-create-account" 14480 action="https://www.mueblesbonitos.com/customer/account/createpost/" 14481 x-data="mbRegisterForm" 14482 id="accountcreate" 14483 @submit.prevent="submitForm" 14484 method="post" 14485 enctype="multipart/form-data" 14486 autocomplete="off" 14487 novalidate> 14488 <input name="form_key" type="hidden" value="GoQ6wnK4Gflfjncs" /> <div class="control"> 14489 <input type="hidden" 14490 value="" 14491 name="g-recaptcha-response" 14492 > 14493</div> 14494 <input type="hidden" name="success_url" value=""> 14495 <input type="hidden" name="error_url" value=""> 14496 14497 <!-- Un único bloque: Tus datos --> 14498 <fieldset class="mb-section"> 14499 <legend class="mb-section__title"> 14500 <span>Tus datos</span> 14501 </legend> 14502 14503 <div class="field field-reserved w-full field-name-firstname required"> 14504 <label class="label" for="firstname"> 14505 <span> 14506 Nombre </span> 14507 </label> 14508 <div class="control"> 14509 <input type="text" id="firstname" 14510 name="firstname" 14511 value="" 14512 required 14513 title="Nombre" 14514 class="form-input w-full required-entry" 14515 @input.debounce="onChange" 14516 required > 14517 </div> 14518 </div> 14519 <div class="field field-reserved w-full field-name-lastname required"> 14520 <label class="label" for="lastname"> 14521 <span> 14522 Apellido </span> 14523 </label> 14524 <div class="control"> 14525 <input type="text" id="lastname" 14526 name="lastname" 14527 required 14528 value="" 14529 title="Apellido" 14530 class="form-input w-full required-entry" 14531 @input.debounce="onChange" 14532 required > 14533 </div> 14534 </div> 14535 14536 14537 14538 14539 14540 <div class="field field-reserved required"> 14541 <label for="am-email-address" class="label"> 14542 <span>Email</span> 14543 </label> 14544 <div class="control"> 14545 <input type="email" 14546 name="email" 14547 id="am-email-address" 14548 autocomplete="email" 14549 inputmode="email" 14550 autocapitalize="off" 14551 spellcheck="false" 14552 required 14553 placeholder="tu@email.com" 14554 value="" 14555 title="Email" 14556 class="form-input w-full" 14557 @input.debounce="onChange"> 14558 </div> 14559 </div> 14560 14561 <div class="field field-reserved required"> 14562 <label for="password" class="label"> 14563 <span>Contraseña</span> 14564 </label> 14565 <div class="control mb-password"> 14566 <div class="sr-only" aria-live="polite"> 14567 <span x-text="pwStatus"></span> 14568 </div> 14569 <input :type="pwType" 14570 type="password" 14571 id="password" 14572 name="password" 14573 title="Contraseña" 14574 minlength="8" 14575 class="form-input w-full" 14576 required 14577 aria-describedby="password-hint" 14578 data-validate='{"password-strength": {"minCharacterSets": 3}}' 14579 @input.debounce="onChange" 14580 autocomplete="off"> 14581 <button type="button" 14582 class="mb-password__toggle" 14583 :aria-pressed="pwPressed" 14584 @click="togglePw" 14585 :aria-label="pwLabel">
14586 <span x-show="pwIsHidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 14587 <path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/> 14588 <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/> 14589</svg> 14590</span> 14591 <span x-show="pwIsVisible" x-cloak><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 14592 <path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/> 14593 <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/> 14594</svg> 14595</span> 14596 </button> 14597 </div> 14598 <p id="password-hint" class="mb-hint"> 14599 MÃnimo 8 caracteres. Combina mayúsculas, minúsculas, números o sÃmbolos. </p> 14600 <div id="password-strength-meter-container" data-role="password-strength-meter" aria-live="polite"> 14601 <div id="password-strength-meter" class="password-strength-meter"> 14602 Nivel de Seguridad de Contraseña: 14603 <span id="password-strength-meter-label" data-role="password-strength-meter-label"> 14604 Ninguna contraseña </span> 14605 </div> 14606 </div> 14607 </div> 14608 14609 <div class="field field-reserved required"> 14610 <label for="password-confirmation" class="label"> 14611 <span>Confirmar Contraseña</span> 14612 </label> 14613 <div class="control mb-password"> 14614 <div class="sr-only" aria-live="polite"> 14615 <span x-text="pwConfirmStatus"></span> 14616 </div> 14617 <input :type="pwConfirmType" 14618 type="password" 14619 name="password_confirmation" 14620 id="password-confirmation" 14621 title="Confirmar Contraseña" 14622 data-validate='{"equalTo": "password"}' 14623 @input.debounce="onChange" 14624 required 14625 class="form-input w-full" 14626 autocomplete="off"> 14627 <button type="button" 14628 class="mb-password__toggle" 14629 :aria-pressed="pwConfirmPressed" 14630 @click="togglePwConfirm" 14631 :aria-label="pwConfirmLabel"> 14632 <span x-show="pwConfirmIsHidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 14633 <path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/> 14634 <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/> 14635</svg> 14636</span> 14637 <span x-show="pwConfirmIsVisible" x-cloak><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 14638 <path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/> 14639 <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/> 14640</svg> 14641</span> 14642 </button> 14643 </div> 14644 </div> 14645 14646 14647 <!-- Consentimientos + envÃo --> 14648 <div class="mb-consents"> 14649 <div class="mb-check field choice newsletter"> 14650 <input type="checkbox" name="is_subscribed" value="1" id="is_subscribed" 14651 title="Darse de Alta para Boletín de Noticias" 14652 class="checkbox"> 14653 <label for="is_subscribed"> 14654 Quiero recibir novedades y ofertas exclusivas por email </label> 14655 </div> 14656 14657 <div class="mb-check field choice required"> 14658 <input type="checkbox" name="privacy" id="privacy" required class="checkbox"> 14659 <label for="privacy"> 14660 He leÃdo y acepto la <a href="https://www.mueblesbonitos.com/privacidad/" target="_blank" rel="noopener">PolÃtica de privacidad</a> 14661 </label> 14662 </div> 14663 14664 14665 <button type="submit" 14666 class="action submit primary btn btn-primary mb-submit" 14667 title="Crear una Cuenta" 14668 >
14669 <span>Crear una Cuenta</span> 14670 </button> 14671 14672 <div class="mt-3 text-xs text-center" style="color: var(--mb-muted)"> 14673 <p class="prose my-4 text-sm"> 14674 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 14675</p> 14676 </div> 14677 </div> 14678 </fieldset> 14679 </form> 14680 </div><!-- /#mb-email-panel --> 14681 14682 <p class="mb-register__footer"> 14683 ¿Ya tienes cuenta? <a href="https://www.mueblesbonitos.com/customer/account/login/">Inicia sesión</a> 14684 </p> 14685</div> 14686
14687<script> 14688 function mbRegisterPanel() { 14689 return { 14690 emailOpen: false, 14691 init() { 14692 this.emailOpen = this.$el.dataset.open === 'true'; 14693 }, 14694 isEmailOpen() { 14695 return this.emailOpen; 14696 }, 14697 isEmailClosed() { 14698 return !this.emailOpen; 14699 }, 14700 emailExpanded() { 14701 return this.emailOpen ? 'true' : 'false'; 14702 }, 14703 openEmail() { 14704 this.emailOpen = true; 14705 this.$nextTick(() => { 14706 const f = this.$root.querySelector('[name="firstname"]'); 14707 f && f.focus(); 14708 }); 14709 }, 14710 closeEmail() { 14711 this.emailOpen = false; 14712 window.scrollTo({ top: 0, behavior: 'smooth' }); 14713 } 14714 } 14715 } 14716 14717 function mbRegisterForm() { 14718 return Object.assign(hyva.formValidation(this.$el), mbRegisterFormMethods()); 14719 } 14720 14721 function mbRegisterFormMethods() { 14722 const labels = { 14723 show: 'Mostrar\u0020Contrase\u00F1a', 14724 hide: 'Ocultar\u0020contrase\u00F1a', 14725 pwShown: 'Se\u0020muestra\u0020la\u0020contrase\u00F1a', 14726 pwHidden: 'Contrase\u00F1a\u0020oculta', 14727 confirmShown: 'Confirm\u0020password\u0020shown', 14728 confirmHidden: 'Confirmar\u0020contrase\u00F1a\u0020oculta' 14729 }; 14730 14731 return { 14732 errors: 0, 14733 hasCaptchaToken: 0, 14734 pwVisible: false, 14735 pwConfirmVisible: false, 14736 14737 // Contraseña 14738 togglePw() { this.pwVisible = !this.pwVisible; }, 14739 pwType() { return this.pwVisible ? 'text' : 'password'; }, 14740 pwPressed() { return this.pwVisible ? 'true' : 'false'; }, 14741 pwLabel() { return this.pwVisible ? labels.hide : labels.show; }, 14742 pwStatus() { return this.pwVisible ? labels.pwShown : labels.pwHidden; }, 14743 pwIsHidden() { return !this.pwVisible; }, 14744 pwIsVisible() { return this.pwVisible; }, 14745 14746 // Confirmar contraseña 14747 togglePwConfirm() { this.pwConfirmVisible = !this.pwConfirmVisible; }, 14748 pwConfirmType() { return this.pwConfirmVisible ? 'text' : 'password'; }, 14749 pwConfirmPressed() { return this.pwConfirmVisible ? 'true' : 'false'; }, 14750 pwConfirmLabel() { return this.pwConfirmVisible ? labels.hide : labels.show; }, 14751 pwConfirmStatus() { return this.pwConfirmVisible ? labels.confirmShown : labels.confirmHidden; }, 14752 pwConfirmIsHidden() { return !this.pwConfirmVisible; }, 14753 pwConfirmIsVisible() { return this.pwConfirmVisible; }, 14754 14755 submitForm() { 14756 this.validate() 14757 .then(() => { 14758 // Do not rename $form, the variable is expected to be declared in the recaptcha output 14759 const $form = this.$root; 14760 // Exactamente un campo g-recaptcha-response dentro del formulario 14761 const tokenInputs = $form.querySelectorAll('[name="g-recaptcha-response"]'); 14762 tokenInputs.forEach((input, i) => { if (i > 0) input.remove(); }); 14763 if (!tokenInputs.length) { 14764 const input = document.createElement('input'); 14765 input.type = 'hidden'; 14766 input.name = 'g-recaptcha-response'; 14767 $form.appendChild(input); 14768 } 14769 if (!this.hasCaptchaToken) { 14770 this.errors = 1; 14771 14772 14773 const executeGreCaptcha = () => { 14774 grecaptcha.ready(() => { 14775 grecaptcha.execute( 14776 '6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3', 14777 {action: 'submit'} 14778 ).then((token) => { 14779 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 14780 14781 if (tokenElement && token && token.length > 0) { 14782 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 14783 this.errors = 0; 14784 this.hasCaptchaToken = 1; 14785 (this.submitForm || $form.submit).call(this); 14786 } else { 14787 this.errors = 1; 14788 const error = tokenElement 14789 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 14790 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 14791 if (this.setErrorMessages) { 14792 this.setErrorMessages([error]) 14793 this.displayErrorMessage = true; 14794 } else { 14795 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 14796 } 14797 } 14798 }).catch(exception => { 14799 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 14800 }); 14801 }) 14802 } 14803 14804 if (window.grecaptcha) { 14805 executeGreCaptcha(); 14806 } else { 14807 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3"; 14808 const script = document.createElement('script'); 14809 script.setAttribute('type', 'text/javascript'); 14810 script.setAttribute('src', recaptchaUrl); 14811 document.head.appendChild(script); 14812 14813 script.addEventListener("load", executeGreCaptcha, false); 14814 } 14815 } 14816 14817 if (this.errors === 0) { 14818 $form.submit(); 14819 } 14820 }) 14821 .catch((invalid) => { 14822 if (invalid.length > 0) { 14823 invalid[0].focus(); 14824 invalid[0].scrollIntoView({ behavior: 'smooth', block: 'center' }); 14825 } 14826 }); 14827 }, 14828 } 14829 } 14830 14831 const mbRegisterAddRules = () => { 14832 hyva.formValidation.addRule('telephone', (value, options) => { 14833 const phoneNumber = value.trim().replace(' ', ''); 14834 if (phoneNumber && phoneNumber.length < (options.minlength || 3)) { 14835 return 'El\u0020n\u00FAmero\u0020de\u0020tel\u00E9fono\u0020es\u0020demasiad
14835o\u0020corto.'; 14836 } 14837 return true; 14838 }); 14839 14840 const postCodeSpecs = {"AD":{"pattern_1":{"example":"AD100","pattern":"^AD\\d{3}$"}},"AM":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"AR":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"},"pattern_2":{"example":"A1234BCD","pattern":"^[a-zA-z]{1}[0-9]{4}[a-zA-z]{3}$"}},"AS":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"AT":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"AU":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"AX":{"pattern_1":{"example":"22123","pattern":"^22\\d{3}$"}},"AZ":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"},"pattern_2":{"example":"123456","pattern":"^[0-9]{6}$"}},"BA":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"BB":{"pattern_1":{"example":"BB12345","pattern":"^(BB\\d{5})?$"}},"BD":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"BE":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"BG":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"BH":{"pattern_1":{"example":"323","pattern":"^((1[0-2]|[1-9])\\d{2})?$"}},"BM":{"pattern_1":{"example":"MA 02","pattern":"^[A-Z]{2}[ ]?[A-Z0-9]{2}$"}},"BN":{"pattern_1":{"example":"AB1234","pattern":"^[a-zA-z]{2}[0-9]{4}$"}},"BR":{"pattern_1":{"example":"12345678","pattern":"^[0-9]{8}$"},"pattern_2":{"example":"12345-678","pattern":"^[0-9]{5}\\-[0-9]{3}$"}},"BY":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"CA":{"pattern_1":{"example":"A1B 2C3","pattern":"^[a-zA-z]{1}[0-9]{1}[a-zA-z]{1}\\s[0-9]{1}[a-zA-z]{1}[0-9]{1}$"},"pattern_2":{"example":"A1B2C3","pattern":"^[a-zA-z]{1}[0-9]{1}[a-zA-z]{1}[0-9]{1}[a-zA-z]{1}[0-9]{1}$"},"pattern_3":{"example":"A1B","pattern":"^[a-zA-z]{1}[0-9]{1}[a-zA-z]{1}$"}},"CC":{"pattern_1":{"example":"6799","pattern":"^6799$"}},"CH":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"CK":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"CL":{"pattern_1":{"example":"1234567","pattern":"^\\d{7}$"}},"CN":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"CR":{"pattern_1":{"example":"12345 or 123-1234","pattern":"^\\d{4,5}|\\d{3}-\\d{4}$"}},"CS":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"CU":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"CV":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"CX":{"pattern_1":{"example":"6798","pattern":"^6798$"}},"CY":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"CZ":{"pattern_1":{"example":"123 45","pattern":"^[0-9]{3}\\s[0-9]{2}$"}},"DE":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"DK":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"DO":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"DZ":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"EC":{"pattern_1":{"example":"A1234B or AB123456 or 123456","pattern":"^([A-Z]\\d{4}[A-Z]|(?:[A-Z]{2})?\\d{6})?$"}},"EE":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"EG":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"ES":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"ET":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"FI":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"FK":{"pattern_1":{"example":"FIQQ 1ZZ","pattern":"^FIQQ 1ZZ$"}},"FM":{"pattern_1":{"example":"96941","pattern":"^(9694[1-4])([ \\-]\\d{4})?$"}},"FO":{"pattern_1":{"example":"123","pattern":"^\\d{3}$"}},"FR":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"GB":{"pattern_1":{"example":"AB12 3CD","pattern":"^[a-zA-Z]{2}[0-9]{2}\\s?[0-9]{1}[a-zA-Z]{2}$"},"pattern_2":{"example":"A1B 2CD","pattern":"^[a-zA-Z]{1}[0-9]{1}[a-zA-Z]{1}\\s?[0-9]{1}[a-zA-Z]{2}$"},"pattern_3":{"example":"AB1 2CD","pattern":"^[a-zA-Z]{2}[0-9]{1}\\s?[0-9]{1}[a-zA-Z]{2}$"},"pattern_4":{"example":"AB1C 2DF","pattern":"^[a-zA-Z]{2}[0-9]{1}[a-zA-Z]{1}\\s?[0-9]{1}[a-zA-Z]{2}$"},"pattern_5":{"example":"A12 3BC","pattern":"^[a-zA-Z]{1}[0-9]{2}\\s?[0-9]{1}[a-zA-Z]{2}$"},"pattern_6":{"example":"A1 2BC","pattern":"^[a-zA-Z]{1}[0-9]{1}\\s?[0-9]{1}[a-zA-Z]{2}$"}},"GE":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"GF":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"GG":{"pattern_1":{"example":"GY10 2AB","pattern":"^[gG][yY]([1-9]|10)\\s?[0-9]{1}[a-zA-Z]{2}$"}},"GH":{"pattern_1":{"example":"GA18400","pattern":"^[A-Z][A-Z0-9]\\d{3,5}$"}},"GL":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"GN":{"pattern_1":{"example":"123","pattern":"^\\d{3}$"}},"GP":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"GR":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"GS":{"pattern_1":{"example":"SIQQ 1ZZ","pattern":"^SIQQ 1ZZ$"}},"GT":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"GU":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"GW":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"HM":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"HN":{"pattern_1":{"example":"12345","pattern":"^(?:\\d{5})?$"}},"HR":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"HT":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"HU":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"IC":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"ID":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"IL":{"pattern_1":{"example":"6687865","pattern":"^[0-9]{7}$"}},"IM":{"pattern_1":{"example":"IM1 1AD","pattern":"^IM\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$"}},"IN":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"IO":{"pattern_1":{"example":"BBND 1ZZ","pattern":"^BBND 1ZZ$"}},"IS":{"pattern_1":{"example":"123","pattern":"^[0-9]{3}$"}},"IQ":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"IT":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}}
14840,"JE":{"pattern_1":{"example":"JE2 4PJ","pattern":"^[jJ][eE][1-5]{1}\\s?[0-9]{1}[a-zA-Z]{2}$"}},"JO":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"JP":{"pattern_1":{"example":"123-4567","pattern":"^[0-9]{3}-[0-9]{4}$"},"pattern_2":{"example":"1234567","pattern":"^[0-9]{7}$"}},"KE":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"KG":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"KR":{"pattern_1":{"example":"123-456","pattern":"^[0-9]{3}-[0-9]{3}$"},"pattern_2":{"example":"12345","pattern":"^[0-9]{5}$"}},"KH":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"KW":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"KZ":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"LA":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"LB":{"pattern_1":{"example":"1234 5678","pattern":"^(\\d{4}([ ]?\\d{4})?)?$"}},"LI":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"LK":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"LT":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"LU":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"LV":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"MA":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MC":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MD":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"ME":{"pattern_1":{"example":"81101","pattern":"^8\\d{4}$"}},"MG":{"pattern_1":{"example":"123","pattern":"^[0-9]{3}$"}},"MH":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MK":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"MN":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"MP":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MS":{"pattern_1":{"example":"MSR1250","pattern":"^MSR\\s?\\d{4}$"}},"MQ":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MT":{"pattern_1":{"example":"ABC 1234","pattern":"^[a-zA-Z]{3}\\s[0-9]{4}$"},"pattern_2":{"example":"ABC 123","pattern":"^[a-zA-Z]{3}\\s[0-9]{3}$"},"pattern_3":{"example":"ABC 12","pattern":"^[a-zA-Z]{3}\\s[0-9]{2}$"}},"MU":{"pattern_1":{"example":"A1201 or 80110","pattern":"^([AR]|[0-9])\\d{4,5}$"}},"MV":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"},"pattern_2":{"example":"1234","pattern":"^[0-9]{4}$"}},"MX":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"MY":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"NC":{"pattern_1":{"example":"98800","pattern":"^988\\d{2}$"}},"NE":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"NF":{"pattern_1":{"example":"2899","pattern":"^2899$"}},"NG":{"pattern_1":{"example":"123456","pattern":"^(\\d{6})?$"}},"NI":{"pattern_1":{"example":"22500","pattern":"^\\d{5}$"}},"NL":{"pattern_1":{"example":"1234 AB\/1234AB","pattern":"^[1-9][0-9]{3}\\s?[a-zA-Z]{2}$"},"pattern_2":{"example":"1234","pattern":"^[1-9][0-9]{3}$"}},"NO":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"NP":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"NZ":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"OM":{"pattern_1":{"example":"PC 123 or 123","pattern":"^(PC )?\\d{3}$"}},"PA":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"PF":{"pattern_1":{"example":"98701","pattern":"^987\\d{2}$"}},"PG":{"pattern_1":{"example":"123","pattern":"^\\d{3}$"}},"PH":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"PK":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"PL":{"pattern_1":{"example":"12-345","pattern":"^[0-9]{2}-[0-9]{3}$"}},"PM":{"pattern_1":{"example":"97500","pattern":"^9[78]5\\d{2}$"}},"PN":{"pattern_1":{"example":"PCRN 1ZZ","pattern":"^PCRN 1ZZ$"}},"PR":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"PT":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"},"pattern_2":{"example":"1234-567","pattern":"^[0-9]{4}-[0-9]{3}$"}},"PW":{"pattern_1":{"example":"96939 or 96940","pattern":"^(?:96939|96940)$"}}
14840,"PY":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"RE":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"RO":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"RS":{"pattern_1":{"example":"123456","pattern":"^\\d{6}$"}},"RU":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"SA":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"SE":{"pattern_1":{"example":"123 45","pattern":"^[0-9]{3}\\s[0-9]{2}$"}},"SG":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"SI":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"SK":{"pattern_1":{"example":"123 45","pattern":"^[0-9]{3}\\s[0-9]{2}$"}},"SH":{"pattern_1":{"example":"ASCN 1ZZ","pattern":"^(ASCN|STHL) 1ZZ$"}},"SJ":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"SM":{"pattern_1":{"example":"47890","pattern":"^4789\\d$"}},"SN":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"SO":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"SZ":{"pattern_1":{"example":"A123","pattern":"^[a-zA-Z]{1}[0-9]{3}$"}},"TC":{"pattern_1":{"example":"TKCA 1ZZ","pattern":"^TKCA 1ZZ$"}},"TH":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"TJ":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"TM":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"TN":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"TR":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"TT":{"pattern_1":{"example":"120110","pattern":"^\\d{6}$"}},"TW":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"},"pattern_2":{"example":"123","pattern":"^[0-9]{3}$"}},"UA":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"US":{"pattern_1":{"example":"12345-6789","pattern":"^[0-9]{5}\\-[0-9]{4}$"},"pattern_2":{"example":"12345","pattern":"^[0-9]{5}$"}},"UY":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"UZ":{"pattern_1":{"example":"123456","pattern":"^[0-9]{6}$"}},"VA":{"pattern_1":{"example":"00120","pattern":"^00120$"}},"VE":{"pattern_1":{"example":"1234","pattern":"^\\d{4}$"}},"VI":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"WF":{"pattern_1":{"example":"98601","pattern":"^986\\d{2}$"}},"XK":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}},"XY":{"pattern_1":{"example":"12345","pattern":"^[0-9]{5}$"}},"YT":{"pattern_1":{"example":"97601","pattern":"^976\\d{2}$"}},"ZA":{"pattern_1":{"example":"1234","pattern":"^[0-9]{4}$"}},"ZM":{"pattern_1":{"example":"12345","pattern":"^\\d{5}$"}}}; 14841 14842 hyva.formValidation.addRule('postcode', (postCode, options, field, context) => { 14843 context.removeMessages(field, 'postcode-warning') 14844 const countryId = (context.fields['country_id'] && context.fields['country_id'].element.value), 14845 validatedPostCodeExamples = [], 14846 countryPostCodeSpecs = countryId && postCodeSpecs ? postCodeSpecs[countryId] : false; 14847 14848 if (!postCode || !countryPostCodeSpecs) return true; 14849 14850 for (const postCodeSpec of Object.values(countryPostCodeSpecs)) { 14851 if (new RegExp(postCodeSpec.pattern).test(postCode)) return true; 14852 validatedPostCodeExamples.push(postCodeSpec.example); 14853 } 14854 if (validatedPostCodeExamples.length) { 14855 context.addMessages(field, 'postcode-warning', [ 14856 'El\u0020C\u00F3digo\u0020Postal\u0020proporcionado\u0020parece\u0020no\u0020ser\u0020v\u00E1lido.', 14857 '\u0020Ejemplo\u003A\u0020' + validatedPostCodeExamples.join('; ') + '. ', 14858 'Si\u0020cree\u0020que\u0020es\u0020el\u0020correcto,\u0020puede\u0020ignorar\u0020este\u0020aviso.' 14859 ]); 14860 } 14861 return true; 14862 }); 14863 }; 14864 document.readyState === 'loading' 14865 ? window.addEventListener('DOMContentLoaded', mbRegisterAddRules) 14866 : mbRegisterAddRules(); 14867 14868 ;(() => { 14869 const register = () => { 14870 Alpine.data('mbRegisterPanel', mbRegisterPanel); 14871 Alpine.data('mbRegisterForm', mbRegisterForm); 14872 }; 14873 (document.readyState === 'loading' || !window.Alpine) 14874 ? window.addEventListener('alpine:init', register, {once: true}) 14875 : register(); 14876 })(); 14877</script>
14877 14878 14879 <div class="recaptcha-create-wrapper recaptcha-wrapper w-full"> 14880 <div class="control"> 14881 <input type="hidden" 14882 value="" 14883 name="g-recaptcha-response" 14884 > 14885</div> 14886 </div> 14887 <div class="recaptcha-create-wrapper recaptcha-wrapper w-full"> 14888 <p class="prose my-4 text-sm"> 14889 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 14890</p> 14891 </div> 14892 </div> 14893 </template> 14894 <span class="amsl-separator bg-gray-500 hidden text-secondary text-sm font-bold relative w-0.5"> 14895 <span 14896 class="amsl-icon absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 14897 border border-gray-500 rounded-full bg-white overflow-hidden w-8 h-8 14898 min-w-8 flex items-center justify-center pb-[3px]" 14899 >o bien</span> 14900 </span> 14901 <div class="amsl-social-wrapper" 14902 > 14903 <div class="amsl-title text-base font-medium text-gray-70 mb-2"> 14904 Inicia sesión con tus redes sociales </div> 14905 <div class="amsl-title text-base font-medium text-gray-70 mb-2 -short"> 14906 Iniciar Sesión con </div> 14907 <div class="amsl-social-login "> 14908 <template x-if="hasSocialError"> 14909 <p class="amsl-error -social message error mb-4" x-text="socialErrorMessage"></p> 14910 </template> 14911 <div class="amsl-buttons flex flex-wrap justify-center gap-7" 14912 :class="socialButtonsClasses" 14913 > 14914 <div 14915 class="amsl-button-wrapper 14916 " 14917 > 14918 <form method="POST" 14919 action="https://www.mueblesbonitos.com/amsociallogin/social/login/?type=google" 14920 class="amsl-button-form" 14921 aria-label="Sign in with Google" 14922 x-on:submit="socialLoginClick" 14923 > 14924 <input name="form_key" type="hidden" value="lYvGLDMwoyHIBAad" /> <button 14925 type="submit" 14926 class="amsl-button rounded-full overflow-hidden bg-white 14927 shadow-md hover:shadow-lg transition-amsl-social-button 14928 block w-16 h-16 p-4 -google " 14929 title="Sign in with Google" 14930 > 14931 <span 14932 class="amsl-social-icon pointer-events-none 14933 " role="img" 14934 aria-label="Sign in with Google" 14935 > 14936 <svg xmlns="http://www.w3.org/2000/svg" xmlns:v="https://vecta.io/nano" viewBox="0 0 31 33" fill="none" width="24" height="24" role="img"><path d="M1.125 10.662c-.726 1.85-1.1 3.841-1.023 5.869-.061 3.005.825 5.947 2.383 8.465l4.781-3.654c-.261-.501-.478-1.03-.643-1.586-.625-1.678-.712-3.469-.371-5.174l-5.127-3.92z" fill="#fbbc05"/><path d="M15.832.502l-.775.045c-6.14.075-11.7 4.435-13.93 10.115l5.125 3.918c.711-3.552 3.289-6.733 6.809-7.75 3.23-1.155 6.557.145 9.322 1.85 1.399-1.331 2.71-2.751 3.998-4.189C23.437 1.989 19.706.395 15.832.502zm.016 13.736v.041l.047-.041c-.016 0-.031 0-.047 0z" fill="#ea4335"/><path d="M23.387 14.219c-2.298-.001-4.595.006-6.891.01l-.648.496.008 4.953 9.035.107c-.76 2.645-2.493 5.106-5.121 6.061-4.56 2.039-10.247-.148-12.514-4.533l-4.777 3.662c1.906 3.086 4.822 5.537 8.256 6.682 5.873 2.003 13.093.505 17.002-4.602 2.853-3.577 3.502-8.348 3.193-12.805l-7.543-.031z" fill="#34a853"/><path d="M23.385 14.219c-2.514-.001-5.026.006-7.537.01l.008 5.449 9.035.107c-.69 2.401-2.185 4.647-4.42 5.756l4.959 3.84c.852-.669 1.63-1.442 2.307-2.326 2.853-3.577 3.502-8.348 3.193-12.805l-7.545-.031z" fill="#4285f4"/><title>google</title></svg> 14937 </span> 14938 </button> 14939 </form> 14940 </div> 14941 <div 14942 class="amsl-button-wrapper 14943 " 14944 > 14945 <form method="POST" 14946 action="https://www.mueblesbonitos.com/amsociallogin/social/login/?type=facebook" 14947 class="amsl-button-form" 14948 aria-label="Sign in with Facebook" 14949 x-on:submit="socialLoginClick" 14950 > 14951 <input name="form_key" type="hidden" value="lYvGLDMwoyHIBAad" /> <button 14952 type="submit" 14953 class="amsl-button rounded-full overflow-hidden bg-white 14954 shadow-md hover:shadow-lg transition-amsl-social-button 14955 block w-16 h-16 p-4 -facebook " 14956 title="Sign in with Facebook" 14957 >
14958 <span 14959 class="amsl-social-icon pointer-events-none 14960 " role="img" 14961 aria-label="Sign in with Facebook" 14962 > 14963 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 38" fill="none" width="24" height="24" role="img"><path d="M12.37 37.28V20.668h5.576l.835-6.474H12.37V10.06c0-1.875.52-3.152 3.209-3.152l3.428-.002v-5.79c-.593-.08-2.628-.256-4.996-.256-4.943 0-8.327 3.017-8.327 8.558v4.775H.094v6.475h5.59V37.28h6.686z" fill="currentColor"/><title>facebook</title></svg> 14964 </span> 14965 </button> 14966 </form> 14967 </div> 14968 </div> 14969 </div> 14970 </div> 14971 14972
14972<script> 14973 function AmSocialLogin() { 14974 return { 14975 socialErrorMessage: '', 14976 isPopupEnabled: '1', 14977 14978 initializeSocialLogin() { 14979 this.initContentUpdaters(); 14980 }, 14981 14982 socialLoginClick(event) { 14983 const form = event.currentTarget; 14984 14985 if (this.isPopupEnabled) { 14986 form.target = '_blank'; 14987 form.action = form.action + '&isAjax=true'; 14988 } 14989 14990 const channel = new BroadcastChannel('amSocialLoginData'); 14991 channel.addEventListener('message', this.onMessageEvent.bind(this)); 14992 14993 event.stopPropagation(); 14994 event.preventDefault(); 14995 form.submit(); 14996 14997 return false; 14998 }, 14999 15000 onSocialResponse(data) { 15001 const isSuccessfulResult = data.result === 1; 15002 15003 if (isSuccessfulResult) { 15004 window.dispatchEvent( 15005 new CustomEvent( 15006 'amsl-popup-show-notification', 15007 { 15008 detail: data.messages 15009 } 15010 ) 15011 ); 15012 this.processRedirect(); 15013 } else { 15014 const redirectData = data?.redirect_data; 15015 15016 this.socialErrorMessage = data.messages.pop(); 15017 setTimeout(() => { 15018 this.socialErrorMessage = ''; 15019 }, 5000); 15020 15021 if (this.shouldCustomUrlRedirectWithError(redirectData)) { 15022 return this.processRedirect(redirectData?.url); 15023 } 15024 15025 if (redirectData?.redirectWithError) { 15026 this.processRedirect(); 15027 } 15028 } 15029 }, 15030 15031 // Helper CSP: x-if="hasSocialError" 15032 hasSocialError() { 15033 return !!this.socialErrorMessage; 15034 }, 15035 15036 shouldCustomUrlRedirectWithError(redirectData) { 15037 return ( 15038 redirectData && 15039 redirectData.redirect && 15040 redirectData.redirectWithError && 15041 redirectData.url 15042 ); 15043 }, 15044 15045 onMessageEvent(event) { 15046 if (event.origin !== window.location.origin) { 15047 return; 15048 } 15049 15050 const data = JSON.parse(event.data); 15051 if (data['redirect_data']) { 15052 this.onSocialResponse(data); 15053 } 15054 }, 15055 15056 ...AmAuthPopupRedirect(), 15057 ...AmAuthPopupReloadContent() 15058 } 15059 } 15060 15061 ;(() => { 15062 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 15063 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 15064 const register = () => Alpine.data('AmSocialLogin', AmSocialLogin); 15065 (document.readyState === 'loading' || !window.Alpine) 15066 ? window.addEventListener('alpine:init', register, {once: true}) 15067 : register(); 15068 })(); 15069</script>
15069 15070 </div> 15071 </div> 15072 </div> 15073 15074 <div class="amsl-tabs-wrapper -forgot" 15075 x-show="isForgotTab" 15076 title="Forgot Your Password Form" 15077 x-cloak 15078 > 15079 <ul class="amsl-tablist flex space-x-4" role="tablist"> 15080 <li class="amsl-title" 15081 id="tab-amsl-forgot" 15082 role="tab" aria-controls="amsl-forgot-content" 15083 > 15084 <span class="amsl-link block p-4 text-lg border-b -active border-primary text-blue-800 hover:bg-transparent" 15085 @click.prevent 15086 > 15087 ¿Olvidó su Contraseña? </span> 15088 </li> 15089 </ul> 15090 <div id="amsl-forgot-content" role="tabpanel" aria-labelledby="tab-amsl-forgot"> 15091 <template x-if="hasForgotMessages"> 15092 <div class="mt-4"> 15093 <template x-for="message in forgotMessages" :key="message"> 15094 <div class="message error"> 15095 <span x-html="message"></span> 15096 </div> 15097 </template> 15098 </div> 15099 </template> 15100 <div class="amsl-content amsl-forgot-content mt-6"> 15101 <template x-if="isNotLogged"> 15102 <div class="amsl-form"> 15103 <div class="mb-12"> 15104 <div class="w-full md:w-1/2 card my-8"> 15105 <form action="https://www.mueblesbonitos.com/customer/account/forgotpasswordpost/" 15106 method="post" 15107 id="user_forgotpassword" 15108 x-data="initPasswordForm" 15109 @submit.prevent="submitForm"> 15110 <input name="form_key" type="hidden" value="GoQ6wnK4Gflfjncs" /> <input type="hidden" name="formId" value="user_forgotpassword"> 15111 <div class="control"> 15112 <input type="hidden" 15113 value="" 15114 name="g-recaptcha-response" 15115 > 15116</div> 15117 <fieldset class="fieldset"> 15118 <fieldset class="mb-8"> 15119 Por favor, introduce tu dirección de correo electrónico a continuación para recibir un enlace de restablecimiento de contraseña. </fieldset> 15120 <div class="field email required"> 15121 <label for="email_address" class="label"> 15122 <span>Email</span> 15123 </label> 15124 <div class="control"> 15125 <input type="email" 15126 name="email" 15127 alt="email" 15128 id="email_address" 15129 class="form-input w-full" 15130 autocomplete="off" 15131 required 15132 value=""> 15133 </div> 15134 </div> 15135 <p class="prose my-4 text-sm"> 15136 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 15137</p> 15138 </fieldset> 15139 <div class="actions-toolbar"> 15140 <div class="primary"> 15141 <button type="submit" class="action submit primary disabled:opacity-75" 15142 > 15143 <span>Restablecer mi contraseña</span> 15144 </button> 15145 </div> 15146 <div class="secondary"> 15147 <a class="action back" 15148 href="https://www.mueblesbonitos.com/customer/account/login/referer/aHR0cHM6Ly93d3cubXVlYmxlc2Jvbml0b3MuY29tL3NhbG9u/"><span>Volver</span></a> 15149 </div> 15150 </div> 15151 </form> 15152
15152<script> 15153 function initPasswordForm() { 15154 return { 15155 errors: 0, 15156 hasCaptchaToken: 0, 15157 submitForm() { 15158 // Do not rename $form, the variable is expected to be declared in the recaptcha output 15159 const $form = this.$root; 15160 // Exactamente un campo g-recaptcha-response dentro del formulario 15161 const tokenInputs = $form.querySelectorAll('[name="g-recaptcha-response"]'); 15162 tokenInputs.forEach((input, i) => { if (i > 0) input.remove(); }); 15163 if (!tokenInputs.length) { 15164 const input = document.createElement('input'); 15165 input.type = 'hidden'; 15166 input.name = 'g-recaptcha-response'; 15167 $form.appendChild(input); 15168 } 15169 if (!this.hasCaptchaToken) { 15170 this.errors = 1; 15171 15172 15173 const executeGreCaptcha = () => { 15174 grecaptcha.ready(() => { 15175 grecaptcha.execute( 15176 '6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3', 15177 {action: 'submit'} 15178 ).then((token) => { 15179 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 15180 15181 if (tokenElement && token && token.length > 0) { 15182 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 15183 this.errors = 0; 15184 this.hasCaptchaToken = 1; 15185 (this.submitForm || $form.submit).call(this); 15186 } else { 15187 this.errors = 1; 15188 const error = tokenElement 15189 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 15190 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 15191 if (this.setErrorMessages) { 15192 this.setErrorMessages([error]) 15193 this.displayErrorMessage = true; 15194 } else { 15195 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 15196 } 15197 } 15198 }).catch(exception => { 15199 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 15200 }); 15201 }) 15202 } 15203 15204 if (window.grecaptcha) { 15205 executeGreCaptcha(); 15206 } else { 15207 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6LdhDJUsAAAAAFXlSOEYil6koVeIFlWUTvMii4H3"; 15208 const script = document.createElement('script'); 15209 script.setAttribute('type', 'text/javascript'); 15210 script.setAttribute('src', recaptchaUrl); 15211 document.head.appendChild(script); 15212 15213 script.addEventListener("load", executeGreCaptcha, false); 15214 } 15215 } 15216 15217 if (this.errors === 0) { 15218 $form.submit(); 15219 } 15220 } 15221 } 15222 } 15223 15224 ;(() => { 15225 // Durante la carga de la página: esperar a alpine:init (todos los scripts ya definidos). 15226 // Si el script llega tarde (p.ej. dentro de un <template x-if>), registrar directamente. 15227 const register = () => Alpine.data('initPasswordForm', initPasswordForm); 15228 (document.readyState === 'loading' || !window.Alpine) 15229 ? window.addEventListener('alpine:init', register, {once: true}) 15230 : register(); 15231 })(); 15232 </script>
15232 15233 </div> 15234</div> 15235 <div class="recaptcha-forgot-wrapper recaptcha-wrapper w-full"> 15236 <div class="control"> 15237 <input type="hidden" 15238 value="" 15239 name="g-recaptcha-response" 15240 > 15241</div> 15242 </div> 15243 <div class="recaptcha-forgot-wrapper recaptcha-wrapper w-full"> 15244 <p class="prose my-4 text-sm"> 15245 <em>Este formulario está protegido por reCAPTCHA: se aplican la <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">PolÃtica de privacidad</a> y las <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Condiciones del servicio</a> <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">de Google</a>.</em> 15246</p> 15247 </div> 15248 </div> 15249 </template> 15250 </div> 15251 </div> 15252 </div> 15253 </div> 15254 </div> 15255 </div> 15256 </div> 15257 </div> 15258 <div x-data="AmAuthPopupNotification" 15259 x-init="initialize" 15260 x-on:amsl-popup-show-notification.window="onShowNotification" 15261 > 15262 <div x-cloak data-dialog-ref-name="amsl-popup-notification" 15263 x-bind="overlay" 15264 class="fixed inset-0 bg-black/50 z-50"> 15265 <div class="fixed flex justify-center items-center text-left z-40 amsl-popup-notification text-green-600 px-2 min-w-[300px] inset-0"> 15266 <div x-ref="amsl-popup-notification" role="dialog" aria-modal="true" 15267 class="inline-block bg-white shadow-xl rounded-lg p-10 max-h-screen overflow-auto overscroll-y-contain"> 15268 <div class="relative"> 15269 <button 15270 type="button" 15271 class="amsl-close absolute left-full bottom-full transform translate-x-2 15272 -translate-y-2 text-gray-400 hover:text-blue-800" 15273 x-on:click="closeNotification" 15274 title="Cerrar" 15275 aria-label="Cerrar" 15276 role="button" 15277 > 15278 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" role="img"> 15279 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 15280<title>x</title></svg> 15281 </button> 15282 <template x-if="hasNotification"> 15283 <div x-html="notification"></div> 15284 </template> 15285</div> 15286 </div> 15287 </div> 15288 </div> 15289 </div> 15290</div></body> 15291</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.