{"id":635,"date":"2026-04-30T08:18:38","date_gmt":"2026-04-30T06:18:38","guid":{"rendered":"https:\/\/tipitapa.nubedev.es\/restaurant-cuisine\/"},"modified":"2026-07-07T11:30:03","modified_gmt":"2026-07-07T09:30:03","slug":"restaurant-cuisine","status":"publish","type":"page","link":"https:\/\/www.restaurantetipitapa.com\/en\/restaurant-cuisine\/","title":{"rendered":"Restaurant Cuisine"},"content":{"rendered":"<section class=\"w-full bg-black flex justify-center items-center relative h-[50vh]\">\n            <div class=\"absolute z-10 w-full bg-white bg-contain bg-no-repeat bg-center opacity-55 sm:hidden h-[50vh]\" style=\"background-image: url(https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Carne-a-la-Barbacoa2.webp);\"><\/div>\n    \n            <div class=\"absolute z-10 w-full bg-cover bg-no-repeat opacity-55 hidden sm:block h-[50vh]\" style=\"background-image: url(https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/06\/HOMETIPITAPA.webp);\"><\/div>\n    \n\n   \n        <div class=\"absolute text-background flex flex-col justify-center items-center text-center gap-5 z-20\">\n            \n                                    <h1 class=\"uppercase text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-warble px-5\">Restaurant Cuisine<\/h1>\n                        <div class=\" sm:text-base text-sm px-5\"><\/div>\n                        \n        <\/div>\n\n \n\n            <div class=\"absolute bottom-10 mx-auto lg:right-32 w-24 sm:w-32 h-24 sm:h-32 bg-cover bg-no-repeat z-30\"\n            style=\"background-image: url(https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/04\/Logo_Dry.svg)\"><\/div>\n    \n<\/section>\n\n\n<section\n    class=\"bg-secondary w-full h-auto py-16 \">\n    <div class=\"container mx-auto flex flex-col justify-center items-center gap-8  sm:gap-6 text-center px-5 sm:px-0 w-full sm:w-3\/4 lg:w-1\/2\">\n                    <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/04\/TPTP_Logo_Imago_Mini_Full-Color_1-11.svg\" class=\"w-full h-20 sm:h-24 lg:h-32 transform-all ease-in-out duration-300\" alt=\"logo\">\n                            <div class=\"font-thin text-sm sm:text-base\"><p>SPECIALTY IN PREMIUM DRY-AGED MEATS AND GOURMET TAPAS<\/p>\n<\/div>\n                            <div class=\"titmixto text-primary text-3xl sm:text-4xl lg:text-5xl 2xl:text-6xl font-warble\"><p><strong>TIPI TAPA<\/strong> RESTAURANT <\/p>\n<\/div>\n                            <div class=\" font-thin text-sm sm:text-base\"><p>It was opened in 1999 with the idea of offering a different proposal: combining the concept of traditional Spanish tapas with a strong focus on high-quality meats. From the beginning, it positioned itself as a place where the product is the protagonist. Over the years, the restaurant has evolved by incorporating <strong>selected meats <\/strong>(beef, cow and ox), many of them with in-house ageing in specialised maturation chambers.<\/p>\n<p>&nbsp;<\/p>\n<\/div>\n            <\/div>\n<\/section>\n\n\n\n<section class=\"w-full h-full py-10 sm:py-12 lg:py-14 my-4 overflow-hidden flex flex-col relative z-20\">\n \n            <div class=\"font-thin md:translate-y-4 lg:translate-y-6 md:translate-x-[12%] text-3xl lg:text-4xl xl:text-5xl 2xl:text-6xl titmixto text-primary font-warble text-center md:text-start z-30 w-full px-4\"> \n            <p>OUR <\/p>\n<p><strong>TIPITAPA MENU<\/strong><\/p>\n \n        <\/div>\n    \n            <img decoding=\"async\" class=\"absolute left-0 top-0 w-[100px] sm:w-[150px] xl:w-[200px] 2xl:w-[220px] object-contain\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/04\/Logo-Silueta.svg\" alt=\"\">\n     \n  <div class=\"transform-all ease-in-out duration-300 relative h-full w-full md:w-[75%] ml-auto mt-4 lg:mt-0 z-0\">\n \n    <div class=\"swiper-next absolute top-1\/2 right-0 -translate-y-1\/2 z-30 h-full flex items-center justify-end pr-1 sm:pr-2 lg:pr-3 cursor-pointer group bg-gradient-to-l from-white via-white\/80 to-transparent\">\n        <svg class=\"w-8 sm:w-6 lg:w-7 xl:w-9 h-auto transform transition-all group-hover:scale-110\" viewBox=\"0 0 48 36\" fill=\"none\">\n            <path d=\"M32.8684 0C32.3688 5.42453 34.4387 10.4922 39.1494 13.3472C41.9331 15.0245 44.7881 15.3457 48 15.2387V20.5918H43.7532C42.7182 20.5918 40.1487 21.7338 39.2208 22.3048C34.4743 25.1598 32.3688 30.2632 32.8684 35.7234H27.7294C27.7294 35.7234 27.5509 35.545 27.5509 35.4022C27.4439 34.7955 27.5152 33.0825 27.5509 32.4045C27.8364 27.8721 29.7636 23.9108 32.7613 20.5918H0V15.2387H32.8684C29.7993 11.9197 27.8007 7.88699 27.5152 3.31896C27.4796 2.6052 27.4082 0.927881 27.5152 0.32119C27.5152 0.178439 27.5866 0.0713755 27.6937 0H32.8327L32.8684 0Z\" fill=\"#309343\" \/>\n        <\/svg>\n    <\/div>\n\n    <div class=\"swiper carnesSwiper w-full h-full\">\n        <div class=\"swiper-wrapper flex items-end h-full\">\n                                                <div class=\"swiper-slide !w-auto h-full flex justify-center px-2 sm:px-3\">\n                        <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Chuleton-1-png.png\"\n                            class=\"block w-full max-h-[220px] sm:max-h-[300px] lg:max-h-[400px] xl:max-h-[480px] 2xl:max-h-[550px] max-w-[85vw] sm:max-w-[320px] lg:max-w-[450px] xl:max-w-[550px] object-contain align-bottom aspect-[3\/4]\" \n                            alt=\"Carne\">\n                    <\/div>\n                                    <div class=\"swiper-slide !w-auto h-full flex justify-center px-2 sm:px-3\">\n                        <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/chuleton-2-png.png\"\n                            class=\"block w-full max-h-[220px] sm:max-h-[300px] lg:max-h-[400px] xl:max-h-[480px] 2xl:max-h-[550px] max-w-[85vw] sm:max-w-[320px] lg:max-w-[450px] xl:max-w-[550px] object-contain align-bottom aspect-[3\/4]\" \n                            alt=\"Carne\">\n                    <\/div>\n                                    <div class=\"swiper-slide !w-auto h-full flex justify-center px-2 sm:px-3\">\n                        <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Solomillo-png.png\"\n                            class=\"block w-full max-h-[220px] sm:max-h-[300px] lg:max-h-[400px] xl:max-h-[480px] 2xl:max-h-[550px] max-w-[85vw] sm:max-w-[320px] lg:max-w-[450px] xl:max-w-[550px] object-contain align-bottom aspect-[3\/4]\" \n                            alt=\"Carne\">\n                    <\/div>\n                                    <div class=\"swiper-slide !w-auto h-full flex justify-center px-2 sm:px-3\">\n                        <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Solomillo1-png.png\"\n                            class=\"block w-full max-h-[220px] sm:max-h-[300px] lg:max-h-[400px] xl:max-h-[480px] 2xl:max-h-[550px] max-w-[85vw] sm:max-w-[320px] lg:max-w-[450px] xl:max-w-[550px] object-contain align-bottom aspect-[3\/4]\" \n                            alt=\"Carne\">\n                    <\/div>\n                                    <\/div>\n    <\/div>\n\n            <img decoding=\"async\" class=\"absolute bottom-0 left-0 md:-left-20   size-24 sm:size-32 lg:size-28 xl:size-36 z-30 object-contain\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/04\/Logo_Dry.svg\" alt=\"\">\n      <\/div>\n \n\n \n    <div class=\"w-full px-5 sm:px-0 w-full md:w-[75%] flex flex-col justify-center items-start gap-5 ml-auto mt-10\">\n        <div class=\"px-0 sm:px-5 w-full flex flex-col lg:flex-row justify-start items-center gap-6 sm:gap-4 lg:gap-16 xl:gap-28 2xl:gap-44 text-center sm:text-start\">\n                            <div class=\"text-sm sm:text-base font-semplecita\"> <p>A menu that mixes tradition with modern touches. A carefully designed atmosphere that combines rustic and cosy elements.<\/p>\n <\/div>\n            \n                            <a class=\"uppercase text-white text-center px-4 py-2 text-sm sm:text-base 2xl:text-lg bg-primary border border-primary hover:text-primary hover:bg-transparent transition-all duration-300\" href=\"https:\/\/www.covermanager.com\/reservation\/module_restaurant\/restaurante-tipi-tapa\/english\" target=\"_blank\" rel=\"noopener\"> \n                    Book Table \n                <\/a>\n                    <\/div>\n        <hr class=\"h-[1px] w-full md:w-[98%] bg-foreground\/20 mt-4\">\n    <\/div>\n\n<\/section>\n\n\n<section\n    class=\"overflow-hidden w-full mb-16 min-h-[780px] sm:min-h-[900px] xl:min-h-[900px]  relative flex-col sm:flex  justify-center items-center text-center aparicion  py-8 \">\n\n            <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Flamenca_022.png\" alt=\"\"\n            class=\"absolute top-5 xl:top-60 2xl:top-32  hidden lg:block left-3 lg:left-32 w-44 sm:w-64 lg:w-72 xl:w-80 2xl:w-[400px] reveal\">\n                <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Carne-a-la-Barbacoa2.webp\" alt=\"\"\n            class=\"absolute top-5 sm:top-32 xl:top-60 2xl:top-32 -right-3   hidden sm:block w-44 sm:w-64  right-0 sm:right-6 2xl:right-32 w-[150px] md:w-[350px] lg:w-[400px] 2xl:w-[500px] reveal\">\n    \n\n\n    <div class=\"hidden\">\n\n                    <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Flamenca_022.png\" alt=\"\"\n                class=\"w-1\/2\">\n                            <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Carne-a-la-Barbacoa2.webp\" alt=\"\"\n                class=\"hidden \">\n            <\/div>\n\n    <div class=\"flex flex-col h-full justify-center items-center gap-3 px-6 w-full sm:w-1\/2 xl:w-[45%]\">\n        \n\n\t\t\t\t<img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/Flamenca2.png\" alt=\"\" class=\"w-40 lg:w-64 xl:w-80 h-auto reveal\">\n\t\t      \n                    <div class=\"titmixto font-thin titmix2 text-primary  titmixto text-primary text-3xl sm:text-4xl lg:text-5xl 2xl:text-6xl reveal font-warble \"><p><strong>IDENTITY <\/strong><br \/>\n <br \/>AND EXPERIENCE<\/p>\n<\/div>\n                <div class=\" w-fit flex flex-col justify-center items-center gap-2 reveal\">\n                        <hr class=\"w-full h-[2px] bg-tertiary px-10 reveal\">\n                            <div class=\"text-sm sm:text-base xl:font-thin reveal\"><p>One of the elements that has defined its identity is the complete experience it offers:<\/p>\n<p>&nbsp;<\/p>\n<p>High-level <strong>gastronomy<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p><strong>Live flamenco shows <\/strong>several days a week (Tuesday, Thursday, Friday and Saturday), with professional artists<\/p>\n<p>&nbsp;<\/p>\n<p>An environment designed for <strong>both tourists and local guests<\/strong><\/p>\n<\/div>\n            \n        <\/div>\n\n            <\/div>\n\n\n            <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/morcilla-png-2.png\" alt=\"\"\n            class=\"sm:block absolute hidden sm:bottom-10 left-3 sm:left-5 -rotate-3  w-44 sm:w-64 lg:w-72 xl:w-80 2xl:w-96 reveal\">\n                <img decoding=\"async\" src=\"https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/05\/pareja2.png\" alt=\"\"\n            class=\"block absolute bottom-6 left-1\/2 -translate-x-1\/2 sm:left-auto sm:-right-3 sm:translate-x-0 w-44 sm:w-64 lg:w-72 xl:w-80 2xl:w-[450px] reveal\">\n    <\/section>\n\n<section class=\"w-full h-full flex flex-col justify-start items-center gap-10 pb-20 bg-secondary\">\n\n            <div class=\"w-full h-[350px] bg-center bg-cover bg-no-repeat md:bg-fixed\"\n            style=\"background-image: url(https:\/\/www.restaurantetipitapa.com\/wp-content\/uploads\/2026\/06\/HOME-TIPITAPA.webp);\">\n        <\/div>\n    \n    <div class=\"w-full px-14 lg:px-20  flex flex-col justify-center items-center gap-5 text-base sm:text-lg text-center font-semplecita text-primary \">\n\n                    <div class=\"titmixto  font-bold\"><p>Over time,<strong> Tipi Tapa<\/strong> has become a benchmark in the area, especially recognised for:<\/p>\n<\/div>\n        \n        <hr class=\"h-[2px] w-2\/4  bg-tertiary\">\n\n        <div>\n            \n                            <div><p>Its specialisation in meats, its consistent quality, and its ability to create an authentic experience<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Today it remains a family-run business with a strong connection to its local clientele and great appeal for international visitors<\/strong><\/p>\n<\/div>\n                    <\/div>\n\n    <\/div>\n<\/section>\n\n\n<section class=\"w-full h-full\">\n            <div class=\"iframe-container\">\n                    <script type=\"text\/javascript\" src=\"https:\/\/www.covermanager.com\/js\/iframeResizer\/iframeResizer.min.js\"><\/script>\r\n        <iframe loading=\"lazy\" id=\"restaurante-tipi-tapa\" \r\n                title=\"Reservas\"\r\n                src=\"https:\/\/www.covermanager.com\/reservation\/module_restaurant\/restaurante-tipi-tapa\/english\"\r\n                allow=\"payment\" \r\n                frameborder=\"0\" \r\n                height=\"550\" \r\n                width=\"100%\" \r\n                onload=\"iFrameResize();\"><\/iframe>\n        <\/div>\n    <\/section>\n\n    <script>\r\n        (function () {\r\n            'use strict';\r\n\r\n            const CM_CONFIG = {\"debug\":true,\"enableN8n\":false,\"n8nUrl\":\"\",\"authToken\":\"\",\"restaurant\":\"tipitapa\",\"unit\":\"TIPITAPA\",\"type\":\"schedule\",\"event\":\"NS - Reserva Tipitapa\",\"allowedOrigins\":[\"https:\/\/www.covermanager.com\",\"https:\/\/module.covermanager.com\"]};\r\n            const DEBUG = !!CM_CONFIG.debug;\r\n            const ENABLE_N8N = !!CM_CONFIG.enableN8n;\r\n            const N8N_URL = CM_CONFIG.n8nUrl || '';\r\n            const AUTH_TOKEN = CM_CONFIG.authToken || '';\r\n            const COOKIE_MAX_AGE = 7776000; \/\/ 90 d\u00edas.\r\n            const AD_PARAMS = ['gclid', 'gbraid', 'wbraid', 'fbclid'];\r\n            const UTM_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];\r\n\r\n            const log = (title, data, type = 'info') => {\r\n                if (!DEBUG || typeof console === 'undefined') return;\r\n                const colors = { info: '#2271b1', success: '#46b450', error: '#dc3232', warn: '#ffb900' };\r\n                const color = colors[type] || colors.info;\r\n                console.groupCollapsed(`%c[CM Tracker] ${title}`, `color:white;background:${color};padding:2px 5px;border-radius:3px;`);\r\n                console.log(data);\r\n                console.groupEnd();\r\n            };\r\n\r\n            const safeString = (value) => String(value ?? '').trim();\r\n\r\n            const getCookie = (name) => {\r\n                try {\r\n                    const value = `; ${document.cookie || ''}`;\r\n                    const parts = value.split(`; ${name}=`);\r\n                    if (parts.length === 2) {\r\n                        return decodeURIComponent(parts.pop().split(';').shift() || '');\r\n                    }\r\n                } catch (err) {\r\n                    log('Error leyendo cookie', { name, error: String(err && err.message ? err.message : err) }, 'warn');\r\n                }\r\n                return '';\r\n            };\r\n\r\n            const setCookie = (name, value, maxAge = COOKIE_MAX_AGE) => {\r\n                const cleanValue = safeString(value);\r\n                if (!cleanValue) return;\r\n\r\n                const secure = window.location.protocol === 'https:' ? '; Secure' : '';\r\n                document.cookie = `${name}=${encodeURIComponent(cleanValue)}; path=\/; max-age=${maxAge}; SameSite=Lax${secure}`;\r\n            };\r\n\r\n            const parseCookieYesCookie = () => {\r\n                const rawCookie = getCookie('cookieyes-consent');\r\n                if (!rawCookie) return null;\r\n\r\n                const decoded = decodeURIComponent(rawCookie).toLowerCase();\r\n                return {\r\n                    advertisement: decoded.includes('advertisement:yes') || decoded.includes('advertisement=yes') || decoded.includes('advertisement:true'),\r\n                    analytics: decoded.includes('analytics:yes') || decoded.includes('analytics=yes') || decoded.includes('analytics:true')\r\n                };\r\n            };\r\n\r\n            const normalizeConsentStatus = (status) => {\r\n                const adGranted = status && (\r\n                    status.advertisement === 'granted' ||\r\n                    status.advertisement === true ||\r\n                    status.advertisement === 'yes' ||\r\n                    status.marketing === 'granted' ||\r\n                    status.marketing === true ||\r\n                    status.marketing === 'yes'\r\n                );\r\n\r\n                const analyticsGranted = status && (\r\n                    status.analytics === 'granted' ||\r\n                    status.analytics === true ||\r\n                    status.analytics === 'yes'\r\n                );\r\n\r\n                return {\r\n                    ad_user_data: adGranted ? 'granted' : 'denied',\r\n                    ad_personalization: adGranted ? 'granted' : 'denied',\r\n                    analytics_storage: analyticsGranted ? 'granted' : 'denied',\r\n                    ad_storage: adGranted ? 'granted' : 'denied',\r\n\r\n                    \/\/ Se\u00f1al separada para datos propios de la reserva: email\/tel\u00e9fono\/nombre.\r\n                    \/\/ No habilita cookies ni click IDs.\r\n                    first_party_user_data: 'granted'\r\n                };\r\n            };\r\n\r\n            const getConsentState = () => {\r\n                const defaultConsent = {\r\n                    ad_user_data: 'denied',\r\n                    ad_personalization: 'denied',\r\n                    analytics_storage: 'denied',\r\n                    ad_storage: 'denied',\r\n\r\n                    \/\/ Datos first-party de la reserva. No equivale a consentimiento de cookies.\r\n                    first_party_user_data: 'granted'\r\n                };\r\n\r\n                try {\r\n                    if (window.cookieyes && typeof window.cookieyes.getConsentStatus === 'function') {\r\n                        return normalizeConsentStatus(window.cookieyes.getConsentStatus());\r\n                    }\r\n\r\n                    \/\/ Compatibilidad defensiva con integraciones antiguas o wrappers mal escritos.\r\n                    if (window.cookieyes && typeof window.cookieyes.getConsecntStatus === 'function') {\r\n                        return normalizeConsentStatus(window.cookieyes.getConsecntStatus());\r\n                    }\r\n                } catch (err) {\r\n                    log('Error leyendo API de CookieYes', String(err && err.message ? err.message : err), 'warn');\r\n                }\r\n\r\n                const parsedCookie = parseCookieYesCookie();\r\n                if (parsedCookie) {\r\n                    return normalizeConsentStatus(parsedCookie);\r\n                }\r\n\r\n                return defaultConsent;\r\n            };\r\n\r\n            const getParamFromUrl = (param, url) => {\r\n                try {\r\n                    const rawUrl = safeString(url);\r\n                    if (!rawUrl || rawUrl === 'direct') return '';\r\n                    const parsed = new URL(rawUrl, window.location.origin);\r\n                    return parsed.searchParams.get(param) || '';\r\n                } catch (err) {\r\n                    return '';\r\n                }\r\n            };\r\n\r\n            const readCurrentOrReferrerParam = (param) => {\r\n                return getParamFromUrl(param, window.location.href) || getParamFromUrl(param, document.referrer || '');\r\n            };\r\n\r\n            const readAttributionParam = (param, canReadStoredCookie) => {\r\n                return (\r\n                    (canReadStoredCookie ? getCookie(`cm_${param}`) : '') ||\r\n                    readCurrentOrReferrerParam(param)\r\n                );\r\n            };\r\n\r\n            const captureAttribution = () => {\r\n                const consent = getConsentState();\r\n                const canStoreAds = consent.ad_storage === 'granted';\r\n                const canStoreAnalytics = consent.analytics_storage === 'granted';\r\n\r\n                AD_PARAMS.forEach((param) => {\r\n                    const value = readCurrentOrReferrerParam(param);\r\n                    if (!value || !canStoreAds) return;\r\n\r\n                    setCookie(`cm_${param}`, value);\r\n\r\n                    if (param === 'fbclid' && !getCookie('cm_fbclid_ts')) {\r\n                        setCookie('cm_fbclid_ts', String(Date.now()));\r\n                    }\r\n                });\r\n\r\n                UTM_PARAMS.forEach((param) => {\r\n                    const value = readCurrentOrReferrerParam(param);\r\n                    if (!value || !canStoreAnalytics) return;\r\n                    setCookie(`cm_${param}`, value);\r\n                });\r\n            };\r\n\r\n            const getGaClientId = () => {\r\n                const gaCookie = getCookie('_ga');\r\n                if (!gaCookie) return '';\r\n\r\n                const clean = gaCookie.replace(\/^_ga=\/, '').trim();\r\n                const parts = clean.split('.');\r\n\r\n                \/\/ _ga habitual: GA1.1.443472446.1779007592 => 443472446.1779007592\r\n                if (parts.length >= 4 && \/^GA\\d+$\/i.test(parts[0])) {\r\n                    return parts.slice(-2).join('.');\r\n                }\r\n\r\n                return clean;\r\n            };\r\n\r\n            const getGaSessionId = () => {\r\n                const gaCookies = (document.cookie || '')\r\n                    .split('; ')\r\n                    .filter((row) => row.trim().startsWith('_ga_'));\r\n\r\n                for (const row of gaCookies) {\r\n                    const value = decodeURIComponent(row.split('=').slice(1).join('=') || '');\r\n                    if (!value) continue;\r\n\r\n                    \/\/ Formato nuevo: GS2.1.s1779011903$o...\r\n                    const matchNew = value.match(\/(?:^|[.$])s(\\d+)\/i);\r\n                    if (matchNew) return matchNew[1];\r\n\r\n                    \/\/ Formato antiguo: GS1.1.1779011903...\r\n                    const parts = value.split('.');\r\n                    if (parts.length >= 3 && \/^\\d+$\/.test(parts[2])) {\r\n                        return parts[2];\r\n                    }\r\n                }\r\n\r\n                return '';\r\n            };\r\n\r\n            const normalizeEventType = (value) => safeString(value).toLowerCase();\r\n\r\n            const normalizeCustomEvent = (value, finalRestaurantId, eventName) => {\r\n                const clean = safeString(value);\r\n                const fallback = eventName === 'Purchase'\r\n                    ? `Compra ${finalRestaurantId}`\r\n                    : `Reserva ${finalRestaurantId}`;\r\n                const base = clean || fallback;\r\n                return base.toLowerCase().startsWith('ns - ') ? base : `NS - ${base}`;\r\n            };\r\n\r\n            const splitName = (fullName) => {\r\n                const parts = safeString(fullName).split(\/\\s+\/).filter(Boolean);\r\n                if (parts.length === 0) return { first_name: '', last_name: '' };\r\n                if (parts.length === 1) return { first_name: parts[0], last_name: '' };\r\n                return { first_name: parts[0], last_name: parts.slice(1).join(' ') };\r\n            };\r\n\r\n            const normalizePhone = (phone, callCode = '') => {\r\n                const rawOriginal = safeString(phone);\r\n                const explicitCallCode = safeString(callCode).replace(\/\\D\/g, '');\r\n\r\n                if (!rawOriginal) return '';\r\n\r\n                \/\/ 1. Si el tel\u00e9fono viene con +, se respeta como internacional.\r\n                if (rawOriginal.trim().startsWith('+')) {\r\n                    return rawOriginal.replace(\/\\D\/g, '');\r\n                }\r\n\r\n                const rawNoSpaces = rawOriginal.replace(\/\\s+\/g, '');\r\n\r\n                \/\/ 2. Si viene con 00 internacional, se respeta y se convierte a formato sin 00.\r\n                if (\/^00\\d{7,15}$\/.test(rawNoSpaces)) {\r\n                    return rawNoSpaces.replace(\/\\D\/g, '').replace(\/^00\/, '');\r\n                }\r\n\r\n                const digits = rawOriginal.replace(\/\\D\/g, '');\r\n                if (!digits) return '';\r\n\r\n                \/\/ 3. Si CoverManager manda prefijo real, se usa.\r\n                if (explicitCallCode) {\r\n                    if (digits.startsWith(explicitCallCode)) {\r\n                        return digits;\r\n                    }\r\n\r\n                    return explicitCallCode + digits;\r\n                }\r\n\r\n                \/\/ 4. Si ya viene con prefijo espa\u00f1ol claro, se respeta.\r\n                if (digits.startsWith('34') && digits.length === 11) {\r\n                    return digits;\r\n                }\r\n\r\n                \/\/ 5. Si parece tel\u00e9fono espa\u00f1ol nacional, se a\u00f1ade 34.\r\n                if (digits.length === 9 && \/^[6-9]\/.test(digits)) {\r\n                    return '34' + digits;\r\n                }\r\n\r\n                \/\/ 6. Si no hay prefijo claro y no parece espa\u00f1ol, no se fuerza 34.\r\n                return digits;\r\n            };\r\n\r\n            const toNumber = (value, fallback = 0) => {\r\n                const n = Number(safeString(value).replace(',', '.'));\r\n                return Number.isFinite(n) ? n : fallback;\r\n            };\r\n\r\n            const toInteger = (value, fallback = 0) => {\r\n                const n = parseInt(value, 10);\r\n                return Number.isFinite(n) ? n : fallback;\r\n            };\r\n\r\n            const generateEventId = () => {\r\n                if (window.crypto && typeof window.crypto.randomUUID === 'function') {\r\n                    return `cm_${window.crypto.randomUUID()}`;\r\n                }\r\n                return `cm_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\r\n            };\r\n\r\n            const alreadySent = (eventName, eventId) => {\r\n                const key = `cm_sent_${eventName}_${eventId}`;\r\n\r\n                try {\r\n                    if (window.sessionStorage && sessionStorage.getItem(key)) return true;\r\n                    if (window.sessionStorage) sessionStorage.setItem(key, String(Date.now()));\r\n                } catch (err) {\r\n                    \/\/ Si sessionStorage est\u00e1 bloqueado, no rompemos el env\u00edo.\r\n                }\r\n\r\n                return false;\r\n            };\r\n\r\n            const buildFbc = (canUseAds) => {\r\n                if (!canUseAds) return '';\r\n\r\n                const existingFbc = getCookie('_fbc');\r\n                if (existingFbc) return existingFbc;\r\n\r\n                const fbclid = readAttributionParam('fbclid', true);\r\n                if (!fbclid) return '';\r\n\r\n                const timestamp = getCookie('cm_fbclid_ts') || String(Date.now());\r\n                return `fb.1.${timestamp}.${fbclid}`;\r\n            };\r\n\r\n            const getAllowedOrigins = () => {\r\n                const configured = Array.isArray(CM_CONFIG.allowedOrigins) ? CM_CONFIG.allowedOrigins : [];\r\n                return configured\r\n                    .map((origin) => safeString(origin).toLowerCase().replace(\/\\\/$\/, ''))\r\n                    .filter(Boolean);\r\n            };\r\n\r\n            const isAllowedMessageOrigin = (origin) => {\r\n                const cleanOrigin = safeString(origin).toLowerCase().replace(\/\\\/$\/, '');\r\n                if (!cleanOrigin) return false;\r\n\r\n                if (cleanOrigin === window.location.origin.toLowerCase()) {\r\n                    return true;\r\n                }\r\n\r\n                const configuredOrigins = getAllowedOrigins();\r\n                if (configuredOrigins.length > 0) {\r\n                    return configuredOrigins.includes(cleanOrigin);\r\n                }\r\n\r\n                \/\/ Fallback prudente si todav\u00eda no se han configurado origins exactos en WP.\r\n                try {\r\n                    const host = new URL(cleanOrigin).hostname.toLowerCase();\r\n                    return host === 'covermanager.com' || host.endsWith('.covermanager.com');\r\n                } catch (err) {\r\n                    return false;\r\n                }\r\n            };\r\n\r\n            const getRawValue = (raw, keys, fallback = '') => {\r\n                for (const key of keys) {\r\n                    if (raw && raw[key] !== undefined && raw[key] !== null && safeString(raw[key]) !== '') {\r\n                        return raw[key];\r\n                    }\r\n                }\r\n                return fallback;\r\n            };\r\n\r\n            const buildPayload = (eventType, raw) => {\r\n                \/\/ Reintenta capturar justo antes de enviar, por si el consentimiento se concedi\u00f3 despu\u00e9s de cargar la p\u00e1gina.\r\n                captureAttribution();\r\n\r\n                const consent = getConsentState();\r\n                const canUseAds = consent.ad_storage === 'granted';\r\n                const canUseAnalytics = consent.analytics_storage === 'granted';\r\n\r\n                const eventName = eventType === 'purchase' ? 'Purchase' : 'Schedule';\r\n                const finalRestaurantId = safeString(getRawValue(raw, ['restaurant', 'restaurant_id'], CM_CONFIG.restaurant || 'unknown')) || 'unknown';\r\n                const rawName = getRawValue(raw, ['name', 'full_name', 'customer_name'], '');\r\n                const nameParts = splitName(rawName);\r\n                const eventId = safeString(getRawValue(raw, ['transaction_id', 'reservation_id', 'booking_id', 'id'], '')) || generateEventId();\r\n                const value = toNumber(getRawValue(raw, ['value', 'amount', 'price', 'total'], 0), 0);\r\n                const currency = (safeString(getRawValue(raw, ['currency'], 'EUR')) || 'EUR').toUpperCase().slice(0, 3);\r\n                const pax = toInteger(getRawValue(raw, ['people', 'pax', 'guests', 'diners'], 0), 0);\r\n                const callCode = safeString(getRawValue(raw, ['call_code', 'phone_prefix'], ''));\r\n\r\n                return {\r\n                    business_unit: safeString(CM_CONFIG.unit),\r\n                    restaurant_id: finalRestaurantId,\r\n                    event_name: eventName,\r\n                    custom_event: normalizeCustomEvent(CM_CONFIG.event, finalRestaurantId, eventName),\r\n                    event_id: eventId,\r\n                    timestamp: Math.floor(Date.now() \/ 1000),\r\n                    event_source_url: window.location.href.split('?')[0],\r\n\r\n                    user_data: {\r\n                        email: safeString(getRawValue(raw, ['email', 'mail'], '')).toLowerCase(),\r\n                        phone: normalizePhone(getRawValue(raw, ['phone', 'telephone', 'mobile'], ''), callCode),\r\n                        call_code: callCode,\r\n                        first_name: safeString(getRawValue(raw, ['first_name'], nameParts.first_name)),\r\n                        last_name: safeString(getRawValue(raw, ['last_name'], nameParts.last_name)),\r\n                        external_id: safeString(getRawValue(raw, ['reservation_id', 'transaction_id', 'booking_id', 'id'], eventId)),\r\n                        address: {\r\n                            country: safeString(getRawValue(raw, ['country'], 'ES')).toUpperCase() || 'ES',\r\n                            city: safeString(getRawValue(raw, ['city'], '')),\r\n                            zip: safeString(getRawValue(raw, ['zip', 'postal_code'], ''))\r\n                        }\r\n                    },\r\n\r\n                    ecommerce: {\r\n                        transaction_id: eventId,\r\n                        value: value,\r\n                        currency: currency,\r\n                        items: [{\r\n                            item_id: eventType === 'purchase' ? `exp_${finalRestaurantId}` : `reserva_${finalRestaurantId}`,\r\n                            item_name: eventType === 'purchase' ? 'Experiencia Gastron\u00f3mica' : 'Reserva de Mesa',\r\n                            item_category: eventType === 'purchase' ? 'Experience' : 'Booking',\r\n                            item_brand: finalRestaurantId,\r\n                            item_variant: pax ? `${pax} pax` : '',\r\n                            price: value,\r\n                            quantity: 1\r\n                        }]\r\n                    },\r\n\r\n                    pax: pax,\r\n                    reservation_date: safeString(getRawValue(raw, ['date', 'reservation_date'], '')),\r\n                    reservation_time: safeString(getRawValue(raw, ['time', 'reservation_time'], '')),\r\n\r\n                    traffic_source: {\r\n                        utm_source: canUseAnalytics ? readAttributionParam('utm_source', true) : '',\r\n                        utm_medium: canUseAnalytics ? readAttributionParam('utm_medium', true) : '',\r\n                        utm_campaign: canUseAnalytics ? readAttributionParam('utm_campaign', true) : '',\r\n                        utm_term: canUseAnalytics ? readAttributionParam('utm_term', true) : '',\r\n                        utm_content: canUseAnalytics ? readAttributionParam('utm_content', true) : '',\r\n                        referrer: document.referrer || 'direct'\r\n                    },\r\n\r\n                    tracking_ids: {\r\n                        fbp: canUseAds ? getCookie('_fbp') : '',\r\n                        fbc: buildFbc(canUseAds),\r\n                        fbclid: canUseAds ? readAttributionParam('fbclid', true) : '',\r\n                        ga_client_id: canUseAnalytics ? getGaClientId() : '',\r\n                        ga_session_id: canUseAnalytics ? getGaSessionId() : '',\r\n                        gclid: canUseAds ? readAttributionParam('gclid', true) : '',\r\n                        gbraid: canUseAds ? readAttributionParam('gbraid', true) : '',\r\n                        wbraid: canUseAds ? readAttributionParam('wbraid', true) : ''\r\n                    },\r\n\r\n                    consent: consent,\r\n                    page_location: window.location.href,\r\n                    page_title: document.title || '',\r\n                    language: navigator.language || '',\r\n                    client_ip: '',\r\n                    client_user_agent: navigator.userAgent || ''\r\n                };\r\n            };\r\n\r\n            const pushToDataLayer = (payload) => {\r\n                window.dataLayer = window.dataLayer || [];\r\n                window.dataLayer.push({ ecommerce: null });\r\n                window.dataLayer.push({\r\n                    event: String(payload.event_name || '').toLowerCase(),\r\n                    ...payload\r\n                });\r\n                log('DataLayer enviado', { event: payload.event_name, event_id: payload.event_id }, 'success');\r\n            };\r\n\r\n            const sendToN8n = (payload) => {\r\n                if (!ENABLE_N8N) {\r\n                    log('n8n desactivado por configuraci\u00f3n', null, 'warn');\r\n                    return;\r\n                }\r\n\r\n                if (!N8N_URL) {\r\n                    log('n8n URL no configurada', null, 'warn');\r\n                    return;\r\n                }\r\n\r\n                if (!AUTH_TOKEN) {\r\n                    log('Bearer token no configurado', null, 'warn');\r\n                    return;\r\n                }\r\n\r\n                const headers = {\r\n                    'Content-Type': 'application\/json',\r\n                    'Authorization': `Bearer ${AUTH_TOKEN}`\r\n                };\r\n\r\n                fetch(N8N_URL, {\r\n                    method: 'POST',\r\n                    mode: 'cors',\r\n                    credentials: 'omit',\r\n                    keepalive: true,\r\n                    headers,\r\n                    body: JSON.stringify(payload)\r\n                })\r\n                    .then(async (res) => {\r\n                        const text = await res.text().catch(() => '');\r\n\r\n                        if (!res.ok) {\r\n                            throw new Error(`n8n HTTP ${res.status}: ${text.slice(0, 300)}`);\r\n                        }\r\n\r\n                        log('n8n Response OK', { status: res.status, body: text.slice(0, 300) }, 'success');\r\n                    })\r\n                    .catch((err) => {\r\n                        log('n8n Error', String(err && err.message ? err.message : err), 'error');\r\n                    });\r\n            };\r\n\r\n            const normalizePostMessageData = (data) => {\r\n                if (data && typeof data === 'object') {\r\n                    return data;\r\n                }\r\n\r\n                if (typeof data === 'string') {\r\n                    try {\r\n                        const parsed = JSON.parse(data);\r\n                        return parsed && typeof parsed === 'object' ? parsed : null;\r\n                    } catch (err) {\r\n                        return null;\r\n                    }\r\n                }\r\n\r\n                return null;\r\n            };\r\n\r\n            const handleCoverManagerMessage = (e) => {\r\n                if (!isAllowedMessageOrigin(e.origin)) {\r\n                    log('postMessage bloqueado por origin', { origin: e.origin }, 'warn');\r\n                    return;\r\n                }\r\n\r\n                const messageData = normalizePostMessageData(e.data);\r\n\r\n                if (!messageData || !messageData.event) {\r\n                    return;\r\n                }\r\n\r\n                const eventType = normalizeEventType(messageData.event);\r\n                const targetType = normalizeEventType(CM_CONFIG.type || 'schedule');\r\n\r\n                if (eventType !== targetType) {\r\n                    return;\r\n                }\r\n\r\n                const raw = (messageData.data && typeof messageData.data === 'object' && messageData.data !== null) ? messageData.data : {};\r\n                const payload = buildPayload(eventType, raw);\r\n\r\n                if (alreadySent(payload.event_name, payload.event_id)) {\r\n                    log('Evento duplicado bloqueado en navegador', { event: payload.event_name, event_id: payload.event_id }, 'warn');\r\n                    return;\r\n                }\r\n\r\n                pushToDataLayer(payload);\r\n                sendToN8n(payload);\r\n            };\r\n\r\n            captureAttribution();\r\n            window.addEventListener('message', handleCoverManagerMessage, false);\r\n\r\n            document.addEventListener('cookieyes_consent_update', captureAttribution, false);\r\n            document.addEventListener('cky-consent-update', captureAttribution, false);\r\n        })();\r\n    <\/script>\r\n    \n\n\n\n<div style=\"height:81px\" aria-hidden=\"true\" class=\"wp-block-spacer bg-secondary\"><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"class_list":["post-635","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/pages\/635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/comments?post=635"}],"version-history":[{"count":6,"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/pages\/635\/revisions"}],"predecessor-version":[{"id":783,"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/pages\/635\/revisions\/783"}],"wp:attachment":[{"href":"https:\/\/www.restaurantetipitapa.com\/en\/wp-json\/wp\/v2\/media?parent=635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}