{"id":47350,"date":"2026-03-30T20:26:22","date_gmt":"2026-03-31T02:26:22","guid":{"rendered":"https:\/\/themesh.art\/?page_id=47350"},"modified":"2026-04-05T16:13:36","modified_gmt":"2026-04-05T22:13:36","slug":"mapa","status":"publish","type":"page","link":"https:\/\/themesh.art\/en\/mapa\/","title":{"rendered":"Mapa"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"47350\" class=\"elementor elementor-47350\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-21522bf e-flex e-con-boxed e-con e-parent\" data-id=\"21522bf\" data-element_type=\"container\" data-settings=\"{&quot;jet_parallax_layout_list&quot;:[]}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-24e7b29 elementor-widget elementor-widget-html\" data-id=\"24e7b29\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<!--\n\tMESH \u2014 MAPA CULTURAL v10\n\tTemplate: \"Elementor Full Width\"\n\tWPCode: Snippet A (lat\/lng REST) + Snippet B (mesh_build_map_cache)\n\t-->\n\t<style>\n\t\/* \u2500\u2500\u2500 ASTRA RESET \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-overlay, #mesh-overlay * {\n\tbox-sizing: border-box;\n\t-webkit-font-smoothing: antialiased;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n\t}\n\t#mesh-overlay button {\n\tbackground-image: none !important;\n\ttext-transform: none !important;\n\tletter-spacing: normal !important;\n\tline-height: normal !important;\n\tfont-size: inherit !important;\n\tpadding: 0 !important;\n\tborder-style: solid !important;\n\tbox-shadow: none !important;\n\t}\n\t\n\n\t\/* \u2500\u2500\u2500 VARS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t:root {\n\t--mh: 75px; --ab: 0px;\n\t--purple: #7C3AED;\n\t--purple-lt: #EDE9FE;\n\t--ink: #0D0D0D;\n\t--ink2: #3A3A3A;\n\t--ink3: #777;\n\t--border: #111; \/* neobrutalist: hard black borders *\/\n\t--border-lt: #E0DDD8; \/* subtle internal dividers *\/\n\t--bg: #FAFAF7;\n\t--white: #FFFEFC;\n\t--shadow: 3px 3px 0 #111;\n\t--shadow-sm: 2px 2px 0 #111;\n\t}\n\tbody.admin-bar { --ab: 32px; }\n\t@media (max-width: 782px) { body.admin-bar { --ab: 46px; } }\n\t@media (max-width: 860px) { :root { --mh: 50px; } }\n\t\n\n\t\/* \u2500\u2500\u2500 OVERLAY \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-overlay {\n\tposition: fixed;\n\ttop: calc(var(--mh) + var(--ab));\n\tleft: 0; right: 0; bottom: 0;\n\tz-index: 998;\n\tdisplay: flex;\n\toverflow: hidden;\n\tbackground: var(--white);\n\t}\n\t\n\n\t\/* \u2500\u2500\u2500 SIDEBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-sidebar {\n\twidth: 278px; min-width: 278px;\n\theight: 100%;\n\toverflow-y: auto; overflow-x: hidden;\n\tbackground: var(--bg);\n\tborder-right: 2px solid var(--border);\n\tdisplay: flex; flex-direction: column;\n\tflex-shrink: 0;\n\ttransition: transform .26s cubic-bezier(.4,0,.2,1);\n\t}\n\t@media (max-width: 860px) {\n\t#mesh-sidebar {\n\tposition: fixed; left: 0;\n\ttop: calc(var(--mh) + var(--ab)); bottom: 0;\n\twidth: min(290px, 90vw);\n\ttransform: translateX(-110%);\n\tz-index: 9999;\n\tbox-shadow: 6px 0 0 #111;\n\t}\n\t#mesh-sidebar.open { transform: translateX(0); }\n\t}\n\t\n\n\t\/* \u2500\u2500 Name search mobile spacing \u2500\u2500 *\/\n\t@media (max-width: 860px) {\n\t.sb-search-wrap { padding-top: 16px; }\n\t}\n\t\n\n\t\n\n\t\/* \u2500\u2500 Name search wrap \u2500\u2500 *\/\n\t.sb-search-wrap {\n\tposition: relative;\n\tpadding: 12px;\n\tbackground: var(--white);\n\tborder-bottom: 2px solid var(--border);\n\t}\n\t.sb-search-input {\n\twidth: 100% !important;\n\tpadding: 9px 12px !important;\n\tfont-size: 13px !important; font-weight: 500 !important;\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tbackground: var(--white) !important;\n\tcolor: var(--ink) !important;\n\toutline: none !important;\n\t}\n\t.sb-search-input:focus { background: var(--purple-lt) !important; }\n\t.name-results {\n\tdisplay: none;\n\tposition: absolute; left: 12px; right: 12px; top: calc(100% - 4px);\n\tbackground: var(--white);\n\tborder: 2px solid var(--border);\n\tborder-top: none;\n\tz-index: 600;\n\tmax-height: 240px; overflow-y: auto;\n\tbox-shadow: var(--shadow);\n\t}\n\t.name-results.open { display: block; }\n\t.name-result-item {\n\tpadding: 11px 14px !important;\n\tfont-size: 13px !important; font-weight: 500 !important;\n\tcolor: var(--ink) !important;\n\tcursor: pointer !important;\n\tborder-bottom: 1px solid var(--border-lt) !important;\n\tbackground: var(--white) !important;\n\twidth: 100% !important; text-align: left !important;\n\tborder-radius: 0 !important; display: block !important;\n\ttransition: background .1s !important;\n\t}\n\t.name-result-item:last-child { border-bottom: none !important; }\n\t.name-result-item:hover { background: var(--purple-lt) !important; }\n\t.nr-sub { font-size: 10px; color: var(--ink3); margin-top: 2px; font-weight: 400; }\n\t\n\n\t\/* \u2500\u2500 Sidebar header \u2500\u2500 *\/\n\t.sb-hd {\n\tpadding: 18px 16px 14px;\n\tborder-bottom: 2px solid var(--border);\n\tdisplay: flex; align-items: flex-start;\n\tjustify-content: space-between;\n\tbackground: var(--white);\n\tposition: sticky; top: 0; z-index: 10;\n\t}\n\t.sb-eyebrow {\n\tfont-size: 9px; font-weight: 800;\n\tletter-spacing: .2em; text-transform: uppercase;\n\tcolor: var(--ink3); margin-bottom: 4px; display: block;\n\t}\n\t.sb-count-wrap { display: flex; align-items: baseline; gap: 5px; }\n\t.sb-num { font-size: 36px; font-weight: 800; color: var(--ink); line-height: 1; letter-spacing: -.04em; }\n\t.sb-unit { font-size: 12px; color: var(--ink3); font-weight: 400; }\n\t\n\n\t.sb-x {\n\tdisplay: none !important;\n\twidth: 30px !important; height: 30px !important;\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tbackground: var(--white) !important;\n\tcolor: var(--ink) !important;\n\tfont-size: 14px !important; font-weight: 700 !important;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;\n\tcursor: pointer !important;\n\talign-items: center !important; justify-content: center !important;\n\tflex-shrink: 0 !important; margin-top: 4px !important;\n\tpadding: 0 !important; line-height: 1 !important;\n\tbox-shadow: none !important;\n\ttransition: all .15s !important;\n\t}\n\t@media (max-width: 860px) { .sb-x { display: flex !important; } }\n\t.sb-x:hover { background: var(--ink) !important; color: var(--white) !important; }\n\t\n\n\t\/* \u2500\u2500 Section \u2500\u2500 *\/\n\t.sb-sec { padding: 14px 16px; border-bottom: 1px solid var(--border-lt); }\n\t.sb-sec-lbl {\n\tfont-size: 8px; font-weight: 800;\n\tletter-spacing: .22em; text-transform: uppercase;\n\tcolor: var(--ink3); margin-bottom: 10px; display: block;\n\t}\n\t\n\n\t\/* \u2500\u2500 Searchable dropdown \u2500\u2500 *\/\n\t.mesh-sel { position: relative; }\n\t.mesh-sel-trigger {\n\twidth: 100%;\n\tdisplay: flex !important; align-items: center !important;\n\tjustify-content: space-between !important;\n\tpadding: 10px 12px !important;\n\tbackground: var(--white) !important;\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tcolor: var(--ink) !important; font-size: 13px !important;\n\tfont-weight: 500 !important;\n\tcursor: pointer !important; text-align: left !important;\n\ttransition: background .12s !important;\n\t}\n\t.mesh-sel-trigger:hover { background: var(--bg) !important; }\n\t.mesh-sel-trigger.open {\n\tbackground: var(--purple-lt) !important;\n\tborder-color: var(--purple) !important;\n\t}\n\t.mesh-sel-val { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\t.mesh-sel-val.ph { color: var(--ink3); font-weight: 400; }\n\t.mesh-sel-arrow {\n\tdisplay: flex; align-items: center; justify-content: center;\n\tmargin-left: 8px; flex-shrink: 0;\n\ttransition: transform .18s; color: var(--ink3);\n\twidth: 16px; height: 16px;\n\t}\n\t.mesh-sel-trigger.open .mesh-sel-arrow { transform: rotate(180deg); }\n\t\n\n\t.mesh-sel-panel {\n\tdisplay: none;\n\tposition: absolute; top: 100%; left: 0; right: 0;\n\tbackground: var(--white);\n\tborder: 2px solid var(--purple);\n\tborder-top: none;\n\tz-index: 500;\n\tmax-height: 280px; overflow: hidden;\n\tflex-direction: column;\n\tbox-shadow: var(--shadow);\n\t}\n\t.mesh-sel-panel.open { display: flex; }\n\t\n\n\t.mesh-sel-search-wrap {\n\tpadding: 10px 12px; border-bottom: 1px solid var(--border-lt); flex-shrink: 0;\n\t}\n\t.mesh-sel-search {\n\twidth: 100% !important; padding: 8px 10px !important;\n\tfont-size: 12px !important; font-weight: 500 !important;\n\tborder: 2px solid var(--border-lt) !important; border-radius: 0 !important;\n\tbackground: var(--bg) !important; color: var(--ink) !important; outline: none !important;\n\t}\n\t.mesh-sel-search:focus { border-color: var(--purple) !important; background: var(--white) !important; }\n\t\n\n\t.mesh-sel-opts { overflow-y: auto; flex: 1; }\n\t.mesh-sel-opt {\n\tdisplay: flex !important; align-items: center !important;\n\tgap: 10px !important; padding: 14px 16px !important;\n\tcursor: pointer !important; font-size: 13px !important;\n\tfont-weight: 500 !important; color: var(--ink) !important;\n\tbackground: var(--white) !important; border: none !important;\n\twidth: 100% !important; text-align: left !important;\n\tborder-bottom: 1px solid var(--border-lt) !important;\n\tborder-radius: 0 !important; transition: background .1s !important;\n\tmin-height: 44px !important;\n\t}\n\t.mesh-sel-opt:last-child { border-bottom: none !important; }\n\t.mesh-sel-opt:hover { background: var(--bg) !important; }\n\t.mesh-sel-opt.active {\n\tbackground: var(--purple-lt) !important;\n\tcolor: var(--purple) !important; font-weight: 700 !important;\n\t}\n\t.mesh-sel-opt-count {\n\tmargin-left: auto; font-size: 11px; color: var(--ink3);\n\tflex-shrink: 0; font-weight: 400;\n\t}\n\t.tipo-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n\t\n\n\t\/* \u2500\u2500 Toggle \u2500\u2500 *\/\n\t.toggle-row {\n\tdisplay: flex; align-items: center;\n\tjustify-content: space-between;\n\tpadding: 13px 16px;\n\tborder-bottom: 1px solid var(--border-lt);\n\t}\n\t.toggle-label { font-size: 13px; color: var(--ink2); font-weight: 500; }\n\t.toggle-sw { position: relative; width: 38px; height: 22px; flex-shrink: 0; }\n\t.toggle-sw input { opacity: 0; width: 0; height: 0; position: absolute; }\n\t.toggle-track {\n\tposition: absolute; inset: 0; background: #ccc;\n\tborder-radius: 0; cursor: pointer; transition: background .2s;\n\tborder: 2px solid var(--border);\n\t}\n\t.toggle-sw input:checked + .toggle-track { background: var(--purple); border-color: var(--purple); }\n\t.toggle-track::after {\n\tcontent: ''; position: absolute; top: 2px; left: 2px;\n\twidth: 14px; height: 14px; background: var(--white);\n\tborder: 1px solid rgba(0,0,0,.2);\n\ttransition: transform .2s;\n\t}\n\t.toggle-sw input:checked + .toggle-track::after { transform: translateX(16px); }\n\t\n\n\t\/* \u2500\u2500 Filter active \u2500\u2500 *\/\n\t.filter-pill {\n\tdisplay: none; align-items: center; gap: 6px;\n\tpadding: 8px 16px; border-bottom: 1px solid var(--border-lt);\n\tbackground: var(--purple-lt); font-size: 11px;\n\tcolor: var(--purple); font-weight: 700; letter-spacing: .04em;\n\t}\n\t.filter-pill.show { display: flex; }\n\t.filter-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--purple); flex-shrink: 0; }\n\t\n\n\t\/* \u2500\u2500 Reset \u2014 text only, no box \u2500\u2500 *\/\n\t.rst-btn {\n\tdisplay: block !important; background: none !important;\n\tborder: none !important; outline: none !important;\n\tpadding: 14px 16px !important; font-size: 12px !important;\n\tcolor: var(--ink3) !important; cursor: pointer !important;\n\ttext-decoration: underline !important; text-underline-offset: 3px !important;\n\ttext-align: left !important; width: 100% !important; font-weight: 500 !important;\n\tbox-shadow: none !important; border-radius: 0 !important;\n\t}\n\t.rst-btn:hover { color: var(--ink) !important; }\n\t\n\n\t\/* \u2500\u2500\u2500 MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-mapwrap { flex: 1; position: relative; overflow: hidden; height: 100%; }\n\t#mesh-map { position: absolute; inset: 0; }\n\t.leaflet-control-attribution { display: none !important; }\n\t\n\n\t\/* \u2500\u2500\u2500 LEAFLET CONTROLS (neobrutalist) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t.leaflet-control-zoom {\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tbox-shadow: var(--shadow) !important;\n\t}\n\t.leaflet-control-zoom a {\n\tfont-family: -apple-system, sans-serif !important;\n\tborder-radius: 0 !important;\n\tborder-bottom: 1px solid var(--border-lt) !important;\n\tfont-weight: 700 !important; color: var(--ink) !important;\n\twidth: 30px !important; height: 30px !important; line-height: 28px !important;\n\t}\n\t.leaflet-control-zoom a:hover { background: var(--bg) !important; }\n\t\n\n\t\/* \u2500\u2500 Geo button \u2014 hidden on mobile until Natively geolocation configured \u2500\u2500 *\/\n\t#geo-btn {\n\tposition: absolute;\n\tbottom: 80px; right: 10px;\n\twidth: 30px; height: 30px;\n\tbackground: var(--white) !important;\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tcursor: pointer !important;\n\tz-index: 1000;\n\tdisplay: flex !important; align-items: center !important; justify-content: center !important;\n\tbox-shadow: 2px 2px 0 var(--border) !important;\n\ttransition: background .15s !important;\n\tpadding: 0 !important;\n\t}\n\t#geo-btn:hover { background: var(--bg) !important; }\n\t#geo-btn.active { background: var(--purple-lt) !important; border-color: var(--purple) !important; box-shadow: 2px 2px 0 var(--purple) !important; }\n\t@media (max-width: 860px) { #geo-btn { display: none !important; } }\n\t.geo-ring {\n\twidth: 14px; height: 14px; border-radius: 50%;\n\tborder: 2px solid var(--purple);\n\tdisplay: flex; align-items: center; justify-content: center;\n\t}\n\t.geo-ring-dot {\n\twidth: 5px; height: 5px; border-radius: 50%;\n\tbackground: var(--purple);\n\ttransition: transform .2s;\n\t}\n\t#geo-btn.active .geo-ring {\n\tbox-shadow: 0 0 0 3px var(--purple-lt);\n\t}\n\t\n\n\t\/* \u2500\u2500\u2500 LOADING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-loading {\n\tposition: absolute; inset: 0;\n\tbackground: rgba(255,254,252,.95);\n\tdisplay: flex; flex-direction: column;\n\talign-items: center; justify-content: center; gap: 14px;\n\tz-index: 1000; transition: opacity .4s;\n\t}\n\t#mesh-loading.hide { opacity: 0; pointer-events: none; }\n\t.ld-spinner {\n\twidth: 24px; height: 24px;\n\tborder: 3px solid var(--border-lt); border-top-color: var(--purple);\n\tborder-radius: 50%; animation: spin .8s linear infinite;\n\t}\n\t.ld-text { font-size: 12px; font-weight: 600; color: var(--ink3); letter-spacing: .06em; text-transform: uppercase; }\n\t@keyframes spin { to { transform: rotate(360deg); } }\n\t\n\n\t\/* \u2500\u2500\u2500 DETAIL CARD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-detail {\n\tposition: absolute; top: 0; right: 0;\n\theight: 100%; width: 316px;\n\ttransform: translateX(100%);\n\ttransition: transform .28s cubic-bezier(.4,0,.2,1);\n\toverflow: hidden;\n\tbackground: var(--white);\n\tborder-left: 2px solid var(--border);\n\tz-index: 1001; \/* above zoom + geo controls (z-index 1000) *\/\n\tdisplay: flex; flex-direction: column;\n\t}\n\t#mesh-detail.open { transform: translateX(0); }\n\t\n\n\t@media (max-width: 640px) {\n\t#mesh-detail {\n\twidth: 100%; top: auto; bottom: 0; height: 72%;\n\ttransform: translateY(100%);\n\tborder-left: none; border-top: 2px solid var(--border);\n\tborder-radius: 0;\n\t}\n\t#mesh-detail.open { transform: translateY(0); }\n\t}\n\t\n\n\t.d-imgwrap {\n\twidth: 100%; height: 160px; flex-shrink: 0;\n\tposition: relative; overflow: hidden;\n\tdisplay: flex; align-items: center; justify-content: center;\n\tbackground: var(--bg); border-bottom: 2px solid var(--border);\n\t}\n\t@media (max-width: 640px) { .d-imgwrap { height: 150px; } }\n\t\n\n\t\/* Handle strip \u2014 removed entirely *\/\n\t.d-handle { display: none !important; }\n\t.d-mob-x { display: none !important; }\n\t\n\n\t.d-cover { width: 100%; height: 100%; object-fit: cover; display: block; position: absolute; inset: 0; }\n\t.d-initial { font-size: 72px; font-weight: 900; opacity: .06; color: var(--ink); line-height: 1; user-select: none; }\n\t\n\n\t\/* X button \u2014 always visible, overlaid on image top-right *\/\n\t.d-x {\n\tposition: absolute; top: 10px; right: 10px;\n\twidth: 30px; height: 30px;\n\tborder: 2px solid rgba(0,0,0,.3) !important;\n\tborder-radius: 0 !important;\n\tbackground: rgba(255,255,255,.92) !important;\n\tcolor: var(--ink) !important; font-size: 13px !important;\n\tfont-weight: 800 !important; cursor: pointer !important;\n\tdisplay: flex !important; align-items: center !important;\n\tjustify-content: center !important; z-index: 10 !important;\n\ttransition: all .12s !important;\n\t}\n\t.d-x:hover { background: var(--ink) !important; color: var(--white) !important; }\n\t\n\n\t\/* Body \u2014 compact gaps to avoid overlap *\/\n\t.d-body {\n\tpadding: 12px 14px 14px;\n\tdisplay: flex; flex-direction: column; gap: 8px;\n\toverflow-y: auto; flex: 1; min-height: 0;\n\t}\n\t\n\n\t\/* Mobile: clamp desc, cap disciplines *\/\n\t@media (max-width: 640px) {\n\t.d-desc {\n\tdisplay: -webkit-box;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n\toverflow: hidden;\n\t}\n\t.d-disc { max-height: 30px; overflow: hidden; }\n\t.d-badge { font-size: 8px; padding: 3px 7px; }\n\t.d-nombre { font-size: 17px; }\n\t.d-addr { font-size: 11px; }\n\t}\n\t\n\n\t.d-cats { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }\n\t.d-badge {\n\tfont-size: 8px; font-weight: 800;\n\tletter-spacing: .1em; padding: 4px 9px;\n\ttext-transform: uppercase; border: 1px solid currentColor;\n\t}\n\t.bg-galeria { background:#FEF3E8; color:#9A3412; } \/* orange *\/\n\t.bg-museo { background:#EFF6FF; color:#1E40AF; } \/* deep blue *\/\n\t.bg-ind { background:#ECFDF5; color:#065F46; } \/* emerald *\/\n\t.bg-cultural { background:#F5F3FF; color:#5B21B6; } \/* purple *\/\n\t.bg-taller { background:#FFFBEB; color:#92400E; } \/* gold\/amber *\/\n\t.bg-inst { background:#FEF3E8; color:#7C2D12; } \/* burnt sienna *\/\n\t.bg-educ { background:#F0F9FF; color:#075985; } \/* sky blue *\/\n\t.bg-res { background:#FDF2F8; color:#9D174D; } \/* deep pink *\/\n\t.bg-conc { background:#F5F3FF; color:#4C1D95; } \/* deep violet *\/\n\t.bg-teatro { background:#F0FDFA; color:#0F766E; } \/* teal *\/\n\t.bg-fest { background:#FFF1F2; color:#B91C1C; } \/* red *\/\n\t.bg-fund { background:#EFF6FF; color:#1E3A5F; } \/* navy *\/\n\t.bg-col { background:#ECFDF5; color:#065F46; } \/* dark green *\/\n\t.bg-est { background:#F5F5F4; color:#57534E; } \/* stone *\/\n\t.bg-arq { background:#FEFCE8; color:#78350F; } \/* brown *\/\n\t.bg-ent { background:#FFF7ED; color:#C2410C; } \/* amber *\/\n\t.bg-sv { background:#F8FAFC; color:#475569; } \/* slate *\/\n\t.bg-default { background:#F5F5F5; color:#444; }\n\t\n\n\t.d-city { font-size: 11px; color: var(--ink3); margin-left: auto; padding-left: 8px; font-weight: 500; }\n\t.d-nombre { font-size: 19px; font-weight: 700; color: var(--ink); line-height: 1.2; letter-spacing: -.02em; }\n\t.d-addr { font-size: 12px; color: var(--ink3); line-height: 1.5; }\n\t.d-desc { font-size: 13px; color: var(--ink2); line-height: 1.65; }\n\t\n\n\t.d-disc { display: flex; flex-wrap: wrap; gap: 5px; }\n\t.d-tag {\n\tfont-size: 11px; padding: 4px 8px;\n\tborder: 1px solid var(--border-lt); color: var(--ink3);\n\tfont-weight: 500;\n\t}\n\t\n\n\t.d-cta {\n\tdisplay: block !important; text-align: center !important;\n\tpadding: 12px 16px !important;\n\tbackground: var(--purple) !important; color: var(--white) !important;\n\tborder: 2px solid var(--border) !important; border-radius: 0 !important;\n\tfont-size: 13px !important; font-weight: 700 !important;\n\tcursor: pointer !important; text-decoration: none !important;\n\tletter-spacing: .02em !important;\n\ttransition: background .15s !important;\n\tbox-shadow: var(--shadow-sm) !important;\n\tmargin-top: 6px !important;\n\t}\n\t.d-cta:hover { background: var(--ink) !important; color: var(--white) !important; box-shadow: none !important; transform: translate(2px,2px) !important; }\n\t\n\n\t\/* \u2500\u2500 Sidebar right-edge handle (mobile) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#sb-pull-bar { display: none !important; } \/* remove top handle *\/\n\t\n\n\t#sb-edge-handle {\n\tdisplay: none;\n\tposition: fixed;\n\ttop: calc(var(--mh) + var(--ab));\n\tbottom: 0;\n\tleft: min(290px, 88vw); \/* right edge of sidebar *\/\n\twidth: 18px;\n\tbackground: var(--border);\n\tz-index: 9998; \/* just below sidebar *\/\n\talign-items: center; justify-content: center;\n\tcursor: grab;\n\t}\n\t#sb-edge-handle::after {\n\tcontent: '';\n\twidth: 3px; height: 28px;\n\tbackground: rgba(255,255,255,.55); border-radius: 2px;\n\t}\n\t\/* shown only when sidebar is open on mobile *\/\n\t#sb-edge-handle.show { display: flex; }\n\t\n\n\t\/* \u2500\u2500 Dropdown item spacing \u2500\u2500 *\/\n\t.mesh-sel-opt {\n\tpadding: 13px 16px !important;\n\tmin-height: 46px !important;\n\tline-height: 1.4 !important;\n\t}\n\t.mesh-sel-opt-count {\n\tmargin-left: auto; font-size: 11px; color: var(--ink3);\n\tflex-shrink: 0; font-weight: 400;\n\tpadding-left: 10px !important;\n\t}\n\t.mesh-sel-trigger {\n\tpadding: 11px 14px !important;\n\t}\n\t.mesh-sel-search {\n\tpadding: 9px 12px !important;\n\tmargin: 0 !important;\n\t}\n\t#mob-filter {\n\tdisplay: none !important;\n\tposition: fixed !important; bottom: 20px; left: 50% !important;\n\ttransform: translateX(-50%) !important;\n\tbackground: var(--purple) !important;\n\tcolor: var(--white) !important;\n\tborder: 2px solid var(--border) !important;\n\tborder-radius: 0 !important;\n\tpadding: 13px 28px !important;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;\n\tfont-size: 15px !important; font-weight: 800 !important;\n\tletter-spacing: .06em !important;\n\ttext-transform: uppercase !important;\n\tcursor: pointer !important; z-index: 10000 !important;\n\tbox-shadow: 4px 4px 0 var(--border) !important;\n\twhite-space: nowrap !important;\n\tpointer-events: all !important;\n\tline-height: normal !important;\n\ttransition: background .15s !important;\n\t}\n\t@media (max-width: 860px) { #mob-filter { display: block !important; } }\n\t#mob-filter:hover { background: var(--ink) !important; transform: translate(2px,2px) !important; box-shadow: 2px 2px 0 var(--border) !important; }\n\t\n\n\t\/* \u2500\u2500\u2500 BACKDROP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\t#mesh-bd {\n\tdisplay: none; position: fixed;\n\ttop: calc(var(--mh) + var(--ab)); left: 0; right: 0; bottom: 0;\n\tbackground: rgba(0,0,0,.45); z-index: 9998;\n\t}\n\t@media (max-width: 860px) { #mesh-bd.show { display: block; } }\n\t<\/style>\n\t\n\n\t<!-- \u2500\u2500 HTML \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n\t<div id=\"mesh-overlay\">\n\t\n\n\t<!-- \u2500\u2500 SIDEBAR \u2500\u2500 -->\n\t<aside id=\"mesh-sidebar\">\n\t<!-- Pull bar \u2014 mobile swipe indicator -->\n\t<div id=\"sb-pull-bar\"><\/div>\n\t\n\n\t<!-- Header \/ counter -->\n\t<div class=\"sb-hd\">\n\t<div>\n\t<span class=\"sb-eyebrow\">Mapa cultural<\/span>\n\t<div class=\"sb-count-wrap\">\n\t<span class=\"sb-num\" id=\"sb-num\">\u2014<\/span>\n\t<span class=\"sb-unit\">espacios<\/span>\n\t<\/div>\n\t<\/div>\n\t<button class=\"sb-x\" id=\"sb-x\">\u2715<\/button>\n\t<\/div>\n\t\n\n\t<!-- Name search \u2014 below counter, in filters area -->\n\t<div class=\"sb-sec\" style=\"position:relative\">\n\t<span class=\"sb-sec-lbl\">Buscar por nombre<\/span>\n\t<div style=\"position:relative\">\n\t<input class=\"sb-search-input\" id=\"name-search\" type=\"text\"\n\tplaceholder=\"Nombre del espacio\u2026\" autocomplete=\"off\">\n\t<\/div>\n\t<div class=\"name-results\" id=\"name-results\"><\/div>\n\t<\/div>\n\t\n\n\t<!-- Lugar (was Ciudad) \u2014 first -->\n\t<div class=\"sb-sec\">\n\t<span class=\"sb-sec-lbl\">Lugar<\/span>\n\t<div class=\"mesh-sel\">\n\t<button class=\"mesh-sel-trigger\" id=\"ciudad-trigger\">\n\t<span class=\"mesh-sel-val ph\" id=\"ciudad-val\">Todos los lugares<\/span>\n\t<span class=\"mesh-sel-arrow\"><svg width=\"14\" height=\"8\" viewbox=\"0 0 14 8\" fill=\"none\"><path d=\"M1 1l6 6 6-6\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n\t<\/button>\n\t<div class=\"mesh-sel-panel\" id=\"ciudad-panel\">\n\t<div class=\"mesh-sel-search-wrap\">\n\t<input class=\"mesh-sel-search\" id=\"ciudad-search\" type=\"text\" placeholder=\"Buscar lugar\u2026\" autocomplete=\"off\">\n\t<\/div>\n\t<div class=\"mesh-sel-opts\" id=\"ciudad-opts\"><\/div>\n\t<\/div>\n\t<\/div>\n\t<\/div>\n\t\n\n\t<!-- Tipo \u2014 second -->\n\t<div class=\"sb-sec\">\n\t<span class=\"sb-sec-lbl\">Tipo de espacio<\/span>\n\t<div class=\"mesh-sel\">\n\t<button class=\"mesh-sel-trigger\" id=\"tipo-trigger\">\n\t<span class=\"mesh-sel-val ph\" id=\"tipo-val\">Todos los tipos<\/span>\n\t<span class=\"mesh-sel-arrow\"><svg width=\"14\" height=\"8\" viewbox=\"0 0 14 8\" fill=\"none\"><path d=\"M1 1l6 6 6-6\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n\t<\/button>\n\t<div class=\"mesh-sel-panel\" id=\"tipo-panel\">\n\t<div class=\"mesh-sel-search-wrap\">\n\t<input class=\"mesh-sel-search\" id=\"tipo-search\" type=\"text\" placeholder=\"Buscar tipo\u2026\" autocomplete=\"off\">\n\t<\/div>\n\t<div class=\"mesh-sel-opts\" id=\"tipo-opts\"><\/div>\n\t<\/div>\n\t<\/div>\n\t<\/div>\n\t\n\n\t<!-- Disciplina \u2014 third -->\n\t<div class=\"sb-sec\">\n\t<span class=\"sb-sec-lbl\">Disciplina<\/span>\n\t<div class=\"mesh-sel\">\n\t<button class=\"mesh-sel-trigger\" id=\"disc-trigger\">\n\t<span class=\"mesh-sel-val ph\" id=\"disc-val\">Todas las disciplinas<\/span>\n\t<span class=\"mesh-sel-arrow\"><svg width=\"14\" height=\"8\" viewbox=\"0 0 14 8\" fill=\"none\"><path d=\"M1 1l6 6 6-6\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n\t<\/button>\n\t<div class=\"mesh-sel-panel\" id=\"disc-panel\">\n\t<div class=\"mesh-sel-search-wrap\">\n\t<input class=\"mesh-sel-search\" id=\"disc-search\" type=\"text\" placeholder=\"Buscar disciplina\u2026\" autocomplete=\"off\">\n\t<\/div>\n\t<div class=\"mesh-sel-opts\" id=\"disc-opts\"><\/div>\n\t<\/div>\n\t<\/div>\n\t<\/div>\n\t\n\n\t\n\n\t<!-- Active filter pill -->\n\t<div class=\"filter-pill\" id=\"filter-pill\">\n\t<span class=\"filter-dot\"><\/span>\n\tFiltro activo\n\t<\/div>\n\t\n\n\t<div id=\"rst-btn\" role=\"button\" tabindex=\"0\"\n\tstyle=\"display:block;padding:14px 16px;font-size:12px;color:#888;cursor:pointer;text-decoration:underline;text-underline-offset:3px;text-align:left;font-weight:500;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;\">\n\tLimpiar filtros\n\t<\/div>\n\t\n\n\t<!-- Sidebar swipe handle \u2014 mobile only -->\n\t<div id=\"sb-drag-tip\"><\/div>\n\t<\/aside>\n\t\n\n\t<!-- \u2500\u2500 MAP \u2500\u2500 -->\n\t<div id=\"mesh-mapwrap\">\n\t<div id=\"mesh-bd\"><\/div>\n\t<div id=\"mesh-map\"><\/div>\n\t\n\n\t<!-- Loading -->\n\t<div id=\"mesh-loading\">\n\t<div class=\"ld-spinner\"><\/div>\n\t<div class=\"ld-text\" id=\"ld-text\">Cargando\u2026<\/div>\n\t<\/div>\n\t\n\n\t<!-- Space card -->\n\t<div id=\"mesh-detail\">\n\t<div class=\"d-imgwrap\" id=\"d-imgwrap\">\n\t<button class=\"d-x\" id=\"d-x\">\u2715<\/button>\n\t<span class=\"d-initial\" id=\"d-initial\">G<\/span>\n\t<\/div>\n\t<div class=\"d-body\">\n\t<div class=\"d-cats\" id=\"d-cats\"><\/div>\n\t<div>\n\t<div class=\"d-nombre\" id=\"d-nombre\"><\/div>\n\t<div class=\"d-addr\" id=\"d-addr\"><\/div>\n\t<\/div>\n\t<div class=\"d-desc\" id=\"d-desc\"><\/div>\n\t<div class=\"d-disc\" id=\"d-disc\"><\/div>\n\t<a class=\"d-cta\" id=\"d-cta\" href=\"#\" target=\"_blank\" rel=\"noopener\">Ver espacio \u2192<\/a>\n\t<\/div>\n\t<\/div>\n\t\n\n\t<!-- Geo button \u2014 reliable native button above zoom controls -->\n\t<button id=\"geo-btn\" title=\"Ir a mi ubicaci\u00f3n\">\n\t<span class=\"geo-ring\"><span class=\"geo-ring-dot\"><\/span><\/span>\n\t<\/button>\n\t\n\n\t<!-- Mobile filter button -->\n\t<button id=\"mob-filter\" style=\"text-transform:uppercase;padding:13px 28px;letter-spacing:.06em;font-family:'Barlow Condensed',sans-serif;font-weight:800;font-size:15px;line-height:normal;\">\u2261 FILTROS<\/button>\n\t<\/div>\n\t<!-- Sidebar edge handle -->\n\t<div id=\"sb-edge-handle\" aria-hidden=\"true\"><\/div>\n\t<\/div>\n\t\n\n\t<!-- \u2500\u2500 LEAFLET \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n\t<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet\/1.9.4\/leaflet.min.css\">\n\t<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet.markercluster\/1.5.3\/MarkerCluster.min.css\">\n\t<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet.markercluster\/1.5.3\/MarkerCluster.Default.min.css\">\n\t<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet\/1.9.4\/leaflet.min.js\"><\/script>\n\t<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/leaflet.markercluster\/1.5.3\/leaflet.markercluster.min.js\"><\/script>\n\t\n\n\t<script>\n\t(function () {\n\t'use strict';\n\t\n\n\tconst API = '\/wp-json\/mesh\/v1\/map-venues';\n\t\n\n\t\/\/ \u2500\u2500 TIPO COLOR SYSTEM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\t\/\/ Each tipo gets a unique, highly distinguishable color.\n\t\/\/ Rationale: warm vs cool hues + varied brightness so no two look alike on the map.\n\tconst TIPO_COLOR = {\n\t'Galer\u00eda': '#E85D04', \/\/ vivid orange \u2014 art energy, warmth\n\t'Museo': '#1E40AF', \/\/ deep blue \u2014 institutional, established\n\t'Espacio Independiente': '#059669', \/\/ emerald \u2014 organic, alternative\n\t'Centro Cultural': '#7C3AED', \/\/ mesh purple \u2014 community, civic identity\n\t'Taller': '#CA8A04', \/\/ golden yellow \u2014 craft, making, tools\n\t'Instituto': '#9A3412', \/\/ burnt sienna \u2014 academic, heritage\n\t'Educaci\u00f3n': '#0284C7', \/\/ sky blue \u2014 learning, clarity\n\t'Residencias': '#BE185D', \/\/ deep pink \u2014 intimate, dwelling\n\t'Sala de Conciertos': '#4C1D95', \/\/ deep violet \u2014 sound, night, performance\n\t'Teatro': '#0F766E', \/\/ teal \u2014 drama, stage\n\t'Festival': '#DC2626', \/\/ red \u2014 celebration, event, energy\n\t'Fundaci\u00f3n': '#1E3A5F', \/\/ navy \u2014 patronage, gravitas\n\t'Colectivo': '#065F46', \/\/ dark green \u2014 collective, grassroots\n\t'Estudio': '#78716C', \/\/ stone gray \u2014 work, neutral\n\t'Arquitectura': '#78350F', \/\/ dark brown \u2014 building, structure\n\t'Entretenimiento': '#B45309', \/\/ amber \u2014 entertainment, stage lights\n\t'Servicios Culturales': '#4B5563', \/\/ slate \u2014 support infrastructure\n\t'default': '#7C3AED', \/\/ mesh purple\n\t};\n\t\n\n\t\/\/ SVG icon paths for each tipo (12\u00d712 viewBox, white fill\/stroke)\n\tconst TIPO_ICON = {\n\t'Galer\u00eda':\n\t'<rect x=\"1.5\" y=\"1.5\" width=\"9\" height=\"9\" stroke=\"white\" stroke-width=\"1.5\" fill=\"none\"\/><rect x=\"3.5\" y=\"3.5\" width=\"5\" height=\"4\" stroke=\"white\" stroke-width=\"1\" fill=\"none\"\/>',\n\t'Museo':\n\t'<path d=\"M1 5.5L6 2L11 5.5Z\" fill=\"white\" opacity=\".9\"\/><rect x=\"2.5\" y=\"5.5\" width=\"1.5\" height=\"4.5\" fill=\"white\"\/><rect x=\"5.25\" y=\"5.5\" width=\"1.5\" height=\"4.5\" fill=\"white\"\/><rect x=\"8\" y=\"5.5\" width=\"1.5\" height=\"4.5\" fill=\"white\"\/><rect x=\"1\" y=\"10\" width=\"10\" height=\"1.2\" fill=\"white\"\/>',\n\t'Espacio Independiente':\n\t'<path d=\"M6 1L11 6L6 11L1 6Z\" stroke=\"white\" stroke-width=\"1.5\" fill=\"none\"\/>',\n\t'Centro Cultural':\n\t'<path d=\"M6 1.2L7.3 4.7H11L8.2 6.9L9.2 10.4L6 8.3L2.8 10.4L3.8 6.9L1 4.7H4.7Z\" fill=\"white\" opacity=\".9\"\/>',\n\t'Taller':\n\t'<path d=\"M9 1.5C7.2 1.5 6 2.9 6 4.5c0 .4.1.8.3 1.1L2 9.8C2 10.7 2.8 11 3.2 10.4L7.4 6.3C7.7 6.4 8 6.5 8.5 6.5 10.3 6.5 11.5 5 11.5 3.5L9.8 5.2 7.5 3 9 1.5Z\" fill=\"white\" opacity=\".9\"\/>',\n\t'Instituto':\n\t'<path d=\"M2 10V4.5L6 2l4 2.5V10\" stroke=\"white\" stroke-width=\"1.3\" fill=\"none\"\/><path d=\"M4.5 10V7.5h3V10\" stroke=\"white\" stroke-width=\"1.2\" fill=\"none\"\/><line x1=\"1\" y1=\"10\" x2=\"11\" y2=\"10\" stroke=\"white\" stroke-width=\"1.4\"\/>',\n\t'Educaci\u00f3n':\n\t'<path d=\"M6 2.5L1 5.5l5 2.5 5-2.5L6 2.5Z\" stroke=\"white\" stroke-width=\"1.3\" fill=\"none\"\/><path d=\"M3 7v2.5\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"\/><line x1=\"2\" y1=\"9.5\" x2=\"4\" y2=\"9.5\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"\/><path d=\"M9 6.8V9\" stroke=\"white\" stroke-width=\"1.2\" stroke-dasharray=\"1 1.2\"\/>',\n\t'Residencias':\n\t'<path d=\"M1.5 6.5L6 2l4.5 4.5\" stroke=\"white\" stroke-width=\"1.4\" fill=\"none\"\/><rect x=\"3.5\" y=\"6.5\" width=\"5\" height=\"4\" stroke=\"white\" stroke-width=\"1.3\" fill=\"none\"\/><rect x=\"5\" y=\"8\" width=\"2\" height=\"2.5\" stroke=\"white\" stroke-width=\"1\" fill=\"none\"\/>',\n\t'Sala de Conciertos':\n\t'<line x1=\"8.5\" y1=\"2\" x2=\"8.5\" y2=\"7.5\" stroke=\"white\" stroke-width=\"1.5\"\/><line x1=\"5.5\" y1=\"3.5\" x2=\"5.5\" y2=\"9\" stroke=\"white\" stroke-width=\"1.5\"\/><ellipse cx=\"4\" cy=\"9\" rx=\"1.5\" ry=\"1\" stroke=\"white\" stroke-width=\"1.2\" fill=\"none\"\/><ellipse cx=\"7\" cy=\"7.5\" rx=\"1.5\" ry=\"1\" stroke=\"white\" stroke-width=\"1.2\" fill=\"none\"\/><line x1=\"5.5\" y1=\"3.5\" x2=\"8.5\" y2=\"2\" stroke=\"white\" stroke-width=\"1.2\"\/>',\n\t'Teatro':\n\t'<path d=\"M2 3C2 7.5 3.5 10 6 10s4-2.5 4-7\" stroke=\"white\" stroke-width=\"1.5\" fill=\"none\" stroke-linecap=\"round\"\/><line x1=\"1\" y1=\"2.5\" x2=\"11\" y2=\"2.5\" stroke=\"white\" stroke-width=\"1.5\"\/><path d=\"M3.5 10C4 11 5 11.5 6 11.5s2-.5 2.5-1.5\" stroke=\"white\" stroke-width=\"1.2\" fill=\"none\" stroke-linecap=\"round\"\/>',\n\t'Festival':\n\t'<line x1=\"2.5\" y1=\"1.5\" x2=\"2.5\" y2=\"11\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"\/><path d=\"M2.5 2.5L9.5 4.8L2.5 7.5Z\" fill=\"white\" opacity=\".9\"\/>',\n\t'Fundaci\u00f3n':\n\t'<path d=\"M6 1.5L10.5 3.5V7.5C10.5 9.8 8.5 11.2 6 11.5 3.5 11.2 1.5 9.8 1.5 7.5V3.5L6 1.5Z\" stroke=\"white\" stroke-width=\"1.4\" fill=\"none\"\/>',\n\t'Colectivo':\n\t'<circle cx=\"4\" cy=\"4\" r=\"1.5\" fill=\"white\" opacity=\".9\"\/><circle cx=\"8\" cy=\"4\" r=\"1.5\" fill=\"white\" opacity=\".9\"\/><circle cx=\"6\" cy=\"8.5\" r=\"1.5\" fill=\"white\" opacity=\".9\"\/><line x1=\"4\" y1=\"5.5\" x2=\"6\" y2=\"7\" stroke=\"white\" stroke-width=\"1\"\/><line x1=\"8\" y1=\"5.5\" x2=\"6\" y2=\"7\" stroke=\"white\" stroke-width=\"1\"\/>',\n\t'Estudio':\n\t'<path d=\"M3 10L8.5 2\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\/><path d=\"M2 10.5L3 11.5 4 10\" stroke=\"white\" stroke-width=\"1.2\" fill=\"none\" stroke-linecap=\"round\"\/>',\n\t'Arquitectura':\n\t'<circle cx=\"6\" cy=\"6\" r=\"2\" stroke=\"white\" stroke-width=\"1.3\" fill=\"none\"\/><line x1=\"6\" y1=\"1\" x2=\"6\" y2=\"11\" stroke=\"white\" stroke-width=\"1.2\" opacity=\".7\"\/><line x1=\"1\" y1=\"6\" x2=\"11\" y2=\"6\" stroke=\"white\" stroke-width=\"1.2\" opacity=\".7\"\/>',\n\t'Entretenimiento':\n\t'<circle cx=\"6\" cy=\"5.5\" r=\"2.5\" stroke=\"white\" stroke-width=\"1.4\" fill=\"none\"\/><line x1=\"3.5\" y1=\"9.5\" x2=\"8.5\" y2=\"9.5\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"\/><line x1=\"4.5\" y1=\"11\" x2=\"7.5\" y2=\"11\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"\/>',\n\t'Servicios Culturales':\n\t'<circle cx=\"6\" cy=\"6\" r=\"2.5\" stroke=\"white\" stroke-width=\"1.3\" fill=\"none\"\/><line x1=\"6\" y1=\"1\" x2=\"6\" y2=\"2.5\" stroke=\"white\" stroke-width=\"1.3\" stroke-linecap=\"round\"\/><line x1=\"6\" y1=\"9.5\" x2=\"6\" y2=\"11\" stroke=\"white\" stroke-width=\"1.3\" stroke-linecap=\"round\"\/><line x1=\"1\" y1=\"6\" x2=\"2.5\" y2=\"6\" stroke=\"white\" stroke-width=\"1.3\" stroke-linecap=\"round\"\/><line x1=\"9.5\" y1=\"6\" x2=\"11\" y2=\"6\" stroke=\"white\" stroke-width=\"1.3\" stroke-linecap=\"round\"\/>',\n\t'default':\n\t'<circle cx=\"6\" cy=\"6\" r=\"3.5\" fill=\"white\" opacity=\".9\"\/>',\n\t};\n\t\n\n\tconst TIPO_BG = {\n\t'Galer\u00eda':'#FEF3E8','Museo':'#EFF6FF','Espacio Independiente':'#ECFDF5',\n\t'Centro Cultural':'#F5F3FF','Taller':'#FFFBEB','Instituto':'#FEF3E8',\n\t'Educaci\u00f3n':'#F0F9FF','Residencias':'#FDF2F8','Sala de Conciertos':'#F5F3FF',\n\t'Teatro':'#F0FDFA','Festival':'#FFF1F2','Fundaci\u00f3n':'#EFF6FF',\n\t'Colectivo':'#ECFDF5','Estudio':'#F5F5F4','Arquitectura':'#FEFCE8',\n\t'default':'#F5F5F5',\n\t};\n\t\n\n\tconst TIPO_CLASS = {\n\t'Galer\u00eda': 'bg-galeria',\n\t'Museo': 'bg-museo',\n\t'Espacio Independiente': 'bg-ind',\n\t'Centro Cultural': 'bg-cultural',\n\t'Taller': 'bg-taller',\n\t'Instituto': 'bg-inst',\n\t'Educaci\u00f3n': 'bg-educ',\n\t'Residencias': 'bg-res',\n\t'Sala de Conciertos': 'bg-conc',\n\t'Teatro': 'bg-teatro',\n\t'Festival': 'bg-fest',\n\t'Fundaci\u00f3n': 'bg-fund',\n\t'Colectivo': 'bg-col',\n\t'Estudio': 'bg-est',\n\t'Arquitectura': 'bg-arq',\n\t'Entretenimiento': 'bg-ent',\n\t'Servicios Culturales': 'bg-sv',\n\t'default': 'bg-default',\n\t};\n\t\n\n\t\/\/ Decode HTML entities (fixes &hellip; etc from PHP)\n\tfunction decode(str) {\n\tif (!str) return '';\n\tconst t = document.createElement('textarea');\n\tt.innerHTML = str;\n\treturn t.value;\n\t}\n\t\n\n\t\/\/ Escape for safe innerHTML injection \u2014 prevents XSS\n\tfunction esc(str) {\n\treturn String(str)\n\t.replace(\/&\/g, '&amp;')\n\t.replace(\/<\/g, '&lt;')\n\t.replace(\/>\/g, '&gt;')\n\t.replace(\/\"\/g, '&quot;')\n\t.replace(\/'\/g, '&#39;');\n\t}\n\t\n\n\tlet map, cg, allSpaces = [];\n\tlet filt = { tipo:'all', ciudad:'all', disc:'all' };\n\tlet showLabels = true;\n\tlet geoActive = false;\n\t\n\n\t\/\/ \u2500\u2500 SIDEBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tconst $sb = () => document.getElementById('mesh-sidebar');\n\tconst $bd = () => document.getElementById('mesh-bd');\n\tconst $edgeH = () => document.getElementById('sb-edge-handle');\n\tconst openSB = () => {\n\t$sb().classList.add('open');\n\t$bd().classList.add('show');\n\tif (window.innerWidth <= 860) $edgeH().classList.add('show');\n\t};\n\tconst closeSB = () => {\n\t$sb().classList.remove('open');\n\t$bd().classList.remove('show');\n\t$edgeH().classList.remove('show');\n\t};\n\t\n\n\t\/\/ \u2500\u2500 ICONS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction color(t) { return TIPO_COLOR[t] || TIPO_COLOR.default; }\n\tfunction icon(t) { return TIPO_ICON[t] || TIPO_ICON.default; }\n\t\n\n\tfunction makeIcon(tipo, isMulti, extraCount) {\n\tconst c = color(tipo);\n\tconst svg = icon(tipo);\n\tconst badge = isMulti\n\t? `<div style=\"position:absolute;top:-5px;right:-5px;min-width:14px;height:14px;background:#7C3AED;border:1.5px solid #111;border-radius:0;display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:800;color:#fff;font-family:-apple-system,sans-serif;padding:0 2px;line-height:1;box-shadow:1px 1px 0 #111;\">+${extraCount}<\/div>`\n\t: '';\n\treturn L.divIcon({\n\thtml: `<div style=\"\n\tposition:relative;width:22px;height:22px;\n\tbackground:${c};border:2px solid #111;\n\tdisplay:flex;align-items:center;justify-content:center;\n\tbox-shadow:1.5px 1.5px 0 #111;\n\t\"><svg viewBox=\"0 0 12 12\" width=\"12\" height=\"12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">${svg}<\/svg>${badge}<\/div>`,\n\tclassName:'', iconSize:[22,22], iconAnchor:[11,11]\n\t});\n\t}\n\t\n\n\tfunction makeCluster(cl) {\n\tconst n = cl.getChildCount();\n\tconst s = n > 99 ? 44 : n > 9 ? 38 : 32;\n\tconst fs = n > 99 ? 11 : 13;\n\treturn L.divIcon({\n\thtml:`<div style=\"width:${s}px;height:${s}px;background:#7C3AED;display:flex;align-items:center;justify-content:center;color:#fff;font-size:${fs}px;font-weight:800;border:2.5px solid #111;box-shadow:2px 2px 0 #111;font-family:-apple-system,sans-serif\">${n}<\/div>`,\n\tclassName:'', iconSize:[s,s], iconAnchor:[s\/2,s\/2]\n\t});\n\t}\n\t\n\n\t\/\/ \u2500\u2500 RENDER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction render(spaces) {\n\tconst c = map.getCenter(), z = map.getZoom();\n\tcg.clearLayers();\n\tspaces.forEach(s => {\n\tconst activeCats = (s.cats || []).filter(c => c !== 'Online');\n\tconst isMulti = activeCats.length > 1;\n\tconst extraCount = activeCats.length - 1;\n\tconst m = L.marker([s.lat, s.lng], { icon: makeIcon(s.tipo, isMulti, extraCount) });\n\tif (showLabels) {\n\tm.bindTooltip(s.nombre, {\n\tpermanent:true, direction:'right',\n\tclassName:'mesh-vlabel', offset:[8,0]\n\t});\n\t}\n\tm.on('click', () => openCard(s));\n\tcg.addLayer(m);\n\t});\n\tmap.setView(c, z, { animate:false });\n\tdocument.getElementById('sb-num').textContent = spaces.length.toLocaleString();\n\t}\n\t\n\n\tfunction applyFilters() {\n\tconst f = allSpaces.filter(s =>\n\t(filt.tipo === 'all' || (s.cats||[s.tipo]).includes(filt.tipo)) &&\n\t(filt.ciudad === 'all' || s.ciudad === filt.ciudad || s.pais === filt.ciudad) &&\n\t(filt.disc === 'all' || (s.disciplinas||[]).includes(filt.disc))\n\t);\n\trender(f);\n\tdocument.getElementById('filter-pill').classList.toggle(\n\t'show', filt.tipo!=='all' || filt.ciudad!=='all' || filt.disc!=='all'\n\t);\n\t}\n\t\n\n\t\/\/ \u2500\u2500 CARD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction openCard(s) {\n\tif (window.innerWidth <= 860) closeSB();\n\t\n\n\tconst wrap = document.getElementById('d-imgwrap');\n\twrap.querySelectorAll('.d-cover').forEach(el => el.remove());\n\t\n\n\tif (s.imagen) {\n\tconst img = document.createElement('img');\n\timg.className = 'd-cover'; img.alt = s.nombre;\n\t\/\/ Try full-size image (strip WP size suffix like -300x225)\n\tconst fullSrc = s.imagen.replace(\/-\\d+x\\d+(\\.[a-z]+)$\/i, '$1');\n\timg.src = fullSrc;\n\timg.onerror = () => { img.src = s.imagen; img.onerror = null; }; \/\/ fallback to medium\n\twrap.insertBefore(img, wrap.firstChild);\n\tdocument.getElementById('d-initial').style.display = 'none';\n\t} else {\n\tdocument.getElementById('d-initial').style.display = '';\n\t}\n\t\n\n\tconst imgBg = TIPO_BG[s.tipo] || TIPO_BG.default;\n\twrap.style.background = imgBg;\n\tdocument.getElementById('d-initial').textContent = s.nombre.charAt(0);\n\t\n\n\tconst cats = s.cats?.length ? s.cats : [s.tipo];\n\tdocument.getElementById('d-cats').innerHTML =\n\tcats.map(cat =>\n\t`<span class=\"d-badge ${TIPO_CLASS[esc(cat)]||'bg-default'}\">${esc(decode(cat))}<\/span>`\n\t).join('') + `<span class=\"d-city\">${esc(decode(s.ciudad))}<\/span>`;\n\t\n\n\tdocument.getElementById('d-nombre').textContent = decode(s.nombre);\n\tdocument.getElementById('d-addr').textContent = decode(s.address);\n\tdocument.getElementById('d-desc').textContent = decode(s.desc);\n\tdocument.getElementById('d-disc').innerHTML =\n\t(s.disciplinas||[]).map(d => `<span class=\"d-tag\">${esc(decode(d))}<\/span>`).join('');\n\tdocument.getElementById('d-cta').href = s.url || '#';\n\tdocument.getElementById('mesh-detail').classList.add('open');\n\t}\n\t\n\n\t\/\/ \u2500\u2500 LOAD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tasync function loadSpaces() {\n\tconst res = await fetch(API);\n\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\tconst data = await res.json();\n\treturn data.map(v => ({\n\tid:v.id, nombre:decode(v.n), url:v.url,\n\tlat:v.lat, lng:v.lng,\n\ttipo:v.t, cats:v.cats||[v.t], ciudad:v.c, pais:v.pais||v.c,\n\timagen:v.img||'',\n\tdesc:decode(v.desc||''),\n\taddress:decode(v.addr||''),\n\tdisciplinas:(v.disc||[]).map(decode),\n\t})).filter(s => s.lat && s.lng);\n\t}\n\t\n\n\t\/\/ \u2500\u2500 NAME SEARCH \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction initNameSearch() {\n\tconst inp = document.getElementById('name-search');\n\tconst box = document.getElementById('name-results');\n\t\n\n\tinp.addEventListener('input', () => {\n\tconst q = inp.value.trim().toLowerCase();\n\tif (!q) { box.classList.remove('open'); return; }\n\tconst hits = allSpaces.filter(s => s.nombre.toLowerCase().includes(q)).slice(0,8);\n\tif (!hits.length) { box.classList.remove('open'); return; }\n\tbox.innerHTML = hits.map(s =>\n\t`<button class=\"name-result-item\" data-id=\"${esc(String(s.id))}\">\n\t<strong>${esc(s.nombre)}<\/strong>\n\t<div class=\"nr-sub\">${esc(s.tipo)} \u00b7 ${esc(s.ciudad)}<\/div>\n\t<\/button>`\n\t).join('');\n\tbox.classList.add('open');\n\t});\n\t\n\n\tbox.addEventListener('click', e => {\n\tconst btn = e.target.closest('.name-result-item');\n\tif (!btn) return;\n\tconst s = allSpaces.find(x => x.id == btn.dataset.id);\n\tif (!s) return;\n\tmap.setView([s.lat, s.lng], 16, { animate:true });\n\topenCard(s);\n\tinp.value = ''; box.classList.remove('open');\n\tif (window.innerWidth <= 860) closeSB();\n\t});\n\t\n\n\tdocument.addEventListener('click', e => {\n\tif (!inp.contains(e.target) && !box.contains(e.target)) box.classList.remove('open');\n\t});\n\t}\n\t\n\n\t\/\/ \u2500\u2500 DROPDOWN \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction buildDropdown({ triggerId, panelId, searchId, optsId, placeholder, colorFn, onSelect }) {\n\tconst trigger = document.getElementById(triggerId);\n\tconst panel = document.getElementById(panelId);\n\tconst search = document.getElementById(searchId);\n\tconst optsCt = document.getElementById(optsId);\n\tlet current = 'all', options = [];\n\t\n\n\tfunction renderOpts(q = '') {\n\tconst f = q ? options.filter(o => o.label.toLowerCase().includes(q.toLowerCase())) : options;\n\toptsCt.innerHTML = f.map(o => {\n\tconst sq = (colorFn && o.value !== 'all')\n\t? `<span style=\"width:11px;height:11px;background:${esc(colorFn(o.value))};border:1.5px solid #111;display:inline-block;flex-shrink:0;box-shadow:1px 1px 0 rgba(0,0,0,.2)\"><\/span>`\n\t: `<span style=\"width:11px;display:inline-block;flex-shrink:0\"><\/span>`;\n\treturn `<button class=\"mesh-sel-opt${o.value===current?' active':''}\" data-v=\"${esc(o.value)}\">\n\t${sq}<span style=\"flex:1\">${esc(o.label)}<\/span>\n\t${o.count!=null?`<span class=\"mesh-sel-opt-count\">${o.count}<\/span>`:''}\n\t<\/button>`;\n\t}).join('');\n\t}\n\t\n\n\tfunction openDrop() {\n\tdocument.querySelectorAll('.mesh-sel-trigger.open').forEach(t => {\n\tif (t!==trigger) { t.classList.remove('open'); t.nextElementSibling?.classList.remove('open'); }\n\t});\n\ttrigger.classList.add('open'); panel.classList.add('open');\n\tsearch.value = ''; renderOpts();\n\tsetTimeout(() => search.focus(), 50);\n\t}\n\tfunction closeDrop() { trigger.classList.remove('open'); panel.classList.remove('open'); }\n\t\n\n\ttrigger.addEventListener('click', e => {\n\te.stopPropagation();\n\tpanel.classList.contains('open') ? closeDrop() : openDrop();\n\t});\n\tsearch.addEventListener('input', () => renderOpts(search.value));\n\tsearch.addEventListener('click', e => e.stopPropagation());\n\tpanel.addEventListener('click', e => e.stopPropagation());\n\t\n\n\toptsCt.addEventListener('click', e => {\n\tconst btn = e.target.closest('.mesh-sel-opt');\n\tif (!btn) return;\n\tcurrent = btn.dataset.v;\n\tconst valEl = document.getElementById(triggerId.replace('-trigger','-val'));\n\tif (current === 'all') {\n\tvalEl.textContent = placeholder;\n\tvalEl.classList.add('ph');\n\t\/\/ Remove color square from trigger if any\n\tconst sq = trigger.querySelector('.trigger-color-sq');\n\tif (sq) sq.remove();\n\t} else {\n\tvalEl.textContent = current;\n\tvalEl.classList.remove('ph');\n\t\/\/ Add\/update color square in trigger\n\tif (colorFn) {\n\tlet sq = trigger.querySelector('.trigger-color-sq');\n\tif (!sq) {\n\tsq = document.createElement('span');\n\tsq.className = 'trigger-color-sq';\n\tsq.style.cssText = 'width:11px;height:11px;border:1.5px solid #111;display:inline-block;flex-shrink:0;margin-right:6px;box-shadow:1px 1px 0 rgba(0,0,0,.2)';\n\ttrigger.insertBefore(sq, valEl);\n\t}\n\tsq.style.background = colorFn(current);\n\t}\n\t}\n\tonSelect(current);\n\tcloseDrop();\n\t});\n\t\n\n\tdocument.addEventListener('click', () => closeDrop());\n\treturn {\n\tsetOptions(list) { options = list; },\n\tsetValue(v) { current = v; }\n\t};\n\t}\n\t\n\n\t\/\/ \u2500\u2500 BUILD FILTER UI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tlet tipoDrop, ciudadDrop, discDrop;\n\t\n\n\tfunction buildFilterUI(spaces) {\n\tconst tc={}, cc={}, dc={};\n\t\/\/ Count tipos\n\tspaces.forEach(s => {\n\t(s.cats||[s.tipo]).forEach(t => { tc[t]=(tc[t]||0)+1; });\n\t(s.disciplinas||[]).forEach(d => { dc[d]=(dc[d]||0)+1; });\n\t});\n\t\n\n\t\/\/ Build location counts \u2014 countries aggregate all their cities\n\tconst cityCount = {}; \/\/ city name \u2192 count\n\tconst paisCount = {}; \/\/ country name \u2192 count\n\tspaces.forEach(s => {\n\tif (s.ciudad) cityCount[s.ciudad] = (cityCount[s.ciudad]||0) + 1;\n\tif (s.pais) paisCount[s.pais] = (paisCount[s.pais]||0) + 1;\n\t});\n\t\n\n\t\/\/ Build location options: countries first (sorted by count desc), then cities\n\tconst countries = Object.entries(paisCount)\n\t.sort((a,b) => b[1]-a[1])\n\t.map(([name, count]) => ({ value:name, label:`${name}`, count, isCountry:true }));\n\t\n\n\tconst cities = Object.entries(cityCount)\n\t.filter(([name]) => !paisCount[name]) \/\/ exclude entries that are also country names\n\t.sort((a,b) => b[1]-a[1])\n\t.map(([name, count]) => ({ value:name, label:name, count }));\n\t\n\n\ttipoDrop.setOptions([\n\t{ value:'all', label:'Todos los tipos', count:spaces.length },\n\t...Object.keys(tc).sort().map(t=>({value:t,label:t,count:tc[t]}))\n\t]);\n\tciudadDrop.setOptions([\n\t{ value:'all', label:'Todos los lugares', count:spaces.length },\n\t...countries,\n\t...cities,\n\t]);\n\tdiscDrop.setOptions([\n\t{ value:'all', label:'Todas las disciplinas', count:spaces.length },\n\t...Object.keys(dc).sort().map(d=>({value:d,label:d,count:dc[d]}))\n\t]);\n\t}\n\t\n\n\t\/\/ \u2500\u2500 DETECT NATIVELY APP \/ WEBVIEW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction isInsideApp() {\n\t\/\/ Natively-specific JS bridge objects\n\tif (typeof window.NativelyLocation !== 'undefined') return true;\n\tif (typeof window.natively !== 'undefined') return true;\n\tif (typeof window.NativelyCore !== 'undefined') return true;\n\t\/\/ React Native WebView generic bridge\n\tif (typeof window.ReactNativeWebView !== 'undefined') return true;\n\t\n\n\tconst ua = navigator.userAgent;\n\t\/\/ Android WebView: contains \"; wv)\"\n\tif (\/Android\/i.test(ua) && \/wv\\)\/i.test(ua)) return true;\n\t\/\/ iOS WebView: iOS device but NO \"Safari\/\" version token\n\t\/\/ Real Safari\/Chrome always has \"Safari\/XXX.X\" \u2014 WebViews don't\n\tif (\/iPhone|iPad|iPod\/i.test(ua) && !\/Safari\\\/[\\d.]+\/.test(ua)) return true;\n\t\/\/ Some wrappers append their name\n\tif (\/Natively|NativeApp\/i.test(ua)) return true;\n\t\n\n\treturn false;\n\t}\n\t\n\n\tfunction hideGeoIfApp() {\n\tconst btn = document.getElementById('geo-btn');\n\tif (!btn) return;\n\tif (isInsideApp()) { btn.style.display = 'none'; return; }\n\t\n\n\t\/\/ Poll up to 3s \u2014 Natively may inject its bridge after page load\n\tlet n = 0;\n\tconst t = setInterval(() => {\n\tif (\n\ttypeof window.NativelyLocation !== 'undefined' ||\n\ttypeof window.natively !== 'undefined' ||\n\ttypeof window.NativelyCore !== 'undefined'\n\t) {\n\tbtn.style.display = 'none';\n\tclearInterval(t);\n\t}\n\tif (++n >= 30) clearInterval(t); \/\/ 30 \u00d7 100ms = 3s\n\t}, 100);\n\t}\n\t\n\n\t\/\/ Run immediately (before init) AND after init\n\thideGeoIfApp();\n\t\n\n\t\/\/ \u2500\u2500 GEO BUTTON (absolute, reliable on mobile) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tfunction buildGeoControl() {\n\tconst btn = document.getElementById('geo-btn');\n\tbtn.addEventListener('click', () => {\n\tgeoActive = !geoActive;\n\tbtn.classList.toggle('active', geoActive);\n\tif (geoActive) {\n\tif (!navigator.geolocation) {\n\tgeoActive = false; btn.classList.remove('active');\n\talert('Geolocalizaci\u00f3n no disponible en este dispositivo.');\n\treturn;\n\t}\n\tnavigator.geolocation.getCurrentPosition(\n\tp => map.setView([p.coords.latitude, p.coords.longitude], 14),\n\terr => {\n\tgeoActive = false; btn.classList.remove('active');\n\t\/\/ Code 1 = permission denied (common in WebView without native permission)\n\tif (err.code === 1) console.warn('Geo permission denied \u2014 check app location settings');\n\t},\n\t{ enableHighAccuracy: false, timeout: 15000, maximumAge: 60000 }\n\t\/\/ Note: WebView apps need location permission in native config:\n\t\/\/ iOS: NSLocationWhenInUseUsageDescription in Info.plist\n\t\/\/ Android: ACCESS_FINE_LOCATION in AndroidManifest.xml\n\t);\n\t}\n\t});\n\t}\n\t\n\n\t\/\/ \u2500\u2500 INIT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tasync function init() {\n\ttipoDrop = buildDropdown({\n\ttriggerId:'tipo-trigger', panelId:'tipo-panel',\n\tsearchId:'tipo-search', optsId:'tipo-opts',\n\tplaceholder:'Todos los tipos', colorFn: v=>color(v),\n\tonSelect: v=>{ filt.tipo=v; applyFilters(); if(window.innerWidth<=860) closeSB(); }\n\t});\n\tciudadDrop = buildDropdown({\n\ttriggerId:'ciudad-trigger', panelId:'ciudad-panel',\n\tsearchId:'ciudad-search', optsId:'ciudad-opts',\n\tplaceholder:'Todos los lugares', colorFn:null,\n\tonSelect: v => {\n\tfilt.ciudad = v;\n\tapplyFilters();\n\t\/\/ Zoom map to the selected lugar\n\tif (v !== 'all') {\n\tconst lugarSpaces = allSpaces.filter(s => s.ciudad === v || s.pais === v);\n\tif (lugarSpaces.length > 0) {\n\ttry {\n\tconst grp = L.featureGroup(lugarSpaces.map(s => L.marker([s.lat, s.lng])));\n\tmap.fitBounds(grp.getBounds().pad(0.2), { animate: true, duration: 0.8 });\n\t} catch(e) {}\n\t}\n\t}\n\tif (window.innerWidth <= 860) closeSB();\n\t}\n\t});\n\tdiscDrop = buildDropdown({\n\ttriggerId:'disc-trigger', panelId:'disc-panel',\n\tsearchId:'disc-search', optsId:'disc-opts',\n\tplaceholder:'Todas las disciplinas', colorFn:null,\n\tonSelect: v=>{ filt.disc=v; applyFilters(); if(window.innerWidth<=860) closeSB(); }\n\t});\n\t\n\n\tconst isMobile = window.innerWidth <= 860;\n\tmap = L.map('mesh-map', {\n\tcenter: [15, -90], zoom: isMobile ? 3 : 3, zoomControl: false\n\t});\n\tL.tileLayer('https:\/\/{s}.basemaps.cartocdn.com\/light_all\/{z}\/{x}\/{y}{r}.png', {\n\tattribution:'\u00a9 OpenStreetMap \u00a9 CARTO', subdomains:'abcd', maxZoom:20\n\t}).addTo(map);\n\tL.control.zoom({ position:'bottomright' }).addTo(map);\n\tbuildGeoControl();\n\t\n\n\tcg = L.markerClusterGroup({\n\tmaxClusterRadius:50, showCoverageOnHover:false,\n\tspiderfyOnMaxZoom:true, iconCreateFunction:makeCluster\n\t});\n\tmap.addLayer(cg);\n\t\n\n\ttry {\n\tallSpaces = await loadSpaces();\n\t} catch(e) {\n\tconsole.error('Mesh:', e);\n\tdocument.getElementById('ld-text').textContent = 'Error cargando datos.';\n\treturn;\n\t}\n\t\n\n\tbuildFilterUI(allSpaces);\n\tinitNameSearch();\n\trender(allSpaces);\n\t\n\n\t\/\/ Zoom to LATAM (where most venues are), ignore global outliers\n\ttry {\n\tmap.invalidateSize();\n\tconst latam = allSpaces.filter(s =>\n\ts.lat > -56 && s.lat < 34 && s.lng > -120 && s.lng < -30\n\t);\n\tconst target = latam.length > 0 ? latam : allSpaces;\n\tconst grp = L.featureGroup(target.map(s => L.marker([s.lat, s.lng])));\n\tmap.fitBounds(grp.getBounds().pad(0.08));\n\t} catch(e) {}\n\t\n\n\tdocument.getElementById('mesh-loading').classList.add('hide');\n\t}\n\t\n\n\t\/\/ \u2500\u2500 RESET \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tdocument.getElementById('rst-btn').addEventListener('click', () => {\n\tfilt = { tipo:'all', ciudad:'all', disc:'all' };\n\t[tipoDrop, ciudadDrop, discDrop].forEach(d => d.setValue('all'));\n\t[['tipo-val','Todos los tipos'],['ciudad-val','Todos los lugares'],['disc-val','Todas las disciplinas']]\n\t.forEach(([id,txt]) => {\n\tconst el = document.getElementById(id);\n\tel.textContent = txt; el.classList.add('ph');\n\t\/\/ Remove color square from trigger\n\tconst trigger = el.closest('.mesh-sel-trigger');\n\tif (trigger) { const sq = trigger.querySelector('.trigger-color-sq'); if (sq) sq.remove(); }\n\t});\n\tdocument.getElementById('mesh-detail').classList.remove('open');\n\tgeoActive = false; document.getElementById('geo-btn').classList.remove('active');\n\tapplyFilters();\n\t});\n\t\n\n\tdocument.getElementById('d-x').addEventListener('click', () =>\n\tdocument.getElementById('mesh-detail').classList.remove('open')\n\t);\n\t\n\n\tdocument.getElementById('mob-filter').addEventListener('click', openSB);\n\tdocument.getElementById('mesh-bd').addEventListener('click', closeSB);\n\tdocument.getElementById('sb-x').addEventListener('click', closeSB);\n\t\n\n\t\/\/ \u2500\u2500 TOUCH: tap image area to close card on mobile \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tconst card = document.getElementById('mesh-detail');\n\tconst dBody = card.querySelector('.d-body');\n\t\n\n\t\/\/ Prevent body scroll from leaking to page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tdBody.addEventListener('touchstart', e => {\n\tdBody._ty = e.touches[0].clientY;\n\t}, { passive: true });\n\tdBody.addEventListener('touchmove', e => {\n\tconst dy = e.touches[0].clientY - (dBody._ty || e.touches[0].clientY);\n\tdBody._ty = e.touches[0].clientY;\n\tconst atTop = dBody.scrollTop <= 0;\n\tconst atBottom = dBody.scrollTop + dBody.clientHeight >= dBody.scrollHeight - 1;\n\tif ((atTop && dy > 0) || (atBottom && dy < 0)) e.preventDefault();\n\t}, { passive: false });\n\t\n\n\t\/\/ \u2500\u2500 TOUCH: swipe sidebar LEFT to close (mobile) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\tconst sb = document.getElementById('mesh-sidebar');\n\tlet tsX = 0, tsSwiping = false;\n\tsb.addEventListener('touchstart', e => {\n\ttsX = e.touches[0].clientX; tsSwiping = true;\n\t}, { passive: true });\n\tsb.addEventListener('touchmove', e => {\n\tif (!tsSwiping || window.innerWidth > 860) return;\n\tconst dx = Math.max(0, tsX - e.touches[0].clientX);\n\tsb.style.transition = 'none';\n\tsb.style.transform = `translateX(-${dx}px)`;\n\t}, { passive: true });\n\tsb.addEventListener('touchend', e => {\n\tif (!tsSwiping) return;\n\ttsSwiping = false;\n\tsb.style.transition = '';\n\tsb.style.transform = '';\n\tconst dx = tsX - e.changedTouches[0].clientX;\n\tif (dx > 60 && window.innerWidth <= 860) closeSB();\n\t}, { passive: true });\n\t\n\n\t\n\n\tif (document.readyState==='loading') {\n\tdocument.addEventListener('DOMContentLoaded', init);\n\t} else {\n\tsetTimeout(init, 50);\n\t}\n\t})();\n\t<\/script>\n\t\n\n\t<style>\n\t\/* Marker labels \u2014 outside scoped block *\/\n\t.mesh-vlabel {\n\tbackground: transparent !important; border: none !important;\n\tbox-shadow: none !important; padding: 0 !important;\n\tfont-size: 11px !important; font-weight: 700 !important;\n\tcolor: #0D0D0D !important; white-space: nowrap !important;\n\tpointer-events: none !important;\n\ttext-shadow: 0 1px 3px rgba(255,255,255,1), 0 -1px 3px rgba(255,255,255,1),\n\t1px 0 3px rgba(255,255,255,1), -1px 0 3px rgba(255,255,255,1) !important;\n\t}\n\t.mesh-vlabel::before { display: none !important; }\n\t<\/style>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2993d8f elementor-absolute elementor-widget elementor-widget-html\" data-id=\"2993d8f\" data-element_type=\"widget\" data-settings=\"{&quot;_position&quot;:&quot;absolute&quot;}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<div id=\"map-custom-loader\">\n    <div class=\"loader-box\">\n        <div class=\"spinner\"><\/div>\n        <p>Loading...<\/p>\n    <\/div>\n<\/div>\n\n<style>\n\/* This ensures the loader stays pinned to the SCREEN, not the section *\/\n#map-custom-loader {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100vw;\n    height: 100vh;\n    background-color: white;\n    z-index: 9999999; \/* Higher than everything else *\/\n    display: flex;\n    justify-content: center;\n    align-items: center;\n}\n\n.loader-box {\n    text-align: center;\n}\n\n.spinner {\n    border: 6px solid #f3f3f3;\n    border-top: 6px solid #3498db;\n    border-radius: 50%;\n    width: 50px;\n    height: 50px;\n    animation: mapSpin 1s linear infinite;\n    margin: 0 auto 20px;\n}\n\n@keyframes mapSpin {\n    0% { transform: rotate(0deg); }\n    100% { transform: rotate(360deg); }\n}\n<\/style>\n\n<script>\n(function($) {\n    $(document).ready(function() {\n        \n        \/\/ This function hides the loader and cleans up\n        function dismissLoader() {\n            $('#map-custom-loader').fadeOut(400, function() {\n                $(this).remove();\n            });\n        }\n\n        \/\/ 1. Listen for the official JetEngine Event\n        $(document).on('jet-engine-maps\/init', function() {\n            dismissLoader();\n        });\n\n        \/\/ 2. The \"Scout\": Check every 500ms if map markers or layers exist\n        var scoutInterval = setInterval(function() {\n            \/\/ We look for Google Maps internal classes or Leaflet classes\n            if ($('.gm-style').length > 0 || $('.leaflet-marker-pane').length > 0) {\n                dismissLoader();\n                clearInterval(scoutInterval);\n            }\n        }, 500);\n\n        \/\/ 3. Safety Net: Kill it after 20 seconds regardless\n        setTimeout(function() {\n            dismissLoader();\n            clearInterval(scoutInterval);\n        }, 20000);\n\n    });\n})(jQuery);\n<\/script>\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>","protected":false},"excerpt":{"rendered":"<p>Mapa cultural \u2014 espacios \u2715 Buscar por nombre Lugar Todos los lugares Tipo de espacio Todos los tipos Disciplina Todas [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","theme-transparent-header-meta":"default","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-47350","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47350","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/comments?post=47350"}],"version-history":[{"count":184,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47350\/revisions"}],"predecessor-version":[{"id":48422,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47350\/revisions\/48422"}],"wp:attachment":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/media?parent=47350"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}