{"id":151,"date":"2025-11-13T22:46:24","date_gmt":"2025-11-13T22:46:24","guid":{"rendered":"https:\/\/ultratop.net\/miami-event-calendar\/"},"modified":"2026-04-13T02:36:30","modified_gmt":"2026-04-13T02:36:30","slug":"miami-event-calendar","status":"publish","type":"page","link":"https:\/\/inmiami.net\/en\/miami-event-calendar\/","title":{"rendered":"Miami Event Calendar"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"151\" class=\"elementor elementor-151\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4e20448 e-flex e-con-boxed e-con e-parent\" data-id=\"4e20448\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6669a52 elementor-widget elementor-widget-html\" data-id=\"6669a52\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"inmiami-calendar-host\"><\/div>\n\n<script>\nfunction initMiamiCalendar(){\n  var host = document.getElementById('inmiami-calendar-host');\n  \n  \/\/ Si Elementor a\u00fan no ha cargado el div, espera 100ms y vuelve a intentar\n  if (!host) {\n    setTimeout(initMiamiCalendar, 100);\n    return;\n  }\n  \n  \/\/ Evitar que se duplique si el script se ejecuta dos veces\n  if (host.shadowRoot) return; \n\n  var shadow = host.attachShadow({mode: 'open'});\n\n  shadow.innerHTML = `\n    <style>\n      :host { display: block; all: initial; }\n      .cal-wrap { padding: 1rem 0; max-width: 900px; margin: 0 auto; font-family: system-ui, -apple-system, sans-serif; text-align: left; }\n      * { box-sizing: border-box; margin: 0; padding: 0; }\n      \n      .cal-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 1rem; flex-wrap: wrap; gap: 10px; }\n      .cal-title { font-size: 20px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; }\n      .cal-subtitle { font-size: 14px; color: #666; text-transform: capitalize; font-weight: 500;}\n      \n      #im-print-btn { display: flex; align-items: center; gap: 6px; font-size: 13px; padding: 8px 16px; border-radius: 6px; border: none; background: #1a1a1a; color: #fff; cursor: pointer; transition: background .15s; font-family: inherit; font-weight: 500; }\n      #im-print-btn:hover { background: #333; }\n      \n      .toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; background: #fdfdfd; padding: 12px 16px; border-radius: 10px; border: 1px solid #eaeaea; margin-bottom: 1rem; }\n      \n      .nav-controls { display: flex; gap: 6px; align-items: center; }\n      .icon-btn { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; cursor: pointer; transition: all .15s; color: #444; }\n      .icon-btn:hover { background: #f0f0f0; border-color: #ccc; }\n      .today-btn { font-size: 13px; padding: 0 12px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; color: #1a1a1a; cursor: pointer; font-weight: 500; transition: all .15s; }\n      .today-btn:hover { background: #f0f0f0; }\n      \n      .view-controls { display: flex; background: #eee; padding: 3px; border-radius: 8px; }\n      .view-btn { font-size: 13px; padding: 6px 14px; border: none; background: transparent; color: #666; cursor: pointer; border-radius: 6px; font-weight: 500; transition: all .2s; }\n      .view-btn.active { background: #fff; color: #1a1a1a; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n      \n      .filter-row { display: flex; flex-direction: row; gap: 6px; flex-wrap: wrap; margin-bottom: 1.5rem; }\n      .chip { font-size: 12px; padding: 6px 14px; border-radius: 20px; border: 1px solid #ddd; background: #fff; color: #666; cursor: pointer; transition: all .15s; white-space: nowrap; font-weight: 500;}\n      .chip:hover { background: #f5f5f5; }\n      .chip.active { background: #1a1a1a; border-color: #1a1a1a; color: #fff; }\n\n      \/* ESTILOS DE CUADR\u00cdCULA (Mes y Semana) *\/\n      .grid-wrapper { overflow-x: auto; margin-bottom: 1rem; }\n      .calendar-grid { min-width: 600px; border: 1px solid #eaeaea; border-radius: 10px; overflow: hidden; background: #fff; }\n      .grid-header-row { display: grid; grid-template-columns: repeat(7, 1fr); background: #f9f9f9; border-bottom: 1px solid #eaeaea; }\n      .grid-header-cell { padding: 10px 5px; text-align: center; font-size: 12px; font-weight: 600; color: #555; text-transform: uppercase; letter-spacing: 0.5px; border-right: 1px solid #eaeaea; }\n      .grid-header-cell:last-child { border-right: none; }\n      .grid-body { display: flex; flex-direction: column; }\n      .grid-row { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid #eaeaea; }\n      .grid-row:last-child { border-bottom: none; }\n      .grid-cell { min-height: 110px; padding: 6px; border-right: 1px solid #eaeaea; background: #fff; display: flex; flex-direction: column; gap: 4px; }\n      .grid-cell:last-child { border-right: none; }\n      .grid-cell.out-of-month { background: #fafafa; }\n      .cell-date-wrap { display: flex; justify-content: flex-end; margin-bottom: 4px; }\n      .cell-date { font-size: 13px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: #444; font-weight: 500; }\n      .cell-date.today { background: #1D9E75; color: #fff; font-weight: 700; }\n      \n      .event-mini { font-size: 10px; padding: 3px 6px; border-radius: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; font-weight: 500; border-left: 3px solid transparent; transition: opacity .15s; }\n      .event-mini:hover { opacity: 0.8; }\n      .event-mini .mini-time { font-weight: 700; margin-right: 3px; opacity: 0.8; }\n\n      \/* ESTILOS DE LISTA *\/\n      .day-block { margin-bottom: 1.5rem; }\n      .day-label { font-size: 13px; font-weight: 500; color: #888; text-transform: uppercase; letter-spacing: .06em; padding-bottom: 8px; border-bottom: 1px solid #eee; margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }\n      .day-label .dlabel { color: #1a1a1a; font-size: 15px; text-transform: none; letter-spacing: 0; }\n      .count-badge { font-size: 11px; background: #f5f5f5; color: #888; padding: 2px 7px; border-radius: 10px; }\n      \n      .event-card { background: #fff; border: 1px solid #eee; border-radius: 12px; padding: .9rem 1.1rem; margin-bottom: .6rem; display: flex; flex-direction: row; gap: 12px; align-items: flex-start; cursor: pointer; transition: border-color .15s; }\n      .event-card:hover { border-color: #ccc; }\n      .event-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; margin-top: 5px; }\n      .event-body { flex: 1; min-width: 0; }\n      .event-name { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 4px; line-height: 1.35; }\n      .event-meta { font-size: 12px; color: #888; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }\n      .event-type { font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; white-space: nowrap; }\n      .imp-badge { font-size: 11px; padding: 1px 7px; border-radius: 10px; font-weight: 600; }\n      \n      .imp-muy-alta { background: #FCEBEB; color: #A32D2D; }\n      .imp-alta { background: #FAEEDA; color: #854F0B; }\n      .imp-media { background: #E6F1FB; color: #185FA5; }\n      .imp-low { background: #F1EFE8; color: #5F5E5A; }\n      \n      .expand-body { display: none; margin-top: .65rem; padding-top: .65rem; border-top: 1px solid #eee; font-size: 13px; color: #666; line-height: 1.65; }\n      .event-card.open .expand-body { display: block; }\n      \n      .no-events { text-align: center; padding: 2rem; color: #888; font-size: 14px; background: #fafafa; border-radius: 10px; border: 1px dashed #ddd; }\n      .loading-cal { text-align: center; padding: 3rem; color: #888; font-size: 14px; }\n      .error-cal { background: #FCEBEB; border: 1px solid #F09595; border-radius: 8px; padding: .75rem 1rem; font-size: 13px; color: #A32D2D; margin-bottom: 1rem; }\n      .gc-link { font-size: 12px; color: #1D9E75; text-decoration: none; margin-top: 6px; display: inline-block; font-weight: 500; }\n      \n      .show-more-btn { width: 100%; padding: 12px; border-radius: 8px; border: 1px dashed #ccc; background: #fafafa; color: #666; cursor: pointer; font-weight: 600; font-size: 13px; transition: all 0.2s; margin-bottom: 20px; font-family: inherit; display:flex; justify-content:center; align-items:center; gap:8px;}\n      .show-more-btn:hover { background: #f0f0f0; color: #1a1a1a; border-color: #bbb; }\n\n      @media print {\n        .toolbar, .filter-row, #im-print-btn, .show-more-btn { display: none !important; }\n        .expand-body { display: block !important; border-top: 1px dashed #ccc; }\n        .event-card { page-break-inside: avoid; break-inside: avoid; border: 1px solid #000 !important; margin-bottom: 12px; }\n        .calendar-grid { border: 2px solid #000 !important; }\n        .grid-row { page-break-inside: avoid; }\n        .gc-link { display: none !important; }\n        .event-dot, .event-type, .imp-badge, .event-mini, .cell-date.today { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }\n      }\n    <\/style>\n\n    <div class=\"cal-wrap\">\n      <div class=\"cal-header\">\n        <div>\n          <div class=\"cal-title\">Miami Events & Experiences<\/div>\n          <div class=\"cal-subtitle\" id=\"im-date-range\">Cargando...<\/div>\n        <\/div>\n        <button id=\"im-print-btn\">\n          <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 6 2 18 2 18 9\"><\/polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"><\/path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"><\/rect><\/svg>\n          Imprimir\n        <\/button>\n      <\/div>\n      \n      <div class=\"toolbar\">\n        <div class=\"nav-controls\">\n          <button class=\"icon-btn\" id=\"im-prev-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 18 9 12 15 6\"><\/polyline><\/svg><\/button>\n          <button class=\"today-btn\" id=\"im-today-btn\">Hoy<\/button>\n          <button class=\"icon-btn\" id=\"im-next-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"9 18 15 12 9 6\"><\/polyline><\/svg><\/button>\n        <\/div>\n        \n        <div class=\"view-controls\" id=\"im-view-controls\">\n          <button class=\"view-btn active\" data-view=\"month\">Mes<\/button>\n          <button class=\"view-btn\" data-view=\"week\">Semana<\/button>\n          <button class=\"view-btn\" data-view=\"list\">Lista<\/button>\n        <\/div>\n      <\/div>\n\n      <div class=\"filter-row\" id=\"im-filters\"><\/div>\n\n      <div id=\"im-body\">\n        <div class=\"loading-cal\">Conectando con el calendario...<\/div>\n      <\/div>\n    <\/div>\n  `;\n\n  var CAL_ID='7e8c3295deb8d7bb2e675958aa1085c01ef0ae38abafb23b927ec99d74315bcd@group.calendar.google.com';\n  var API_KEY='AIzaSyDQtET3TewbCCkVCZZwbMNV0McGn9yxaXM'; \n  var COLORS={festival:{dot:'#1D9E75',bg:'#E1F5EE',text:'#0F6E56'},music:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},m\u00fasica:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concierto:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concert:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},sport:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},soccer:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},mls:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},film:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},cine:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},art:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},arte:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},food:{dot:'#BA7517',bg:'#FAEEDA',text:'#854F0B'},pride:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},nightlife:{dot:'#534AB7',bg:'#EEEDFE',text:'#3C3489'},default:{dot:'#888780',bg:'#F1EFE8',text:'#5F5E5A'}};\n  var LABELS={festival:'Festival',music:'M\u00fasica',m\u00fasica:'M\u00fasica',concierto:'Concierto',concert:'Concierto',sport:'Deportes',soccer:'F\u00fatbol',mls:'F\u00fatbol',film:'Cine',cine:'Cine',art:'Arte',arte:'Arte',food:'Gastronom\u00eda',pride:'Orgullo',nightlife:'Vida Nocturna'};\n  var DAYS_ES = ['Dom', 'Lun', 'Mar', 'Mi\u00e9', 'Jue', 'Vie', 'S\u00e1b'];\n\n  var allEvents=[], activeFilter='all', showOnlyTop=true;\n  var currentView = 'month'; \n  var currentDate = new Date(); \n\n  function getMIA_YMD(d){\n    var parts = new Intl.DateTimeFormat('en-US', { timeZone: 'America\/New_York', year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(d);\n    var y, m, day;\n    parts.forEach(function(p){ if(p.type==='year') y=p.value; if(p.type==='month') m=p.value; if(p.type==='day') day=p.value; });\n    return y+'-'+m+'-'+day;\n  }\n  function addDays(d, days) { var nd = new Date(d); nd.setDate(nd.getDate() + days); return nd; }\n  function getStartOfWeek(d) { var nd = new Date(d); var day = nd.getDay(); nd.setDate(nd.getDate() - day); return nd; }\n\n  function getCat(ev){var s=((ev.summary||'')+(ev.description||'')).toLowerCase();for(var k in COLORS){if(k!=='default'&&s.includes(k))return k;}return 'default';}\n  function getColor(c){return COLORS[c]||COLORS.default;}\n  function getImp(desc){var m=(desc||'').match(\/importanc[ei]a?\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():'';}\n  function getLoc(ev){var m=(ev.description||'').match(\/tipo\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():(ev.location||'');}\n  function impCls(s){var v=s.toLowerCase();if(v.includes('muy alta')||v.includes('very high')||v.includes('alta'))return 'imp-muy-alta';if(v.includes('media')||v.includes('medium'))return 'imp-media';return 'imp-low';}\n  function fmtTime(d){if(!d)return '';return new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'});}\n  function fmtMiniTime(d){if(!d)return '';var t=new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'}); return t.replace(':00','').replace(' AM','a').replace(' PM','p');}\n  function cleanDesc(d){return (d||'').replace(\/<[^>]+>\/g,'').replace(\/tipo\\s*[:\\-][^\\n]*\/gi,'').replace(\/importanc[ei]a?\\s*[:\\-][^\\n]*\/gi,'').trim();}\n\n  function buildFilters(){\n    var row = shadow.getElementById('im-filters');\n    var cats=new Set(allEvents.map(function(e){return getCat(e);}).filter(function(c){return c!=='default';}));\n    var seen=new Set();\n    var html='<div class=\"chip '+(activeFilter==='all'?'active':'')+'\" data-filter=\"all\">Todos los eventos<\/div>';\n    cats.forEach(function(c){\n      var lbl=LABELS[c];\n      if(lbl&&!seen.has(lbl)){\n        seen.add(lbl);\n        html+='<div class=\"chip '+(activeFilter===c?'active':'')+'\" data-filter=\"'+c+'\">'+lbl+'<\/div>';\n      }\n    });\n    row.innerHTML=html;\n    row.querySelectorAll('.chip').forEach(function(ch){\n      ch.addEventListener('click',function(){\n        activeFilter=ch.dataset.filter;\n        buildFilters();\n        render(); \n      });\n    });\n  }\n\n  function getGroupedEvents() {\n    var groups={};\n    allEvents.forEach(function(ev){\n      var s = getMIA_YMD(new Date(ev.start.dateTime||ev.start.date));\n      if(!groups[s]) groups[s]=[];\n      groups[s].push(ev);\n    });\n    return groups;\n  }\n\n  function filterEvents(evs) {\n    var visible = activeFilter==='all' ? evs : evs.filter(function(e){return getCat(e)===activeFilter;});\n    if (showOnlyTop) {\n      return visible.filter(function(e){ return impCls(getImp(e.description)) === 'imp-muy-alta'; });\n    }\n    return visible;\n  }\n\n  function renderGrid(startDate, numDays, isMonthView) {\n    var groups = getGroupedEvents();\n    var todayYMD = getMIA_YMD(new Date());\n    var currentMonth = currentDate.getMonth();\n    \n    var html = '<div class=\"grid-wrapper\"><div class=\"calendar-grid\">';\n    \n    html += '<div class=\"grid-header-row\">';\n    for(var i=0; i<7; i++) {\n      html += '<div class=\"grid-header-cell\">' + DAYS_ES[i] + '<\/div>';\n    }\n    html += '<\/div><div class=\"grid-body\">';\n    \n    var renderDate = new Date(startDate);\n    var rows = Math.ceil(numDays \/ 7);\n    var additionalHidden = 0; \n    \n    for (var r = 0; r < rows; r++) {\n      html += '<div class=\"grid-row\">';\n      for (var c = 0; c < 7; c++) {\n        var ymd = getMIA_YMD(renderDate);\n        var isToday = (ymd === todayYMD);\n        var isOutOfMonth = isMonthView && (renderDate.getMonth() !== currentMonth);\n        \n        html += '<div class=\"grid-cell ' + (isOutOfMonth ? 'out-of-month' : '') + '\">';\n        html += '<div class=\"cell-date-wrap\"><div class=\"cell-date ' + (isToday ? 'today' : '') + '\">' + renderDate.getDate() + '<\/div><\/div>';\n        \n        var dayEvents = groups[ymd] || [];\n        var visibleEvents = filterEvents(dayEvents);\n        \n        if (showOnlyTop) {\n          var baseVisible = activeFilter==='all' ? dayEvents : dayEvents.filter(function(e){return getCat(e)===activeFilter;});\n          additionalHidden += (baseVisible.length - visibleEvents.length);\n        }\n\n        visibleEvents.forEach(function(ev){\n          var cat = getCat(ev); var col = getColor(cat);\n          var t0 = ev.start.dateTime;\n          var timeStr = t0 ? '<span class=\"mini-time\">'+fmtMiniTime(t0)+'<\/span>' : '';\n          var title = ev.summary || 'Evento';\n          var link = ev.htmlLink ? 'onclick=\"window.open(\\\\''+ev.htmlLink+'\\\\',\\\\'_blank\\\\')\"' : '';\n          \n          html += '<div class=\"event-mini\" title=\"'+title+'\" '+link+' style=\"background:'+col.bg+'; color:'+col.text+'; border-left-color:'+col.dot+';\">';\n          html += timeStr + title;\n          html += '<\/div>';\n        });\n\n        html += '<\/div>';\n        renderDate = addDays(renderDate, 1);\n      }\n      html += '<\/div>';\n    }\n    \n    html += '<\/div><\/div><\/div>';\n\n    if (showOnlyTop && additionalHidden > 0) {\n      html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos regulares adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n    }\n\n    return html;\n  }\n\n  function renderList(groups) {\n    var html='';\n    var additionalHidden = 0;\n    var todayYMD = getMIA_YMD(new Date());\n    \n    Object.keys(groups).sort().forEach(function(ymd){\n      var evs=groups[ymd];\n      var visible = filterEvents(evs);\n      \n      if (showOnlyTop) {\n        var baseVisible = activeFilter==='all' ? evs : evs.filter(function(e){return getCat(e)===activeFilter;});\n        additionalHidden += (baseVisible.length - visible.length);\n      }\n      \n      if (visible.length > 0) {\n        var dLbl = new Date(ymd + 'T12:00:00').toLocaleDateString('es-US', {weekday:'long',month:'long',day:'numeric'});\n        var pre = (ymd === todayYMD) ? 'Hoy' : '';\n        html+='<div class=\"day-block\">';\n        html+='<div class=\"day-label\">'+(pre?'<span>'+pre+' &mdash;<\/span>':'')+'<span class=\"dlabel\">'+dLbl+'<\/span><span class=\"count-badge\">'+visible.length+' evento'+(visible.length!==1?'s':'')+'<\/span><\/div>';\n        \n        visible.forEach(function(ev){\n          var imp=getImp(ev.description);\n          var cat=getCat(ev);var col=getColor(cat);var loc=getLoc(ev);\n          var t0=ev.start.dateTime,t1=ev.end.dateTime;\n          var time=t0?(fmtTime(t0)+(t1?' \\u2013 '+fmtTime(t1):'')):'Todo el d\u00eda';\n          var typeLabel=LABELS[cat]||'Evento';\n          var desc=cleanDesc(ev.description);\n          var link=ev.htmlLink||'';\n          \n          html+='<div class=\"event-card\" data-cat=\"'+cat+'\" onclick=\"this.classList.toggle(\\'open\\')\">';\n          html+='<div class=\"event-dot\" style=\"background:'+col.dot+'\"><\/div>';\n          html+='<div class=\"event-body\">';\n          html+='<div class=\"event-name\">'+(ev.summary||'Untitled')+'<\/div>';\n          html+='<div class=\"event-meta\"><span>'+time+'<\/span>'+(loc?'<span style=\"opacity:.75\">'+loc+'<\/span>':'')+'<span class=\"event-type\" style=\"background:'+col.bg+';color:'+col.text+'\">'+typeLabel+'<\/span>'+(imp?'<span class=\"imp-badge '+impCls(imp)+'\">'+imp+'<\/span>':'')+'<\/div>';\n          html+='<div class=\"expand-body\">'+(desc||'Sin detalles adicionales.')+(link?'<br><a class=\"gc-link\" href=\"'+link+'\" target=\"_blank\">Ver en Google Calendar \\u2192<\/a>':'')+'<\/div>';\n          html+='<\/div><\/div>';\n        });\n        html+='<\/div>';\n      }\n    });\n    \n    if (html === '' && additionalHidden === 0) {\n      html = '<div class=\"no-events\">No hay eventos para esta fecha.<\/div>';\n    } else if (html === '' && additionalHidden > 0) {\n      html = '<div class=\"no-events\">Solo hay eventos regulares programados. Haz clic abajo para verlos.<\/div>';\n    }\n    \n    if (showOnlyTop && additionalHidden > 0) {\n      html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n    }\n    \n    return html;\n  }\n\n  function render() {\n    var body = shadow.getElementById('im-body');\n    if(!allEvents.length){ body.innerHTML='<div class=\"no-events\">No se encontraron eventos para este periodo.<\/div>'; return; }\n    \n    var html = '';\n    if (currentView === 'month') {\n      var y = currentDate.getFullYear();\n      var m = currentDate.getMonth();\n      var firstDay = new Date(y, m, 1);\n      var lastDay = new Date(y, m + 1, 0);\n      var startOffset = firstDay.getDay(); \n      var startDate = addDays(firstDay, -startOffset);\n      var totalDays = Math.ceil((lastDay.getDate() + startOffset) \/ 7) * 7;\n      html = renderGrid(startDate, totalDays, true);\n    } \n    else if (currentView === 'week') {\n      var startOfWeek = getStartOfWeek(currentDate);\n      html = renderGrid(startOfWeek, 7, false);\n    } \n    else if (currentView === 'list') {\n      html = renderList(getGroupedEvents());\n    }\n\n    body.innerHTML = html;\n\n    var moreBtn = shadow.getElementById('im-show-more-btn');\n    if (moreBtn) {\n      moreBtn.addEventListener('click', function() {\n        showOnlyTop = false;\n        render();\n      });\n    }\n  }\n\n  function updateTitle(timeMin, timeMax) {\n    var dr = shadow.getElementById('im-date-range');\n    if (currentView === 'month') {\n      dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'});\n    } else if (currentView === 'week') {\n      dr.textContent = timeMin.toLocaleDateString('es-US', {month:'short', day:'numeric'}) + ' - ' + timeMax.toLocaleDateString('es-US', {month:'short', day:'numeric', year:'numeric'});\n    } else {\n      dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'}); \n    }\n  }\n\n  function loadEvents(){\n    var body = shadow.getElementById('im-body');\n    body.innerHTML='<div class=\"loading-cal\">Cargando eventos de Miami...<\/div>';\n    \n    var timeMin, timeMax;\n\n    if (currentView === 'month' || currentView === 'list') {\n      var y = currentDate.getFullYear();\n      var m = currentDate.getMonth();\n      var firstDay = new Date(y, m, 1);\n      var lastDay = new Date(y, m + 1, 0);\n      var startOffset = firstDay.getDay();\n      timeMin = addDays(firstDay, -startOffset);\n      timeMax = addDays(lastDay, 6 - lastDay.getDay());\n      timeMax.setHours(23, 59, 59);\n    } else if (currentView === 'week') {\n      timeMin = getStartOfWeek(currentDate);\n      timeMax = addDays(timeMin, 6);\n      timeMax.setHours(23, 59, 59);\n    }\n    \n    updateTitle(timeMin, timeMax);\n    \n    var url='https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/'+encodeURIComponent(CAL_ID)+'\/events?key='+API_KEY+'&timeMin='+timeMin.toISOString()+'&timeMax='+timeMax.toISOString()+'&singleEvents=true&orderBy=startTime&maxResults=250';\n    \n    fetch(url).then(function(r){if(!r.ok)return r.json().then(function(e){throw new Error(e.error&&e.error.message||'HTTP '+r.status);});return r.json();}).then(function(data){\n      allEvents=data.items||[];\n      activeFilter='all';\n      showOnlyTop=true; \n      buildFilters();\n      render();\n    }).catch(function(err){body.innerHTML='<div class=\"error-cal\">Error al cargar el calendario: '+err.message+'<\/div>';});\n  }\n\n  shadow.querySelectorAll('.view-btn').forEach(function(btn){\n    btn.addEventListener('click', function(){\n      shadow.querySelectorAll('.view-btn').forEach(function(b){ b.classList.remove('active'); });\n      btn.classList.add('active');\n      currentView = btn.getAttribute('data-view');\n      loadEvents(); \n    });\n  });\n\n  shadow.getElementById('im-prev-btn').addEventListener('click', function(){\n    if (currentView === 'month' || currentView === 'list') {\n      currentDate.setMonth(currentDate.getMonth() - 1);\n    } else if (currentView === 'week') {\n      currentDate.setDate(currentDate.getDate() - 7);\n    }\n    loadEvents();\n  });\n\n  shadow.getElementById('im-next-btn').addEventListener('click', function(){\n    if (currentView === 'month' || currentView === 'list') {\n      currentDate.setMonth(currentDate.getMonth() + 1);\n    } else if (currentView === 'week') {\n      currentDate.setDate(currentDate.getDate() + 7);\n    }\n    loadEvents();\n  });\n\n  shadow.getElementById('im-today-btn').addEventListener('click', function(){\n    currentDate = new Date();\n    loadEvents();\n  });\n\n  shadow.getElementById('im-print-btn').addEventListener('click', function(){\n    window.print();\n  });\n\n  loadEvents();\n}\n\n\/\/ Iniciar el calendario\ninitMiamiCalendar();\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e5525a6 e-flex e-con-boxed e-con e-parent\" data-id=\"e5525a6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ea65024 elementor-widget elementor-widget-html\" data-id=\"ea65024\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"inmiami-calendar-host\"><\/div>\n\n<script>\nfunction initMiamiCalendar(){\n  var host = document.getElementById('inmiami-calendar-host');\n  \n  \/\/ Si Elementor a\u00fan no ha cargado el div, espera 100ms y vuelve a intentar\n  if (!host) {\n    setTimeout(initMiamiCalendar, 100);\n    return;\n  }\n  \n  \/\/ Evitar que se duplique si el script se ejecuta dos veces\n  if (host.shadowRoot) return; \n\n  var shadow = host.attachShadow({mode: 'open'});\n\n  shadow.innerHTML = `\n    <style>\n      :host { display: block; all: initial; }\n      .cal-wrap { padding: 1rem 0; max-width: 900px; margin: 0 auto; font-family: system-ui, -apple-system, sans-serif; text-align: left; }\n      * { box-sizing: border-box; margin: 0; padding: 0; }\n      \n      .cal-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 1rem; flex-wrap: wrap; gap: 10px; }\n      .cal-title { font-size: 20px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; }\n      .cal-subtitle { font-size: 14px; color: #666; text-transform: capitalize; font-weight: 500;}\n      \n      #im-print-btn { display: flex; align-items: center; gap: 6px; font-size: 13px; padding: 8px 16px; border-radius: 6px; border: none; background: #1a1a1a; color: #fff; cursor: pointer; transition: background .15s; font-family: inherit; font-weight: 500; }\n      #im-print-btn:hover { background: #333; }\n      \n      .toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; background: #fdfdfd; padding: 12px 16px; border-radius: 10px; border: 1px solid #eaeaea; margin-bottom: 1rem; }\n      \n      .nav-controls { display: flex; gap: 6px; align-items: center; }\n      .icon-btn { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; cursor: pointer; transition: all .15s; color: #444; }\n      .icon-btn:hover { background: #f0f0f0; border-color: #ccc; }\n      .today-btn { font-size: 13px; padding: 0 12px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; color: #1a1a1a; cursor: pointer; font-weight: 500; transition: all .15s; }\n      .today-btn:hover { background: #f0f0f0; }\n      \n      .view-controls { display: flex; background: #eee; padding: 3px; border-radius: 8px; }\n      .view-btn { font-size: 13px; padding: 6px 14px; border: none; background: transparent; color: #666; cursor: pointer; border-radius: 6px; font-weight: 500; transition: all .2s; }\n      .view-btn.active { background: #fff; color: #1a1a1a; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n      \n      .filter-row { display: flex; flex-direction: row; gap: 6px; flex-wrap: wrap; margin-bottom: 1.5rem; }\n      .chip { font-size: 12px; padding: 6px 14px; border-radius: 20px; border: 1px solid #ddd; background: #fff; color: #666; cursor: pointer; transition: all .15s; white-space: nowrap; font-weight: 500;}\n      .chip:hover { background: #f5f5f5; }\n      .chip.active { background: #1a1a1a; border-color: #1a1a1a; color: #fff; }\n\n      \/* ESTILOS DE CUADR\u00cdCULA (Mes y Semana) *\/\n      .grid-wrapper { overflow-x: auto; margin-bottom: 1rem; }\n      .calendar-grid { min-width: 600px; border: 1px solid #eaeaea; border-radius: 10px; overflow: hidden; background: #fff; }\n      .grid-header-row { display: grid; grid-template-columns: repeat(7, 1fr); background: #f9f9f9; border-bottom: 1px solid #eaeaea; }\n      .grid-header-cell { padding: 10px 5px; text-align: center; font-size: 12px; font-weight: 600; color: #555; text-transform: uppercase; letter-spacing: 0.5px; border-right: 1px solid #eaeaea; }\n      .grid-header-cell:last-child { border-right: none; }\n      .grid-body { display: flex; flex-direction: column; }\n      .grid-row { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid #eaeaea; }\n      .grid-row:last-child { border-bottom: none; }\n      .grid-cell { min-height: 110px; padding: 6px; border-right: 1px solid #eaeaea; background: #fff; display: flex; flex-direction: column; gap: 4px; }\n      .grid-cell:last-child { border-right: none; }\n      .grid-cell.out-of-month { background: #fafafa; }\n      .cell-date-wrap { display: flex; justify-content: flex-end; margin-bottom: 4px; }\n      .cell-date { font-size: 13px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: #444; font-weight: 500; }\n      .cell-date.today { background: #1D9E75; color: #fff; font-weight: 700; }\n      \n      .event-mini { font-size: 10px; padding: 3px 6px; border-radius: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; font-weight: 500; border-left: 3px solid transparent; transition: opacity .15s; }\n      .event-mini:hover { opacity: 0.8; }\n      .event-mini .mini-time { font-weight: 700; margin-right: 3px; opacity: 0.8; }\n\n      \/* ESTILOS DE LISTA *\/\n      .day-block { margin-bottom: 1.5rem; }\n      .day-label { font-size: 13px; font-weight: 500; color: #888; text-transform: uppercase; letter-spacing: .06em; padding-bottom: 8px; border-bottom: 1px solid #eee; margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }\n      .day-label .dlabel { color: #1a1a1a; font-size: 15px; text-transform: none; letter-spacing: 0; }\n      .count-badge { font-size: 11px; background: #f5f5f5; color: #888; padding: 2px 7px; border-radius: 10px; }\n      \n      .event-card { background: #fff; border: 1px solid #eee; border-radius: 12px; padding: .9rem 1.1rem; margin-bottom: .6rem; display: flex; flex-direction: row; gap: 12px; align-items: flex-start; cursor: pointer; transition: border-color .15s; }\n      .event-card:hover { border-color: #ccc; }\n      .event-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; margin-top: 5px; }\n      .event-body { flex: 1; min-width: 0; }\n      .event-name { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 4px; line-height: 1.35; }\n      .event-meta { font-size: 12px; color: #888; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }\n      .event-type { font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; white-space: nowrap; }\n      .imp-badge { font-size: 11px; padding: 1px 7px; border-radius: 10px; font-weight: 600; }\n      \n      .imp-muy-alta { background: #FCEBEB; color: #A32D2D; }\n      .imp-alta { background: #FAEEDA; color: #854F0B; }\n      .imp-media { background: #E6F1FB; color: #185FA5; }\n      .imp-low { background: #F1EFE8; color: #5F5E5A; }\n      \n      .expand-body { display: none; margin-top: .65rem; padding-top: .65rem; border-top: 1px solid #eee; font-size: 13px; color: #666; line-height: 1.65; }\n      .event-card.open .expand-body { display: block; }\n      \n      .no-events { text-align: center; padding: 2rem; color: #888; font-size: 14px; background: #fafafa; border-radius: 10px; border: 1px dashed #ddd; }\n      .loading-cal { text-align: center; padding: 3rem; color: #888; font-size: 14px; }\n      .error-cal { background: #FCEBEB; border: 1px solid #F09595; border-radius: 8px; padding: .75rem 1rem; font-size: 13px; color: #A32D2D; margin-bottom: 1rem; }\n      .gc-link { font-size: 12px; color: #1D9E75; text-decoration: none; margin-top: 6px; display: inline-block; font-weight: 500; }\n      \n      .show-more-btn { width: 100%; padding: 12px; border-radius: 8px; border: 1px dashed #ccc; background: #fafafa; color: #666; cursor: pointer; font-weight: 600; font-size: 13px; transition: all 0.2s; margin-bottom: 20px; font-family: inherit; display:flex; justify-content:center; align-items:center; gap:8px;}\n      .show-more-btn:hover { background: #f0f0f0; color: #1a1a1a; border-color: #bbb; }\n\n      @media print {\n        .toolbar, .filter-row, #im-print-btn, .show-more-btn { display: none !important; }\n        .expand-body { display: block !important; border-top: 1px dashed #ccc; }\n        .event-card { page-break-inside: avoid; break-inside: avoid; border: 1px solid #000 !important; margin-bottom: 12px; }\n        .calendar-grid { border: 2px solid #000 !important; }\n        .grid-row { page-break-inside: avoid; }\n        .gc-link { display: none !important; }\n        .event-dot, .event-type, .imp-badge, .event-mini, .cell-date.today { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }\n      }\n    <\/style>\n\n    <div class=\"cal-wrap\">\n      <div class=\"cal-header\">\n        <div>\n          <div class=\"cal-title\">Miami Events & Experiences<\/div>\n          <div class=\"cal-subtitle\" id=\"im-date-range\">Cargando...<\/div>\n        <\/div>\n        <button id=\"im-print-btn\">\n          <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 6 2 18 2 18 9\"><\/polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"><\/path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"><\/rect><\/svg>\n          Imprimir\n        <\/button>\n      <\/div>\n      \n      <div class=\"toolbar\">\n        <div class=\"nav-controls\">\n          <button class=\"icon-btn\" id=\"im-prev-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 18 9 12 15 6\"><\/polyline><\/svg><\/button>\n          <button class=\"today-btn\" id=\"im-today-btn\">Hoy<\/button>\n          <button class=\"icon-btn\" id=\"im-next-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"9 18 15 12 9 6\"><\/polyline><\/svg><\/button>\n        <\/div>\n        \n        <div class=\"view-controls\" id=\"im-view-controls\">\n          <button class=\"view-btn active\" data-view=\"month\">Mes<\/button>\n          <button class=\"view-btn\" data-view=\"week\">Semana<\/button>\n          <button class=\"view-btn\" data-view=\"list\">Lista<\/button>\n        <\/div>\n      <\/div>\n\n      <div class=\"filter-row\" id=\"im-filters\"><\/div>\n\n      <div id=\"im-body\">\n        <div class=\"loading-cal\">Conectando con el calendario...<\/div>\n      <\/div>\n    <\/div>\n  `;\n\n  var CAL_ID='7e8c3295deb8d7bb2e675958aa1085c01ef0ae38abafb23b927ec99d74315bcd@group.calendar.google.com';\n  var API_KEY='AIzaSyDQtET3TewbCCkVCZZwbMNV0McGn9yxaXM'; \n  var COLORS={festival:{dot:'#1D9E75',bg:'#E1F5EE',text:'#0F6E56'},music:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},m\u00fasica:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concierto:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concert:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},sport:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},soccer:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},mls:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},film:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},cine:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},art:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},arte:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},food:{dot:'#BA7517',bg:'#FAEEDA',text:'#854F0B'},pride:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},nightlife:{dot:'#534AB7',bg:'#EEEDFE',text:'#3C3489'},default:{dot:'#888780',bg:'#F1EFE8',text:'#5F5E5A'}};\n  var LABELS={festival:'Festival',music:'M\u00fasica',m\u00fasica:'M\u00fasica',concierto:'Concierto',concert:'Concierto',sport:'Deportes',soccer:'F\u00fatbol',mls:'F\u00fatbol',film:'Cine',cine:'Cine',art:'Arte',arte:'Arte',food:'Gastronom\u00eda',pride:'Orgullo',nightlife:'Vida Nocturna'};\n  var DAYS_ES = ['Dom', 'Lun', 'Mar', 'Mi\u00e9', 'Jue', 'Vie', 'S\u00e1b'];\n\n  var allEvents=[], activeFilter='all', showOnlyTop=true;\n  var currentView = 'month'; \n  var currentDate = new Date(); \n\n  function getMIA_YMD(d){\n    var parts = new Intl.DateTimeFormat('en-US', { timeZone: 'America\/New_York', year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(d);\n    var y, m, day;\n    parts.forEach(function(p){ if(p.type==='year') y=p.value; if(p.type==='month') m=p.value; if(p.type==='day') day=p.value; });\n    return y+'-'+m+'-'+day;\n  }\n  function addDays(d, days) { var nd = new Date(d); nd.setDate(nd.getDate() + days); return nd; }\n  function getStartOfWeek(d) { var nd = new Date(d); var day = nd.getDay(); nd.setDate(nd.getDate() - day); return nd; }\n\n  function getCat(ev){var s=((ev.summary||'')+(ev.description||'')).toLowerCase();for(var k in COLORS){if(k!=='default'&&s.includes(k))return k;}return 'default';}\n  function getColor(c){return COLORS[c]||COLORS.default;}\n  function getImp(desc){var m=(desc||'').match(\/importanc[ei]a?\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():'';}\n  function getLoc(ev){var m=(ev.description||'').match(\/tipo\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():(ev.location||'');}\n  function impCls(s){var v=s.toLowerCase();if(v.includes('muy alta')||v.includes('very high')||v.includes('alta'))return 'imp-muy-alta';if(v.includes('media')||v.includes('medium'))return 'imp-media';return 'imp-low';}\n  function fmtTime(d){if(!d)return '';return new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'});}\n  function fmtMiniTime(d){if(!d)return '';var t=new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'}); return t.replace(':00','').replace(' AM','a').replace(' PM','p');}\n  function cleanDesc(d){return (d||'').replace(\/<[^>]+>\/g,'').replace(\/tipo\\s*[:\\-][^\\n]*\/gi,'').replace(\/importanc[ei]a?\\s*[:\\-][^\\n]*\/gi,'').trim();}\n\n  function buildFilters(){\n    var row = shadow.getElementById('im-filters');\n    var cats=new Set(allEvents.map(function(e){return getCat(e);}).filter(function(c){return c!=='default';}));\n    var seen=new Set();\n    var html='<div class=\"chip '+(activeFilter==='all'?'active':'')+'\" data-filter=\"all\">Todos los eventos<\/div>';\n    cats.forEach(function(c){\n      var lbl=LABELS[c];\n      if(lbl&&!seen.has(lbl)){\n        seen.add(lbl);\n        html+='<div class=\"chip '+(activeFilter===c?'active':'')+'\" data-filter=\"'+c+'\">'+lbl+'<\/div>';\n      }\n    });\n    row.innerHTML=html;\n    row.querySelectorAll('.chip').forEach(function(ch){\n      ch.addEventListener('click',function(){\n        activeFilter=ch.dataset.filter;\n        buildFilters();\n        render(); \n      });\n    });\n  }\n\n  function getGroupedEvents() {\n    var groups={};\n    allEvents.forEach(function(ev){\n      var s = getMIA_YMD(new Date(ev.start.dateTime||ev.start.date));\n      if(!groups[s]) groups[s]=[];\n      groups[s].push(ev);\n    });\n    return groups;\n  }\n\n  function filterEvents(evs) {\n    var visible = activeFilter==='all' ? evs : evs.filter(function(e){return getCat(e)===activeFilter;});\n    if (showOnlyTop) {\n      return visible.filter(function(e){ return impCls(getImp(e.description)) === 'imp-muy-alta'; });\n    }\n    return visible;\n  }\n\n  function renderGrid(startDate, numDays, isMonthView) {\n    var groups = getGroupedEvents();\n    var todayYMD = getMIA_YMD(new Date());\n    var currentMonth = currentDate.getMonth();\n    \n    var html = '<div class=\"grid-wrapper\"><div class=\"calendar-grid\">';\n    \n    html += '<div class=\"grid-header-row\">';\n    for(var i=0; i<7; i++) {\n      html += '<div class=\"grid-header-cell\">' + DAYS_ES[i] + '<\/div>';\n    }\n    html += '<\/div><div class=\"grid-body\">';\n    \n    var renderDate = new Date(startDate);\n    var rows = Math.ceil(numDays \/ 7);\n    var additionalHidden = 0; \n    \n    for (var r = 0; r < rows; r++) {\n      html += '<div class=\"grid-row\">';\n      for (var c = 0; c < 7; c++) {\n        var ymd = getMIA_YMD(renderDate);\n        var isToday = (ymd === todayYMD);\n        var isOutOfMonth = isMonthView && (renderDate.getMonth() !== currentMonth);\n        \n        html += '<div class=\"grid-cell ' + (isOutOfMonth ? 'out-of-month' : '') + '\">';\n        html += '<div class=\"cell-date-wrap\"><div class=\"cell-date ' + (isToday ? 'today' : '') + '\">' + renderDate.getDate() + '<\/div><\/div>';\n        \n        var dayEvents = groups[ymd] || [];\n        var visibleEvents = filterEvents(dayEvents);\n        \n        if (showOnlyTop) {\n          var baseVisible = activeFilter==='all' ? dayEvents : dayEvents.filter(function(e){return getCat(e)===activeFilter;});\n          additionalHidden += (baseVisible.length - visibleEvents.length);\n        }\n\n        visibleEvents.forEach(function(ev){\n          var cat = getCat(ev); var col = getColor(cat);\n          var t0 = ev.start.dateTime;\n          var timeStr = t0 ? '<span class=\"mini-time\">'+fmtMiniTime(t0)+'<\/span>' : '';\n          var title = ev.summary || 'Evento';\n          var link = ev.htmlLink ? 'onclick=\"window.open(\\\\''+ev.htmlLink+'\\\\',\\\\'_blank\\\\')\"' : '';\n          \n          html += '<div class=\"event-mini\" title=\"'+title+'\" '+link+' style=\"background:'+col.bg+'; color:'+col.text+'; border-left-color:'+col.dot+';\">';\n          html += timeStr + title;\n          html += '<\/div>';\n        });\n\n        html += '<\/div>';\n        renderDate = addDays(renderDate, 1);\n      }\n      html += '<\/div>';\n    }\n    \n    html += '<\/div><\/div><\/div>';\n\n    if (showOnlyTop && additionalHidden > 0) {\n      html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos regulares adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n    }\n\n    return html;\n  }\n\n  function renderList(groups) {\n    var html='';\n    var additionalHidden = 0;\n    var todayYMD = getMIA_YMD(new Date());\n    \n    Object.keys(groups).sort().forEach(function(ymd){\n      var evs=groups[ymd];\n      var visible = filterEvents(evs);\n      \n      if (showOnlyTop) {\n        var baseVisible = activeFilter==='all' ? evs : evs.filter(function(e){return getCat(e)===activeFilter;});\n        additionalHidden += (baseVisible.length - visible.length);\n      }\n      \n      if (visible.length > 0) {\n        var dLbl = new Date(ymd + 'T12:00:00').toLocaleDateString('es-US', {weekday:'long',month:'long',day:'numeric'});\n        var pre = (ymd === todayYMD) ? 'Hoy' : '';\n        html+='<div class=\"day-block\">';\n        html+='<div class=\"day-label\">'+(pre?'<span>'+pre+' &mdash;<\/span>':'')+'<span class=\"dlabel\">'+dLbl+'<\/span><span class=\"count-badge\">'+visible.length+' evento'+(visible.length!==1?'s':'')+'<\/span><\/div>';\n        \n        visible.forEach(function(ev){\n          var imp=getImp(ev.description);\n          var cat=getCat(ev);var col=getColor(cat);var loc=getLoc(ev);\n          var t0=ev.start.dateTime,t1=ev.end.dateTime;\n          var time=t0?(fmtTime(t0)+(t1?' \\u2013 '+fmtTime(t1):'')):'Todo el d\u00eda';\n          var typeLabel=LABELS[cat]||'Evento';\n          var desc=cleanDesc(ev.description);\n          var link=ev.htmlLink||'';\n          \n          html+='<div class=\"event-card\" data-cat=\"'+cat+'\" onclick=\"this.classList.toggle(\\'open\\')\">';\n          html+='<div class=\"event-dot\" style=\"background:'+col.dot+'\"><\/div>';\n          html+='<div class=\"event-body\">';\n          html+='<div class=\"event-name\">'+(ev.summary||'Untitled')+'<\/div>';\n          html+='<div class=\"event-meta\"><span>'+time+'<\/span>'+(loc?'<span style=\"opacity:.75\">'+loc+'<\/span>':'')+'<span class=\"event-type\" style=\"background:'+col.bg+';color:'+col.text+'\">'+typeLabel+'<\/span>'+(imp?'<span class=\"imp-badge '+impCls(imp)+'\">'+imp+'<\/span>':'')+'<\/div>';\n          html+='<div class=\"expand-body\">'+(desc||'Sin detalles adicionales.')+(link?'<br><a class=\"gc-link\" href=\"'+link+'\" target=\"_blank\">Ver en Google Calendar \\u2192<\/a>':'')+'<\/div>';\n          html+='<\/div><\/div>';\n        });\n        html+='<\/div>';\n      }\n    });\n    \n    if (html === '' && additionalHidden === 0) {\n      html = '<div class=\"no-events\">No hay eventos para esta fecha.<\/div>';\n    } else if (html === '' && additionalHidden > 0) {\n      html = '<div class=\"no-events\">Solo hay eventos regulares programados. Haz clic abajo para verlos.<\/div>';\n    }\n    \n    if (showOnlyTop && additionalHidden > 0) {\n      html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n    }\n    \n    return html;\n  }\n\n  function render() {\n    var body = shadow.getElementById('im-body');\n    if(!allEvents.length){ body.innerHTML='<div class=\"no-events\">No se encontraron eventos para este periodo.<\/div>'; return; }\n    \n    var html = '';\n    if (currentView === 'month') {\n      var y = currentDate.getFullYear();\n      var m = currentDate.getMonth();\n      var firstDay = new Date(y, m, 1);\n      var lastDay = new Date(y, m + 1, 0);\n      var startOffset = firstDay.getDay(); \n      var startDate = addDays(firstDay, -startOffset);\n      var totalDays = Math.ceil((lastDay.getDate() + startOffset) \/ 7) * 7;\n      html = renderGrid(startDate, totalDays, true);\n    } \n    else if (currentView === 'week') {\n      var startOfWeek = getStartOfWeek(currentDate);\n      html = renderGrid(startOfWeek, 7, false);\n    } \n    else if (currentView === 'list') {\n      html = renderList(getGroupedEvents());\n    }\n\n    body.innerHTML = html;\n\n    var moreBtn = shadow.getElementById('im-show-more-btn');\n    if (moreBtn) {\n      moreBtn.addEventListener('click', function() {\n        showOnlyTop = false;\n        render();\n      });\n    }\n  }\n\n  function updateTitle(timeMin, timeMax) {\n    var dr = shadow.getElementById('im-date-range');\n    if (currentView === 'month') {\n      dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'});\n    } else if (currentView === 'week') {\n      dr.textContent = timeMin.toLocaleDateString('es-US', {month:'short', day:'numeric'}) + ' - ' + timeMax.toLocaleDateString('es-US', {month:'short', day:'numeric', year:'numeric'});\n    } else {\n      dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'}); \n    }\n  }\n\n  function loadEvents(){\n    var body = shadow.getElementById('im-body');\n    body.innerHTML='<div class=\"loading-cal\">Cargando eventos de Miami...<\/div>';\n    \n    var timeMin, timeMax;\n\n    if (currentView === 'month' || currentView === 'list') {\n      var y = currentDate.getFullYear();\n      var m = currentDate.getMonth();\n      var firstDay = new Date(y, m, 1);\n      var lastDay = new Date(y, m + 1, 0);\n      var startOffset = firstDay.getDay();\n      timeMin = addDays(firstDay, -startOffset);\n      timeMax = addDays(lastDay, 6 - lastDay.getDay());\n      timeMax.setHours(23, 59, 59);\n    } else if (currentView === 'week') {\n      timeMin = getStartOfWeek(currentDate);\n      timeMax = addDays(timeMin, 6);\n      timeMax.setHours(23, 59, 59);\n    }\n    \n    updateTitle(timeMin, timeMax);\n    \n    var url='https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/'+encodeURIComponent(CAL_ID)+'\/events?key='+API_KEY+'&timeMin='+timeMin.toISOString()+'&timeMax='+timeMax.toISOString()+'&singleEvents=true&orderBy=startTime&maxResults=250';\n    \n    fetch(url).then(function(r){if(!r.ok)return r.json().then(function(e){throw new Error(e.error&&e.error.message||'HTTP '+r.status);});return r.json();}).then(function(data){\n      allEvents=data.items||[];\n      activeFilter='all';\n      showOnlyTop=true; \n      buildFilters();\n      render();\n    }).catch(function(err){body.innerHTML='<div class=\"error-cal\">Error al cargar el calendario: '+err.message+'<\/div>';});\n  }\n\n  shadow.querySelectorAll('.view-btn').forEach(function(btn){\n    btn.addEventListener('click', function(){\n      shadow.querySelectorAll('.view-btn').forEach(function(b){ b.classList.remove('active'); });\n      btn.classList.add('active');\n      currentView = btn.getAttribute('data-view');\n      loadEvents(); \n    });\n  });\n\n  shadow.getElementById('im-prev-btn').addEventListener('click', function(){\n    if (currentView === 'month' || currentView === 'list') {\n      currentDate.setMonth(currentDate.getMonth() - 1);\n    } else if (currentView === 'week') {\n      currentDate.setDate(currentDate.getDate() - 7);\n    }\n    loadEvents();\n  });\n\n  shadow.getElementById('im-next-btn').addEventListener('click', function(){\n    if (currentView === 'month' || currentView === 'list') {\n      currentDate.setMonth(currentDate.getMonth() + 1);\n    } else if (currentView === 'week') {\n      currentDate.setDate(currentDate.getDate() + 7);\n    }\n    loadEvents();\n  });\n\n  shadow.getElementById('im-today-btn').addEventListener('click', function(){\n    currentDate = new Date();\n    loadEvents();\n  });\n\n  shadow.getElementById('im-print-btn').addEventListener('click', function(){\n    window.print();\n  });\n\n  loadEvents();\n}\n\n\/\/ Iniciar el calendario\ninitMiamiCalendar();\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-94a8ba5 e-flex e-con-boxed e-con e-parent\" data-id=\"94a8ba5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ab71088 elementor-widget elementor-widget-shortcode\" data-id=\"ab71088\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5f40228 e-flex e-con-boxed e-con e-parent\" data-id=\"5f40228\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e479c2b elementor-widget elementor-widget-html\" data-id=\"e479c2b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"inmiami-calendar-host\"><\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  function initMiamiCalendar(){\n    var host = document.getElementById('inmiami-calendar-host');\n    \n    \/\/ Si Elementor a\u00fan no ha cargado el div, espera 200ms y vuelve a intentar\n    if (!host) {\n      setTimeout(initMiamiCalendar, 200);\n      return;\n    }\n    \n    \/\/ Evitar que se duplique si el script se ejecuta dos veces\n    if (host.shadowRoot) return; \n\n    var shadow = host.attachShadow({mode: 'open'});\n\n    shadow.innerHTML = `\n      <style>\n        :host { display: block; all: initial; }\n        .cal-wrap { padding: 1rem 0; max-width: 900px; margin: 0 auto; font-family: system-ui, -apple-system, sans-serif; text-align: left; }\n        * { box-sizing: border-box; margin: 0; padding: 0; }\n        \n        .cal-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 1rem; flex-wrap: wrap; gap: 10px; }\n        .cal-title { font-size: 20px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; }\n        .cal-subtitle { font-size: 14px; color: #666; text-transform: capitalize; font-weight: 500;}\n        \n        #im-print-btn { display: flex; align-items: center; gap: 6px; font-size: 13px; padding: 8px 16px; border-radius: 6px; border: none; background: #1a1a1a; color: #fff; cursor: pointer; transition: background .15s; font-family: inherit; font-weight: 500; }\n        #im-print-btn:hover { background: #333; }\n        \n        .toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; background: #fdfdfd; padding: 12px 16px; border-radius: 10px; border: 1px solid #eaeaea; margin-bottom: 1rem; }\n        \n        .nav-controls { display: flex; gap: 6px; align-items: center; }\n        .icon-btn { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; cursor: pointer; transition: all .15s; color: #444; }\n        .icon-btn:hover { background: #f0f0f0; border-color: #ccc; }\n        .today-btn { font-size: 13px; padding: 0 12px; height: 32px; border-radius: 6px; border: 1px solid #ddd; background: #fff; color: #1a1a1a; cursor: pointer; font-weight: 500; transition: all .15s; }\n        .today-btn:hover { background: #f0f0f0; }\n        \n        .view-controls { display: flex; background: #eee; padding: 3px; border-radius: 8px; }\n        .view-btn { font-size: 13px; padding: 6px 14px; border: none; background: transparent; color: #666; cursor: pointer; border-radius: 6px; font-weight: 500; transition: all .2s; }\n        .view-btn.active { background: #fff; color: #1a1a1a; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        \n        .filter-row { display: flex; flex-direction: row; gap: 6px; flex-wrap: wrap; margin-bottom: 1.5rem; }\n        .chip { font-size: 12px; padding: 6px 14px; border-radius: 20px; border: 1px solid #ddd; background: #fff; color: #666; cursor: pointer; transition: all .15s; white-space: nowrap; font-weight: 500;}\n        .chip:hover { background: #f5f5f5; }\n        .chip.active { background: #1a1a1a; border-color: #1a1a1a; color: #fff; }\n\n        \/* ESTILOS DE CUADR\u00cdCULA (Mes y Semana) *\/\n        .grid-wrapper { overflow-x: auto; margin-bottom: 1rem; }\n        .calendar-grid { min-width: 600px; border: 1px solid #eaeaea; border-radius: 10px; overflow: hidden; background: #fff; }\n        .grid-header-row { display: grid; grid-template-columns: repeat(7, 1fr); background: #f9f9f9; border-bottom: 1px solid #eaeaea; }\n        .grid-header-cell { padding: 10px 5px; text-align: center; font-size: 12px; font-weight: 600; color: #555; text-transform: uppercase; letter-spacing: 0.5px; border-right: 1px solid #eaeaea; }\n        .grid-header-cell:last-child { border-right: none; }\n        .grid-body { display: flex; flex-direction: column; }\n        .grid-row { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid #eaeaea; }\n        .grid-row:last-child { border-bottom: none; }\n        .grid-cell { min-height: 110px; padding: 6px; border-right: 1px solid #eaeaea; background: #fff; display: flex; flex-direction: column; gap: 4px; }\n        .grid-cell:last-child { border-right: none; }\n        .grid-cell.out-of-month { background: #fafafa; }\n        .cell-date-wrap { display: flex; justify-content: flex-end; margin-bottom: 4px; }\n        .cell-date { font-size: 13px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: #444; font-weight: 500; }\n        .cell-date.today { background: #1D9E75; color: #fff; font-weight: 700; }\n        \n        .event-mini { font-size: 10px; padding: 3px 6px; border-radius: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; font-weight: 500; border-left: 3px solid transparent; transition: opacity .15s; }\n        .event-mini:hover { opacity: 0.8; }\n        .event-mini .mini-time { font-weight: 700; margin-right: 3px; opacity: 0.8; }\n\n        \/* ESTILOS DE LISTA *\/\n        .day-block { margin-bottom: 1.5rem; }\n        .day-label { font-size: 13px; font-weight: 500; color: #888; text-transform: uppercase; letter-spacing: .06em; padding-bottom: 8px; border-bottom: 1px solid #eee; margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }\n        .day-label .dlabel { color: #1a1a1a; font-size: 15px; text-transform: none; letter-spacing: 0; }\n        .count-badge { font-size: 11px; background: #f5f5f5; color: #888; padding: 2px 7px; border-radius: 10px; }\n        \n        .event-card { background: #fff; border: 1px solid #eee; border-radius: 12px; padding: .9rem 1.1rem; margin-bottom: .6rem; display: flex; flex-direction: row; gap: 12px; align-items: flex-start; cursor: pointer; transition: border-color .15s; }\n        .event-card:hover { border-color: #ccc; }\n        .event-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; margin-top: 5px; }\n        .event-body { flex: 1; min-width: 0; }\n        .event-name { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 4px; line-height: 1.35; }\n        .event-meta { font-size: 12px; color: #888; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }\n        .event-type { font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; white-space: nowrap; }\n        .imp-badge { font-size: 11px; padding: 1px 7px; border-radius: 10px; font-weight: 600; }\n        \n        .imp-muy-alta { background: #FCEBEB; color: #A32D2D; }\n        .imp-alta { background: #FAEEDA; color: #854F0B; }\n        .imp-media { background: #E6F1FB; color: #185FA5; }\n        .imp-low { background: #F1EFE8; color: #5F5E5A; }\n        \n        .expand-body { display: none; margin-top: .65rem; padding-top: .65rem; border-top: 1px solid #eee; font-size: 13px; color: #666; line-height: 1.65; }\n        .event-card.open .expand-body { display: block; }\n        \n        .no-events { text-align: center; padding: 2rem; color: #888; font-size: 14px; background: #fafafa; border-radius: 10px; border: 1px dashed #ddd; }\n        .loading-cal { text-align: center; padding: 3rem; color: #888; font-size: 14px; }\n        .error-cal { background: #FCEBEB; border: 1px solid #F09595; border-radius: 8px; padding: .75rem 1rem; font-size: 13px; color: #A32D2D; margin-bottom: 1rem; }\n        .gc-link { font-size: 12px; color: #1D9E75; text-decoration: none; margin-top: 6px; display: inline-block; font-weight: 500; }\n        \n        .show-more-btn { width: 100%; padding: 12px; border-radius: 8px; border: 1px dashed #ccc; background: #fafafa; color: #666; cursor: pointer; font-weight: 600; font-size: 13px; transition: all 0.2s; margin-bottom: 20px; font-family: inherit; display:flex; justify-content:center; align-items:center; gap:8px;}\n        .show-more-btn:hover { background: #f0f0f0; color: #1a1a1a; border-color: #bbb; }\n\n        @media print {\n          .toolbar, .filter-row, #im-print-btn, .show-more-btn { display: none !important; }\n          .expand-body { display: block !important; border-top: 1px dashed #ccc; }\n          .event-card { page-break-inside: avoid; break-inside: avoid; border: 1px solid #000 !important; margin-bottom: 12px; }\n          .calendar-grid { border: 2px solid #000 !important; }\n          .grid-row { page-break-inside: avoid; }\n          .gc-link { display: none !important; }\n          .event-dot, .event-type, .imp-badge, .event-mini, .cell-date.today { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }\n        }\n      <\/style>\n\n      <div class=\"cal-wrap\">\n        <div class=\"cal-header\">\n          <div>\n            <div class=\"cal-title\">Miami Events & Experiences<\/div>\n            <div class=\"cal-subtitle\" id=\"im-date-range\">Cargando...<\/div>\n          <\/div>\n          <button id=\"im-print-btn\">\n            <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 6 2 18 2 18 9\"><\/polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"><\/path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"><\/rect><\/svg>\n            Imprimir\n          <\/button>\n        <\/div>\n        \n        <div class=\"toolbar\">\n          <div class=\"nav-controls\">\n            <button class=\"icon-btn\" id=\"im-prev-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 18 9 12 15 6\"><\/polyline><\/svg><\/button>\n            <button class=\"today-btn\" id=\"im-today-btn\">Hoy<\/button>\n            <button class=\"icon-btn\" id=\"im-next-btn\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"9 18 15 12 9 6\"><\/polyline><\/svg><\/button>\n          <\/div>\n          \n          <div class=\"view-controls\" id=\"im-view-controls\">\n            <button class=\"view-btn active\" data-view=\"month\">Mes<\/button>\n            <button class=\"view-btn\" data-view=\"week\">Semana<\/button>\n            <button class=\"view-btn\" data-view=\"list\">Lista<\/button>\n          <\/div>\n        <\/div>\n\n        <div class=\"filter-row\" id=\"im-filters\"><\/div>\n\n        <div id=\"im-body\">\n          <div class=\"loading-cal\">Conectando con el calendario...<\/div>\n        <\/div>\n      <\/div>\n    `;\n\n    var CAL_ID='7e8c3295deb8d7bb2e675958aa1085c01ef0ae38abafb23b927ec99d74315bcd@group.calendar.google.com';\n    var API_KEY='AIzaSyDQtET3TewbCCkVCZZwbMNV0McGn9yxaXM'; \n    var COLORS={festival:{dot:'#1D9E75',bg:'#E1F5EE',text:'#0F6E56'},music:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},m\u00fasica:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concierto:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},concert:{dot:'#7F77DD',bg:'#EEEDFE',text:'#3C3489'},sport:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},soccer:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},mls:{dot:'#378ADD',bg:'#E6F1FB',text:'#185FA5'},film:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},cine:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},art:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},arte:{dot:'#D85A30',bg:'#FAECE7',text:'#712B13'},food:{dot:'#BA7517',bg:'#FAEEDA',text:'#854F0B'},pride:{dot:'#D4537E',bg:'#FBEAF0',text:'#72243E'},nightlife:{dot:'#534AB7',bg:'#EEEDFE',text:'#3C3489'},default:{dot:'#888780',bg:'#F1EFE8',text:'#5F5E5A'}};\n    var LABELS={festival:'Festival',music:'M\u00fasica',m\u00fasica:'M\u00fasica',concierto:'Concierto',concert:'Concierto',sport:'Deportes',soccer:'F\u00fatbol',mls:'F\u00fatbol',film:'Cine',cine:'Cine',art:'Arte',arte:'Arte',food:'Gastronom\u00eda',pride:'Orgullo',nightlife:'Vida Nocturna'};\n    var DAYS_ES = ['Dom', 'Lun', 'Mar', 'Mi\u00e9', 'Jue', 'Vie', 'S\u00e1b'];\n\n    var allEvents=[], activeFilter='all', showOnlyTop=true;\n    var currentView = 'month'; \n    var currentDate = new Date(); \n\n    function getMIA_YMD(d){\n      var parts = new Intl.DateTimeFormat('en-US', { timeZone: 'America\/New_York', year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(d);\n      var y, m, day;\n      parts.forEach(function(p){ if(p.type==='year') y=p.value; if(p.type==='month') m=p.value; if(p.type==='day') day=p.value; });\n      return y+'-'+m+'-'+day;\n    }\n    function addDays(d, days) { var nd = new Date(d); nd.setDate(nd.getDate() + days); return nd; }\n    function getStartOfWeek(d) { var nd = new Date(d); var day = nd.getDay(); nd.setDate(nd.getDate() - day); return nd; }\n\n    function getCat(ev){var s=((ev.summary||'')+(ev.description||'')).toLowerCase();for(var k in COLORS){if(k!=='default'&&s.includes(k))return k;}return 'default';}\n    function getColor(c){return COLORS[c]||COLORS.default;}\n    function getImp(desc){var m=(desc||'').match(\/importanc[ei]a?\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():'';}\n    function getLoc(ev){var m=(ev.description||'').match(\/tipo\\s*[:\\-]\\s*([^\\n<\\r]+)\/i);return m?m[1].trim():(ev.location||'');}\n    \n    function impCls(s){\n      var v=s.toLowerCase();\n      if(v.includes('muy alta')||v.includes('very high')||v.includes('alta')) return 'imp-muy-alta';\n      if(v.includes('media')||v.includes('medium')) return 'imp-media';\n      return 'imp-low';\n    }\n    \n    function fmtTime(d){\n      if(!d) return '';\n      return new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'});\n    }\n    \n    function fmtMiniTime(d){\n      if(!d) return '';\n      var t=new Date(d).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit',hour12:true,timeZone:'America\/New_York'}); \n      return t.replace(':00','').replace(' AM','a').replace(' PM','p');\n    }\n    \n    function cleanDesc(d){\n      return (d||'').replace(\/<[^>]+>\/g,'').replace(\/tipo\\s*[:\\-][^\\n]*\/gi,'').replace(\/importanc[ei]a?\\s*[:\\-][^\\n]*\/gi,'').trim();\n    }\n\n    function buildFilters(){\n      var row = shadow.getElementById('im-filters');\n      var cats=new Set(allEvents.map(function(e){return getCat(e);}).filter(function(c){return c!=='default';}));\n      var seen=new Set();\n      \n      var activeClass = '';\n      if (activeFilter === 'all') { activeClass = 'active'; }\n      var html = '<div class=\"chip ' + activeClass + '\" data-filter=\"all\">Todos los eventos<\/div>';\n      \n      cats.forEach(function(c){\n        var lbl=LABELS[c];\n        if(lbl && !seen.has(lbl)){\n          seen.add(lbl);\n          var cClass = '';\n          if (activeFilter === c) { cClass = 'active'; }\n          html += '<div class=\"chip ' + cClass + '\" data-filter=\"' + c + '\">' + lbl + '<\/div>';\n        }\n      });\n      row.innerHTML=html;\n      row.querySelectorAll('.chip').forEach(function(ch){\n        ch.addEventListener('click',function(){\n          activeFilter=ch.dataset.filter;\n          buildFilters();\n          render(); \n        });\n      });\n    }\n\n    function getGroupedEvents() {\n      var groups={};\n      allEvents.forEach(function(ev){\n        var s = getMIA_YMD(new Date(ev.start.dateTime||ev.start.date));\n        if(!groups[s]) { groups[s]=[]; }\n        groups[s].push(ev);\n      });\n      return groups;\n    }\n\n    function filterEvents(evs) {\n      var visible = evs;\n      if (activeFilter !== 'all') {\n        visible = evs.filter(function(e){ return getCat(e) === activeFilter; });\n      }\n      if (showOnlyTop) {\n        return visible.filter(function(e){ return impCls(getImp(e.description)) === 'imp-muy-alta'; });\n      }\n      return visible;\n    }\n\n    function renderGrid(startDate, numDays, isMonthView) {\n      var groups = getGroupedEvents();\n      var todayYMD = getMIA_YMD(new Date());\n      var currentMonth = currentDate.getMonth();\n      \n      var html = '<div class=\"grid-wrapper\"><div class=\"calendar-grid\">';\n      \n      html += '<div class=\"grid-header-row\">';\n      for(var i=0; i<7; i++) {\n        html += '<div class=\"grid-header-cell\">' + DAYS_ES[i] + '<\/div>';\n      }\n      html += '<\/div><div class=\"grid-body\">';\n      \n      var renderDate = new Date(startDate);\n      var rows = Math.ceil(numDays \/ 7);\n      var additionalHidden = 0; \n      \n      for (var r = 0; r < rows; r++) {\n        html += '<div class=\"grid-row\">';\n        for (var c = 0; c < 7; c++) {\n          var ymd = getMIA_YMD(renderDate);\n          \n          var cellClasses = 'grid-cell';\n          if (isMonthView && renderDate.getMonth() !== currentMonth) {\n            cellClasses += ' out-of-month';\n          }\n          \n          var dateClasses = 'cell-date';\n          if (ymd === todayYMD) {\n            dateClasses += ' today';\n          }\n          \n          html += '<div class=\"' + cellClasses + '\">';\n          html += '<div class=\"cell-date-wrap\"><div class=\"' + dateClasses + '\">' + renderDate.getDate() + '<\/div><\/div>';\n          \n          var dayEvents = groups[ymd] || [];\n          var visibleEvents = filterEvents(dayEvents);\n          \n          if (showOnlyTop) {\n            var baseVisible = dayEvents;\n            if (activeFilter !== 'all') {\n              baseVisible = dayEvents.filter(function(e){ return getCat(e) === activeFilter; });\n            }\n            additionalHidden += (baseVisible.length - visibleEvents.length);\n          }\n\n          visibleEvents.forEach(function(ev){\n            var cat = getCat(ev); \n            var col = getColor(cat);\n            var t0 = ev.start.dateTime;\n            \n            var timeStr = '';\n            if (t0) {\n              timeStr = '<span class=\"mini-time\">' + fmtMiniTime(t0) + '<\/span>';\n            }\n            \n            var title = 'Evento';\n            if (ev.summary) {\n              title = ev.summary.replace(\/\"\/g, '&quot;'); \n            }\n            \n            var linkData = '';\n            if (ev.htmlLink) {\n              linkData = ' data-link=\"' + ev.htmlLink + '\"';\n            }\n            \n            html += '<div class=\"event-mini\" title=\"' + title + '\"' + linkData + ' style=\"background:' + col.bg + '; color:' + col.text + '; border-left-color:' + col.dot + ';\">';\n            html += timeStr + title;\n            html += '<\/div>';\n          });\n\n          html += '<\/div>';\n          renderDate = addDays(renderDate, 1);\n        }\n        html += '<\/div>';\n      }\n      \n      html += '<\/div><\/div><\/div>';\n\n      if (showOnlyTop && additionalHidden > 0) {\n        html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos regulares adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n      }\n\n      return html;\n    }\n\n    function renderList(groups) {\n      var html='';\n      var additionalHidden = 0;\n      var todayYMD = getMIA_YMD(new Date());\n      \n      Object.keys(groups).sort().forEach(function(ymd){\n        var evs=groups[ymd];\n        var visible = filterEvents(evs);\n        \n        if (showOnlyTop) {\n          var baseVisible = evs;\n          if (activeFilter !== 'all') {\n            baseVisible = evs.filter(function(e){ return getCat(e) === activeFilter; });\n          }\n          additionalHidden += (baseVisible.length - visible.length);\n        }\n        \n        if (visible.length > 0) {\n          var dLbl = new Date(ymd + 'T12:00:00').toLocaleDateString('es-US', {weekday:'long',month:'long',day:'numeric'});\n          \n          var preHtml = '';\n          if (ymd === todayYMD) {\n            preHtml = '<span>Hoy &mdash;<\/span>';\n          }\n          \n          var plural = '';\n          if (visible.length !== 1) {\n            plural = 's';\n          }\n          \n          html += '<div class=\"day-block\">';\n          html += '<div class=\"day-label\">' + preHtml + '<span class=\"dlabel\">' + dLbl + '<\/span><span class=\"count-badge\">' + visible.length + ' evento' + plural + '<\/span><\/div>';\n          \n          visible.forEach(function(ev){\n            var imp=getImp(ev.description);\n            var cat=getCat(ev);\n            var col=getColor(cat);\n            var loc=getLoc(ev);\n            var t0=ev.start.dateTime;\n            var t1=ev.end.dateTime;\n            \n            var time='Todo el d\u00eda';\n            if (t0) {\n              time = fmtTime(t0);\n              if (t1) {\n                time += ' \\u2013 ' + fmtTime(t1);\n              }\n            }\n            \n            var typeLabel = LABELS[cat];\n            if (!typeLabel) { typeLabel = 'Evento'; }\n            \n            var desc = cleanDesc(ev.description);\n            if (!desc) { desc = 'Sin detalles adicionales.'; }\n            \n            var link = ev.htmlLink;\n            \n            var locHtml = '';\n            if (loc) {\n              locHtml = '<span style=\"opacity:.75\">' + loc + '<\/span>';\n            }\n            \n            var impHtml = '';\n            if (imp) {\n              impHtml = '<span class=\"imp-badge ' + impCls(imp) + '\">' + imp + '<\/span>';\n            }\n            \n            var linkHtml = '';\n            if (link) {\n              linkHtml = '<br><a class=\"gc-link\" href=\"' + link + '\" target=\"_blank\">Ver en Google Calendar \\u2192<\/a>';\n            }\n            \n            var summary = ev.summary;\n            if (!summary) { summary = 'Untitled'; }\n            \n            html += '<div class=\"event-card list-card\" data-cat=\"' + cat + '\">';\n            html += '<div class=\"event-dot\" style=\"background:' + col.dot + '\"><\/div>';\n            html += '<div class=\"event-body\">';\n            html += '<div class=\"event-name\">' + summary + '<\/div>';\n            html += '<div class=\"event-meta\"><span>' + time + '<\/span>' + locHtml + '<span class=\"event-type\" style=\"background:' + col.bg + ';color:' + col.text + '\">' + typeLabel + '<\/span>' + impHtml + '<\/div>';\n            html += '<div class=\"expand-body\">' + desc + linkHtml + '<\/div>';\n            html += '<\/div><\/div>';\n          });\n          html += '<\/div>';\n        }\n      });\n      \n      if (html === '' && additionalHidden === 0) {\n        html = '<div class=\"no-events\">No hay eventos para esta fecha.<\/div>';\n      } else if (html === '' && additionalHidden > 0) {\n        html = '<div class=\"no-events\">Solo hay eventos regulares programados. Haz clic abajo para verlos.<\/div>';\n      }\n      \n      if (showOnlyTop && additionalHidden > 0) {\n        html += '<button id=\"im-show-more-btn\" class=\"show-more-btn\">Ver ' + additionalHidden + ' eventos adicionales <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg><\/button>';\n      }\n      \n      return html;\n    }\n\n    function render() {\n      var body = shadow.getElementById('im-body');\n      if(!allEvents.length){ \n        body.innerHTML='<div class=\"no-events\">No se encontraron eventos para este periodo.<\/div>'; \n        return; \n      }\n      \n      var html = '';\n      if (currentView === 'month') {\n        var y = currentDate.getFullYear();\n        var m = currentDate.getMonth();\n        var firstDay = new Date(y, m, 1);\n        var lastDay = new Date(y, m + 1, 0);\n        var startOffset = firstDay.getDay(); \n        var startDate = addDays(firstDay, -startOffset);\n        var totalDays = Math.ceil((lastDay.getDate() + startOffset) \/ 7) * 7;\n        html = renderGrid(startDate, totalDays, true);\n      } \n      else if (currentView === 'week') {\n        var startOfWeek = getStartOfWeek(currentDate);\n        html = renderGrid(startOfWeek, 7, false);\n      } \n      else if (currentView === 'list') {\n        html = renderList(getGroupedEvents());\n      }\n\n      body.innerHTML = html;\n\n      \/\/ ---- ACTIVAR CLICS DE FORMA SEGURA ----\n      \n      shadow.querySelectorAll('.list-card').forEach(function(card) {\n        card.addEventListener('click', function() {\n          this.classList.toggle('open');\n        });\n      });\n\n      shadow.querySelectorAll('.event-mini[data-link]').forEach(function(mini) {\n        mini.addEventListener('click', function(e) {\n          e.stopPropagation();\n          var linkUrl = this.getAttribute('data-link');\n          if (linkUrl) {\n            window.open(linkUrl, '_blank');\n          }\n        });\n      });\n\n      var moreBtn = shadow.getElementById('im-show-more-btn');\n      if (moreBtn) {\n        moreBtn.addEventListener('click', function() {\n          showOnlyTop = false;\n          render();\n        });\n      }\n    }\n\n    function updateTitle(timeMin, timeMax) {\n      var dr = shadow.getElementById('im-date-range');\n      if (currentView === 'month') {\n        dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'});\n      } else if (currentView === 'week') {\n        dr.textContent = timeMin.toLocaleDateString('es-US', {month:'short', day:'numeric'}) + ' - ' + timeMax.toLocaleDateString('es-US', {month:'short', day:'numeric', year:'numeric'});\n      } else {\n        dr.textContent = currentDate.toLocaleDateString('es-US', {month:'long', year:'numeric'}); \n      }\n    }\n\n    function loadEvents(){\n      var body = shadow.getElementById('im-body');\n      body.innerHTML='<div class=\"loading-cal\">Cargando eventos de Miami...<\/div>';\n      \n      var timeMin, timeMax;\n\n      if (currentView === 'month' || currentView === 'list') {\n        var y = currentDate.getFullYear();\n        var m = currentDate.getMonth();\n        var firstDay = new Date(y, m, 1);\n        var lastDay = new Date(y, m + 1, 0);\n        var startOffset = firstDay.getDay();\n        timeMin = addDays(firstDay, -startOffset);\n        timeMax = addDays(lastDay, 6 - lastDay.getDay());\n        timeMax.setHours(23, 59, 59);\n      } else if (currentView === 'week') {\n        timeMin = getStartOfWeek(currentDate);\n        timeMax = addDays(timeMin, 6);\n        timeMax.setHours(23, 59, 59);\n      }\n      \n      updateTitle(timeMin, timeMax);\n      \n      var url='https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/'+encodeURIComponent(CAL_ID)+'\/events?key='+API_KEY+'&timeMin='+timeMin.toISOString()+'&timeMax='+timeMax.toISOString()+'&singleEvents=true&orderBy=startTime&maxResults=250';\n      \n      fetch(url).then(function(r){if(!r.ok)return r.json().then(function(e){throw new Error(e.error&&e.error.message||'HTTP '+r.status);});return r.json();}).then(function(data){\n        allEvents=data.items||[];\n        activeFilter='all';\n        showOnlyTop=true; \n        buildFilters();\n        render();\n      }).catch(function(err){body.innerHTML='<div class=\"error-cal\">Error al cargar el calendario: '+err.message+'<\/div>';});\n    }\n\n    shadow.querySelectorAll('.view-btn').forEach(function(btn){\n      btn.addEventListener('click', function(){\n        shadow.querySelectorAll('.view-btn').forEach(function(b){ b.classList.remove('active'); });\n        btn.classList.add('active');\n        currentView = btn.getAttribute('data-view');\n        loadEvents(); \n      });\n    });\n\n    shadow.getElementById('im-prev-btn').addEventListener('click', function(){\n      if (currentView === 'month' || currentView === 'list') {\n        currentDate.setMonth(currentDate.getMonth() - 1);\n      } else if (currentView === 'week') {\n        currentDate.setDate(currentDate.getDate() - 7);\n      }\n      loadEvents();\n    });\n\n    shadow.getElementById('im-next-btn').addEventListener('click', function(){\n      if (currentView === 'month' || currentView === 'list') {\n        currentDate.setMonth(currentDate.getMonth() + 1);\n      } else if (currentView === 'week') {\n        currentDate.setDate(currentDate.getDate() + 7);\n      }\n      loadEvents();\n    });\n\n    shadow.getElementById('im-today-btn').addEventListener('click', function(){\n      currentDate = new Date();\n      loadEvents();\n    });\n\n    shadow.getElementById('im-print-btn').addEventListener('click', function(){\n      window.print();\n    });\n\n    loadEvents();\n  }\n\n  \/\/ Iniciar el calendario una vez que la p\u00e1gina carga\n  initMiamiCalendar();\n});\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p><iframe loading=\"lazy\" src=\"https:\/\/calendar.google.com\/calendar\/embed?src=7e8c3295deb8d7bb2e675958aa1085c01ef0ae38abafb23b927ec99d74315bcd%40group.calendar.google.com&#038;ctz=America%2FNew_York\" style=\"border: 0\" width=\"800\" height=\"600\" frameborder=\"0\" scrolling=\"no\"><\/iframe><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"publish","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-151","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/pages\/151","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/comments?post=151"}],"version-history":[{"count":26,"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/pages\/151\/revisions"}],"predecessor-version":[{"id":1350,"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/pages\/151\/revisions\/1350"}],"wp:attachment":[{"href":"https:\/\/inmiami.net\/en\/wp-json\/wp\/v2\/media?parent=151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}