{"id":47659,"date":"2026-04-01T21:39:48","date_gmt":"2026-04-02T03:39:48","guid":{"rendered":"https:\/\/themesh.art\/?page_id=47659"},"modified":"2026-04-04T20:47:02","modified_gmt":"2026-04-05T02:47:02","slug":"spaces","status":"publish","type":"page","link":"https:\/\/themesh.art\/en\/spaces\/","title":{"rendered":"Espacios"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"47659\" class=\"elementor elementor-47659\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b2692d3 e-flex e-con-boxed e-con e-parent\" data-id=\"b2692d3\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;jet_parallax_layout_list&quot;:[]}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7f42e3b e-flex e-con-boxed e-con e-parent\" data-id=\"7f42e3b\" 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-936ba37 elementor-widget elementor-widget-html\" data-id=\"936ba37\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<!--\n  MESH \u2014 ESPACIOS SEARCH PAGE\n  Endpoint: \/wp-json\/mesh\/v1\/map-venues (extend with featured field \u2014 see PHP note)\n  Template: Elementor Full Width > Code Widget\n  Follows: mesh Search Pages Build Reference & Lessons Learned\n-->\n<style>\n\/* \u2500\u2500\u2500 FONTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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@import url('https:\/\/fonts.googleapis.com\/css2?family=Barlow+Condensed:wght@700;900&family=Space+Grotesk:wght@400;500;700&display=swap');\n\n\/* \u2500\u2500\u2500 TOKENS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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:root {\n  --black:     #0a0a0a;\n  --white:     #f5f2eb;\n  --yellow:    #ffe135;\n  --purple:    #7c3aff;\n  --purple-lt: #ede9fe;\n  --green:     #22c55e;\n  --red:       #ff3c3c;\n  --ink2:      #3a3a3a;\n  --ink3:      #777;\n  --border-lt: #d4d0c8;\n  --border:    2px solid #0a0a0a;\n  --shadow:    4px 4px 0 #0a0a0a;\n  --font-head: 'Barlow Condensed', sans-serif;\n  --font-body: 'Space Grotesk', sans-serif;\n  --mh: 80px; --ab: 0px;\n}\nbody.admin-bar { --ab: 32px; }\n@media (max-width: 782px) { body.admin-bar { --ab: 46px; } }\n\n\/* \u2500\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 *\/\n#msp, #msp * {\n  box-sizing: border-box;\n  -webkit-font-smoothing: antialiased;\n}\n#msp button {\n  background-image: none !important;\n  text-transform: none !important;\n  letter-spacing: normal !important;\n  line-height: normal !important;\n  border-style: solid !important;\n  box-shadow: none !important;\n  padding: 0 !important;\n  font-size: inherit !important;\n}\n\n\/* \u2500\u2500\u2500 WRAPPER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp {\n  display: flex;\n  min-height: calc(100vh - var(--mh) - var(--ab));\n  background: var(--white);\n  font-family: var(--font-body);\n  color: var(--black);\n  position: relative;\n}\n\n\/* \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 *\/\n#msp-sidebar {\n  width: 268px; min-width: 268px;\n  border-right: var(--border);\n  display: flex; flex-direction: column;\n  background: var(--white);\n  flex-shrink: 0;\n  position: sticky;\n  top: calc(var(--mh) + var(--ab));\n  height: calc(100vh - var(--mh) - var(--ab));\n  overflow-y: auto; overflow-x: hidden;\n  transition: transform .26s cubic-bezier(.4,0,.2,1);\n}\n@media (max-width: 860px) {\n  #msp-sidebar {\n    position: fixed;\n    top: calc(var(--mh) + var(--ab));\n    left: 0; bottom: 0;\n    width: min(290px, 90vw);\n    transform: translateX(-110%);\n    z-index: 9999;\n    box-shadow: 6px 0 0 var(--black);\n  }\n  #msp-sidebar.open { transform: translateX(0); }\n}\n\n\/* Sidebar header *\/\n.sb-hd {\n  padding: 20px 18px 16px;\n  border-bottom: var(--border);\n  background: var(--white);\n  position: sticky; top: 0; z-index: 10;\n  display: flex; align-items: flex-start; justify-content: space-between;\n}\n.sb-eyebrow {\n  font-family: var(--font-head);\n  font-size: 10px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase;\n  color: var(--ink3); margin-bottom: 4px; display: block;\n}\n.sb-count-wrap { display: flex; align-items: baseline; gap: 5px; }\n.sb-num { font-size: 38px; font-weight: 800; line-height: 1; letter-spacing: -.04em; }\n.sb-unit { font-size: 13px; color: var(--ink3); font-weight: 400; }\n\n\/* Close X \u2014 mobile only *\/\n.sb-x {\n  display: none !important;\n  width: 32px; height: 32px;\n  border: var(--border) !important;\n  background: var(--white) !important;\n  color: var(--black) !important;\n  font-size: 15px !important; font-weight: 700 !important;\n  cursor: pointer !important;\n  align-items: center !important; justify-content: center !important;\n  flex-shrink: 0; margin-top: 4px;\n}\n@media (max-width: 860px) { .sb-x { display: flex !important; } }\n.sb-x:hover { background: var(--black) !important; color: var(--white) !important; }\n\n\/* Name search *\/\n.sb-name-sec {\n  padding: 14px 18px;\n  border-bottom: var(--border);\n  position: relative;\n}\n.sb-name-label {\n  font-family: var(--font-head);\n  font-size: 13px; font-weight: 900; letter-spacing: .16em; text-transform: uppercase;\n  color: var(--black); margin-bottom: 10px; display: block;\n}\n.sb-name-input {\n  width: 100% !important;\n  padding: 10px 13px !important;\n  font-size: 14px !important; font-weight: 500 !important;\n  font-family: var(--font-body) !important;\n  border: var(--border) !important;\n  border-radius: 0 !important;\n  background: var(--white) !important;\n  color: var(--black) !important;\n  outline: none !important;\n}\n.sb-name-input:focus { background: var(--purple-lt) !important; }\n\n\/* Filter sections *\/\n.sb-sec { padding: 14px 18px; border-bottom: 1px solid var(--border-lt); }\n.sb-sec-lbl {\n  font-family: var(--font-head);\n  font-size: 13px; font-weight: 900; letter-spacing: .16em; text-transform: uppercase;\n  color: var(--black); margin-bottom: 10px; display: block;\n}\n\n\/* Dropdown *\/\n.mesh-sel { position: relative; }\n.mesh-sel-trigger {\n  width: 100%;\n  display: flex !important; align-items: center !important;\n  justify-content: space-between !important;\n  padding: 11px 14px !important;\n  background: var(--white) !important;\n  border: var(--border) !important;\n  border-radius: 0 !important;\n  color: var(--black) !important;\n  font-size: 13px !important; font-weight: 500 !important;\n  font-family: var(--font-body) !important;\n  cursor: pointer !important; text-align: left !important;\n}\n.mesh-sel-trigger:hover { background: #ece9e0 !important; }\n.mesh-sel-trigger.open { background: var(--purple-lt) !important; border-color: var(--purple) !important; }\n.mesh-sel-val { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.mesh-sel-val.ph { color: var(--ink3); font-weight: 400; }\n.mesh-sel-arrow {\n  margin-left: 8px; flex-shrink: 0;\n  transition: transform .18s; color: var(--ink3);\n  display: flex; align-items: center; justify-content: center;\n  width: 16px; height: 16px;\n}\n.mesh-sel-trigger.open .mesh-sel-arrow { transform: rotate(180deg); }\n.mesh-sel-panel {\n  display: none;\n  position: absolute; top: 100%; left: 0; right: 0;\n  background: var(--white);\n  border: var(--border); border-color: var(--purple); border-top: none;\n  z-index: 500; max-height: 280px; overflow: hidden;\n  flex-direction: column; box-shadow: var(--shadow);\n}\n.mesh-sel-panel.open { display: flex; }\n.mesh-sel-search-wrap { padding: 10px 12px; border-bottom: 1px solid var(--border-lt); flex-shrink: 0; }\n.mesh-sel-search {\n  width: 100% !important; padding: 9px 12px !important;\n  font-size: 12px !important; font-weight: 500 !important;\n  font-family: var(--font-body) !important;\n  border: var(--border) !important; border-color: var(--border-lt) !important;\n  border-radius: 0 !important;\n  background: #ece9e0 !important; color: var(--black) !important; outline: none !important;\n}\n.mesh-sel-search:focus { border-color: var(--purple) !important; background: var(--white) !important; }\n.mesh-sel-opts { overflow-y: auto; flex: 1; }\n.mesh-sel-opt {\n  display: flex !important; align-items: center !important;\n  gap: 10px !important; padding: 13px 16px !important;\n  cursor: pointer !important; font-size: 13px !important;\n  font-weight: 500 !important; font-family: var(--font-body) !important;\n  color: var(--black) !important; background: var(--white) !important;\n  border: none !important; width: 100% !important; text-align: left !important;\n  border-bottom: 1px solid var(--border-lt) !important;\n  border-radius: 0 !important; min-height: 44px !important;\n}\n.mesh-sel-opt:last-child { border-bottom: none !important; }\n.mesh-sel-opt:hover { background: #ece9e0 !important; }\n.mesh-sel-opt.active { background: var(--purple-lt) !important; color: var(--purple) !important; font-weight: 700 !important; }\n.mesh-sel-opt-count { margin-left: auto; font-size: 11px; color: var(--ink3); flex-shrink: 0; font-weight: 400; padding-left: 10px !important; }\n.tipo-dot { width: 9px; height: 9px; border: 1.5px solid rgba(0,0,0,.25); flex-shrink: 0; }\n\n\/* Reset \u2014 use #msp prefix to beat #msp button specificity *\/\n#msp #msp-rst {\n  display: block !important; background: transparent !important;\n  border: 0 none !important; border-style: none !important;\n  outline: none !important; box-shadow: none !important;\n  -webkit-appearance: none !important; appearance: none !important;\n  padding: 14px 18px !important; font-size: 12px !important;\n  color: var(--ink3) !important; cursor: pointer !important;\n  text-decoration: underline !important; text-underline-offset: 3px !important;\n  text-align: left !important; width: 100% !important; font-weight: 500 !important;\n  font-family: var(--font-body) !important; border-radius: 0 !important;\n  margin: 0 !important; line-height: normal !important;\n}\n#msp #msp-rst:hover { color: var(--black) !important; background: transparent !important; }\n\n\/* Backdrop *\/\n#msp-bd {\n  display: none; position: fixed;\n  top: calc(var(--mh) + var(--ab)); left: 0; right: 0; bottom: 0;\n  background: rgba(0,0,0,.45); z-index: 9998;\n}\n@media (max-width: 860px) { #msp-bd.show { display: block; } }\n\n\/* \u2500\u2500\u2500 FULL-WIDTH BREAKOUT (matches events page) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n#msp {\n  width: 100vw;\n  max-width: 100vw;\n  margin-left: calc(50% - 50vw);\n}\n\n\/* \u2500\u2500\u2500 MAIN CONTENT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp-main {\n  flex: 1; min-width: 0;\n  display: flex; flex-direction: column;\n}\n\n\/* Dark page header \u2014 matches events\/learning\/opps *\/\n#msp-header {\n  background: var(--black);\n  padding: 28px 32px 22px;\n  border-bottom: var(--border);\n  display: flex; align-items: flex-end; justify-content: space-between;\n  gap: 16px; flex-wrap: wrap;\n}\n.msp-eyebrow {\n  font-family: var(--font-head);\n  font-size: 11px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;\n  color: var(--yellow); margin-bottom: 8px; display: block;\n}\n.msp-title {\n  font-family: var(--font-head);\n  font-size: clamp(40px, 5vw, 68px); font-weight: 900;\n  line-height: .9; text-transform: uppercase;\n  color: #fff; letter-spacing: -.02em; margin: 0;\n}\n.msp-header-cta {\n  display: inline-flex !important; align-items: center !important; gap: 8px !important;\n  padding: 12px 22px !important;\n  background: var(--yellow) !important; color: var(--black) !important;\n  border: var(--border) !important;\n  box-shadow: 3px 3px 0 rgba(255,225,53,.35) !important;\n  font-family: var(--font-head) !important;\n  font-size: 14px !important; font-weight: 900 !important;\n  letter-spacing: .08em !important; text-transform: uppercase !important;\n  text-decoration: none !important; white-space: nowrap !important;\n  flex-shrink: 0; align-self: flex-end; margin-bottom: 3px;\n  transition: transform .1s, box-shadow .1s !important;\n}\n.msp-header-cta:hover { transform: translate(-2px,-2px) !important; box-shadow: 5px 5px 0 rgba(255,225,53,.5) !important; }\n@media (max-width: 640px) {\n  #msp-header { padding: 18px 16px 16px; }\n  .msp-header-cta { width: 100% !important; justify-content: center !important; }\n}\n\n\/* Results bar \u2014 count + sort *\/\n#msp-res-bar {\n  display: flex; align-items: center; justify-content: space-between;\n  padding: 11px 18px; border-bottom: var(--border);\n  background: var(--white);\n}\n.msp-res-lbl {\n  font-family: var(--font-head);\n  font-size: 13px; font-weight: 700; color: var(--ink3);\n  text-transform: uppercase; letter-spacing: .08em;\n}\n.msp-res-lbl strong { color: var(--purple); font-size: 15px; }\n.msp-sort-wrap { position: relative; }\n.msp-sort-sel {\n  -webkit-appearance: none; appearance: none;\n  font-family: var(--font-head) !important;\n  font-size: 13px !important; font-weight: 700 !important;\n  text-transform: uppercase !important; letter-spacing: .08em !important;\n  padding: 8px 30px 8px 11px !important;\n  border: var(--border) !important; border-radius: 0 !important;\n  background: var(--white) !important; color: var(--black) !important;\n  cursor: pointer !important;\n}\n.msp-sort-sel:focus { outline: none; background: var(--purple-lt) !important; }\n.msp-sort-arrow {\n  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);\n  pointer-events: none; color: var(--ink3);\n}\n\n\/* \u2500\u2500\u2500 FEATURED STRIP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp-featured {\n  border-bottom: var(--border);\n  display: none; \/* shown via JS if featured venues exist *\/\n}\n.feat-label {\n  padding: 8px 24px;\n  font-family: var(--font-head);\n  font-size: 9px; font-weight: 900; letter-spacing: .22em; text-transform: uppercase;\n  background: var(--black); color: var(--yellow);\n  border-bottom: var(--border);\n}\n.feat-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(460px, 1fr));\n  border-left: var(--border);\n  border-bottom: var(--border);\n}\n.feat-card {\n  display: flex;\n  border-right: var(--border); border-top: var(--border);\n  min-height: 220px;\n  text-decoration: none; color: var(--black);\n  transition: background .1s;\n}\n.feat-card:hover { background: #ece9e0; }\n.feat-card-img {\n  width: 42%; min-width: 42%;\n  border-right: var(--border);\n  position: relative; overflow: hidden;\n  background: #c8c4ba;\n  flex-shrink: 0;\n}\n.feat-card-img img {\n  width: 100%; height: 100%; object-fit: cover; display: block;\n  position: absolute; inset: 0;\n}\n.feat-card-img-init {\n  position: absolute; inset: 0;\n  display: flex; align-items: center; justify-content: center;\n  font-family: var(--font-head);\n  font-size: 72px; font-weight: 900; color: rgba(0,0,0,.07);\n  user-select: none;\n}\n.feat-star {\n  position: absolute; bottom: 0; left: 0;\n  background: var(--yellow); color: var(--black);\n  font-family: var(--font-head);\n  font-size: 8px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase;\n  padding: 4px 9px;\n  border-top: var(--border); border-right: var(--border);\n}\n.feat-card-info {\n  flex: 1; display: flex; flex-direction: column; min-width: 0;\n}\n.feat-tipo-strip {\n  padding: 7px 14px;\n  font-family: var(--font-head);\n  font-size: 10px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase;\n  color: white;\n  border-bottom: var(--border);\n  display: flex; align-items: center; justify-content: space-between;\n  flex-shrink: 0;\n}\n.feat-tipo-strip span { opacity: .65; font-size: 14px; }\n.feat-body { padding: 16px 18px; flex: 1; display: flex; flex-direction: column; gap: 7px; }\n.feat-name {\n  font-family: var(--font-head);\n  font-size: 30px; font-weight: 900; text-transform: uppercase;\n  line-height: .93; letter-spacing: -.01em;\n}\n.feat-city { font-size: 11px; color: var(--ink3); font-weight: 500; }\n.feat-desc {\n  font-size: 12px; color: var(--ink2); line-height: 1.55; flex: 1;\n  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;\n}\n.feat-tags { display: flex; gap: 5px; flex-wrap: wrap; margin-top: auto; }\n.feat-tag {\n  font-family: var(--font-head);\n  font-size: 9px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;\n  padding: 2px 6px; border: 1px solid var(--border-lt); color: var(--ink3);\n}\n\n\/* \u2500\u2500\u2500 RESULTS GRID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp-grid-wrap { padding: 0; flex: 1; }\n\n.msp-grid {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  border-left: var(--border);\n  border-bottom: var(--border);\n}\n@media (max-width: 960px) { .msp-grid { grid-template-columns: repeat(2, 1fr); } }\n@media (max-width: 560px)  { .msp-grid { grid-template-columns: 1fr; } }\n\n.venue-card {\n  border-right: var(--border); border-top: var(--border);\n  display: flex; flex-direction: column;\n  text-decoration: none; color: var(--black);\n  transition: background .1s;\n  min-width: 0;\n  background: var(--white);\n}\n.venue-card:hover { background: #ece9e0; }\n.venue-card-img {\n  aspect-ratio: 4\/3;\n  border-bottom: var(--border);\n  position: relative; overflow: hidden;\n  background: #c8c4ba;\n}\n.venue-card-img img {\n  width: 100%; height: 100%; object-fit: cover; display: block;\n  position: absolute; inset: 0;\n}\n.venue-card-img-init {\n  position: absolute; inset: 0;\n  display: flex; align-items: center; justify-content: center;\n  font-family: var(--font-head);\n  font-size: 56px; font-weight: 900; color: rgba(0,0,0,.07);\n  user-select: none;\n}\n.venue-tipo-strip {\n  padding: 8px 14px;\n  font-family: var(--font-head);\n  font-size: 12px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase;\n  color: white;\n  border-bottom: var(--border);\n  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n.venue-card-body {\n  padding: 14px 16px;\n  display: flex; flex-direction: column; gap: 5px;\n  flex: 1;\n}\n.venue-name {\n  font-family: var(--font-head);\n  font-size: 24px; font-weight: 900; text-transform: uppercase;\n  line-height: 1; overflow-wrap: break-word;\n}\n.venue-city { font-size: 13px; color: var(--ink3); font-weight: 500; }\n.venue-desc {\n  font-size: 13px; color: var(--ink2); line-height: 1.55;\n  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;\n  overflow: hidden; margin-top: 4px;\n}\n\n\/* \u2500\u2500\u2500 LOAD MORE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp #msp-load-more {\n  display: none;\n  width: 100%;\n  padding: 36px !important;\n  font-family: var(--font-head) !important;\n  font-size: 20px !important; font-weight: 900 !important;\n  letter-spacing: .12em !important; text-transform: uppercase !important;\n  background: var(--yellow) !important;\n  border: none !important; border-top: var(--border) !important;\n  cursor: pointer !important; color: var(--black) !important;\n  box-shadow: none !important;\n}\n#msp #msp-load-more:hover { background: var(--black) !important; color: var(--yellow) !important; }\n\n\/* \u2500\u2500\u2500 EMPTY STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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#msp-empty {\n  display: none;\n  padding: 64px 28px;\n  flex-direction: column; align-items: center; text-align: center; gap: 14px;\n  background: repeating-linear-gradient(45deg,var(--white),var(--white) 12px,#ece9e0 12px,#ece9e0 24px);\n  border: var(--border);\n  margin: 0;\n}\n#msp-empty.show { display: flex; }\n.empty-icon { font-size: 36px; }\n.empty-title {\n  font-family: var(--font-head);\n  font-size: 22px; font-weight: 900; text-transform: uppercase;\n}\n.empty-sub { font-size: 13px; color: var(--ink3); max-width: 300px; line-height: 1.6; }\n.empty-cta {\n  display: inline-flex !important; align-items: center !important; gap: 6px !important;\n  padding: 9px 18px !important;\n  font-family: var(--font-head) !important;\n  font-size: 11px !important; font-weight: 900 !important;\n  letter-spacing: .12em !important; text-transform: uppercase !important;\n  background: var(--white) !important; color: var(--black) !important;\n  border: var(--border) !important; box-shadow: var(--shadow) !important;\n  cursor: pointer !important;\n}\n.empty-cta:hover { background: var(--black) !important; color: var(--white) !important; box-shadow: none !important; transform: translate(2px,2px); }\n\n\/* \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 *\/\n#msp-loading {\n  display: flex; flex-direction: column;\n  align-items: center; justify-content: center; gap: 14px;\n  padding: 80px 0;\n}\n.ld-spinner {\n  width: 24px; height: 24px;\n  border: 3px solid var(--border-lt); border-top-color: var(--purple);\n  border-radius: 50%; animation: msp-spin .8s linear infinite;\n}\n@keyframes msp-spin { to { transform: rotate(360deg); } }\n.ld-text {\n  font-family: var(--font-head);\n  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;\n  color: var(--ink3);\n}\n\n\/* \u2500\u2500\u2500 MOBILE FILTER BTN (must stay here, outside #msp) \u2500\u2500 *\/\n\/* see HTML below *\/\n<\/style>\n\n<!-- \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 -->\n<div id=\"msp-bd\"><\/div>\n\n<div id=\"msp\">\n\n  <!-- \u2500\u2500 SIDEBAR \u2500\u2500 -->\n  <aside id=\"msp-sidebar\">\n\n    <div class=\"sb-hd\">\n      <div>\n        <span class=\"sb-eyebrow\">Espacios<\/span>\n        <div class=\"sb-count-wrap\">\n          <span class=\"sb-num\" id=\"msp-count\">\u2014<\/span>\n          <span class=\"sb-unit\">espacios<\/span>\n        <\/div>\n      <\/div>\n      <button class=\"sb-x\" id=\"msp-sb-x\">\u2715<\/button>\n    <\/div>\n\n    <!-- Name search -->\n    <div class=\"sb-name-sec\">\n      <span class=\"sb-name-label\">Buscar por nombre<\/span>\n      <input class=\"sb-name-input\" id=\"msp-name-inp\" type=\"text\"\n        placeholder=\"Nombre del espacio\u2026\" autocomplete=\"off\">\n    <\/div>\n\n    <!-- Tipo -->\n    <div class=\"sb-sec\">\n      <span class=\"sb-sec-lbl\">Tipo de espacio<\/span>\n      <div class=\"mesh-sel\">\n        <button class=\"mesh-sel-trigger\" id=\"tipo-trigger\">\n          <span class=\"mesh-sel-val ph\" id=\"tipo-val\">Todos los tipos<\/span>\n          <span class=\"mesh-sel-arrow\"><svg width=\"12\" height=\"7\" viewbox=\"0 0 12 7\" fill=\"none\"><path d=\"M1 1l5 5 5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n        <\/button>\n        <div class=\"mesh-sel-panel\" id=\"tipo-panel\">\n          <div class=\"mesh-sel-search-wrap\">\n            <input class=\"mesh-sel-search\" id=\"tipo-search\" type=\"text\" placeholder=\"Buscar tipo\u2026\" autocomplete=\"off\">\n          <\/div>\n          <div class=\"mesh-sel-opts\" id=\"tipo-opts\"><\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Disciplina -->\n    <div class=\"sb-sec\">\n      <span class=\"sb-sec-lbl\">Disciplina<\/span>\n      <div class=\"mesh-sel\">\n        <button class=\"mesh-sel-trigger\" id=\"disc-trigger\">\n          <span class=\"mesh-sel-val ph\" id=\"disc-val\">Todas las disciplinas<\/span>\n          <span class=\"mesh-sel-arrow\"><svg width=\"12\" height=\"7\" viewbox=\"0 0 12 7\" fill=\"none\"><path d=\"M1 1l5 5 5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n        <\/button>\n        <div class=\"mesh-sel-panel\" id=\"disc-panel\">\n          <div class=\"mesh-sel-search-wrap\">\n            <input class=\"mesh-sel-search\" id=\"disc-search\" type=\"text\" placeholder=\"Buscar disciplina\u2026\" autocomplete=\"off\">\n          <\/div>\n          <div class=\"mesh-sel-opts\" id=\"disc-opts\"><\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Lugar -->\n    <div class=\"sb-sec\">\n      <span class=\"sb-sec-lbl\">Lugar<\/span>\n      <div class=\"mesh-sel\">\n        <button class=\"mesh-sel-trigger\" id=\"lugar-trigger\">\n          <span class=\"mesh-sel-val ph\" id=\"lugar-val\">Todos los lugares<\/span>\n          <span class=\"mesh-sel-arrow\"><svg width=\"12\" height=\"7\" viewbox=\"0 0 12 7\" fill=\"none\"><path d=\"M1 1l5 5 5-5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><\/span>\n        <\/button>\n        <div class=\"mesh-sel-panel\" id=\"lugar-panel\">\n          <div class=\"mesh-sel-search-wrap\">\n            <input class=\"mesh-sel-search\" id=\"lugar-search\" type=\"text\" placeholder=\"Buscar lugar\u2026\" autocomplete=\"off\">\n          <\/div>\n          <div class=\"mesh-sel-opts\" id=\"lugar-opts\"><\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <button class=\"rst-btn\" id=\"msp-rst\">Limpiar filtros<\/button>\n\n  <\/aside>\n\n  <!-- \u2500\u2500 MAIN \u2500\u2500 -->\n  <main id=\"msp-main\">\n\n    <!-- Dark page header -->\n    <div id=\"msp-header\">\n      <div>\n        <span class=\"msp-eyebrow\">Cultura \u00b7 Espacios<\/span>\n        <h1 class=\"msp-title\">ESPACIOS<\/h1>\n      <\/div>\n      <a class=\"msp-header-cta\" href=\"https:\/\/themesh.art\/en\/sumate\/\" target=\"_blank\" rel=\"noopener\">\n        + Publicar espacio \u2192\n      <\/a>\n    <\/div>\n\n    <!-- Results bar \u2014 count + sort -->\n    <div id=\"msp-res-bar\">\n      <span class=\"msp-res-lbl\"><strong id=\"msp-count-badge\">\u2014<\/strong> espacios<\/span>\n      <div class=\"msp-sort-wrap\">\n        <select class=\"msp-sort-sel\" id=\"msp-sort-sel\">\n          <option value=\"random\">Aleatorio<\/option>\n          <option value=\"az\">A \u2192 Z<\/option>\n          <option value=\"za\">Z \u2192 A<\/option>\n          <option value=\"new\">M\u00e1s recientes<\/option>\n        <\/select>\n        <span class=\"msp-sort-arrow\"><svg width=\"10\" height=\"7\" 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      <\/div>\n    <\/div>\n\n    <!-- Loading -->\n    <div id=\"msp-loading\">\n      <div class=\"ld-spinner\"><\/div>\n      <div class=\"ld-text\">Cargando espacios\u2026<\/div>\n    <\/div>\n\n    <!-- Featured strip -->\n    <div id=\"msp-featured\">\n      <div class=\"feat-label\">\u2605 Espacios destacados<\/div>\n      <div class=\"feat-grid\" id=\"msp-feat-grid\"><\/div>\n    <\/div>\n\n    <!-- Results grid -->\n    <div id=\"msp-grid-wrap\">\n      <div class=\"msp-grid\" id=\"msp-grid\"><\/div>\n      <button id=\"msp-load-more\">Ver m\u00e1s espacios \u2193<\/button>\n    <\/div>\n\n    <!-- Empty state -->\n    <div id=\"msp-empty\">\n      <div class=\"empty-icon\">\ud83c\udfdb\ufe0f<\/div>\n      <div class=\"empty-title\">Sin espacios que coincidan<\/div>\n      <div class=\"empty-sub\">Intenta con otros filtros o busca por nombre.<\/div>\n      <button class=\"empty-cta\" id=\"msp-empty-rst\">Limpiar filtros<\/button>\n    <\/div>\n\n  <\/main>\n<\/div>\n\n<!-- Mobile filter button \u2014 OUTSIDE #msp to avoid transform issues (lesson 5.10) -->\n<button id=\"msp-mob-filter\"\n  style=\"display:none;position:fixed;bottom:20px;left:50%;transform:translateX(-50%);  background:#7c3aff!important;color:#fff!important;  border:2px solid #0a0a0a!important;border-radius:0!important;  padding:13px 28px!important;font-size:14px!important;font-weight:700!important;  font-family:'Barlow Condensed',sans-serif!important;letter-spacing:.06em!important;  text-transform:uppercase!important;  cursor:pointer!important;z-index:400;  box-shadow:4px 4px 0 #0a0a0a!important;white-space:nowrap;\">\n  \u2261 Filtros\n<\/button>\n\n<style>\n@media (max-width: 860px) {\n  #msp-mob-filter { display: block !important; }\n}\n<\/style>\n\n<!-- \u2500\u2500 SCRIPT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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<script>\n(function () {\n'use strict';\n\n\/\/ \u2500\u2500 CONFIG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst API = '\/wp-json\/mesh\/v1\/spaces';\nconst BATCH = 48; \/\/ 3-col \u00d7 4 rows \u00d7 4\n\n\/\/ Tipo \u2192 color (from map code)\nconst TIPO_COLOR = {\n  'Galer\u00eda':               '#E85D04',\n  'Museo':                 '#1E40AF',\n  'Espacio Independiente': '#059669',\n  'Centro Cultural':       '#7C3AED',\n  'Taller':                '#CA8A04',\n  'Instituto':             '#9A3412',\n  'Educaci\u00f3n':             '#0284C7',\n  'Residencias':           '#BE185D',\n  'Sala de Conciertos':    '#4C1D95',\n  'Teatro':                '#0F766E',\n  'Festival':              '#DC2626',\n  'Fundaci\u00f3n':             '#1E3A5F',\n  'Colectivo':             '#065F46',\n  'Estudio':               '#78716C',\n  'Arquitectura':          '#78350F',\n  'Entretenimiento':       '#B45309',\n  'Servicios Culturales':  '#4B5563',\n  'default':               '#7C3AED',\n};\nfunction tipoColor(t) { return TIPO_COLOR[t] || TIPO_COLOR.default; }\n\n\/\/ \u2500\u2500 STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet allVenues = [];\nlet filtered  = [];\nlet shown     = 0;\nlet filt      = { tipo: 'all', disc: 'all', lugar: 'all', q: '' };\nlet sortMode  = 'random';\nlet tipoDrop, discDrop, lugarDrop;\n\n\/\/ \u2500\u2500 UTILS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction decode(str) {\n  if (!str) return '';\n  const t = document.createElement('textarea');\n  t.innerHTML = str;\n  return t.value;\n}\nfunction esc(s) {\n  return String(s)\n    .replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;')\n    .replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;').replace(\/'\/g,'&#39;');\n}\n\n\/\/ \u2500\u2500 SIDEBAR OPEN\/CLOSE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst $sb = () => document.getElementById('msp-sidebar');\nconst $bd = () => document.getElementById('msp-bd');\nconst openSB  = () => { $sb().classList.add('open'); $bd().classList.add('show'); };\nconst closeSB = () => { $sb().classList.remove('open'); $bd().classList.remove('show'); };\n\n\/\/ \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\nasync function loadVenues() {\n  const res = await fetch(API);\n  if (!res.ok) throw new Error(`HTTP ${res.status}`);\n  const data = await res.json();\n  return data.map(v => ({\n    id:       v.id,\n    nombre:   decode(v.n),\n    url:      v.url,\n    tipo:     v.t || 'default',\n    cats:     v.cats || [v.t],\n    ciudad:   decode(v.c || ''),\n    pais:     decode(v.pais || ''),\n    img:      v.img || '',\n    desc:     decode(v.desc || ''),\n    disc:     (v.disc || []).map(decode),\n    addr:     decode(v.addr || ''),\n    featured: v.featured === true || v.featured === 1 || v.featured === '1',\n  }));\n}\n\n\/\/ \u2500\u2500 SEEDED SHUFFLE (stable per session) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst SESSION_SEED = Math.random();\nfunction seededShuffle(arr) {\n  const a = [...arr];\n  \/\/ Mulberry32 PRNG \u2014 fast, good distribution\n  let s = (SESSION_SEED * 2147483647) | 0;\n  function rand() {\n    s = Math.imul(s ^ (s >>> 15), s | 1);\n    s ^= s + Math.imul(s ^ (s >>> 7), s | 61);\n    return ((s ^ (s >>> 14)) >>> 0) \/ 4294967296;\n  }\n  for (let i = a.length - 1; i > 0; i--) {\n    const j = Math.floor(rand() * (i + 1));\n    [a[i], a[j]] = [a[j], a[i]];\n  }\n  return a;\n}\n\n\/\/ \u2500\u2500 FILTER + SORT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction isFiltered() {\n  return filt.tipo !== 'all' || filt.disc !== 'all' || filt.lugar !== 'all' || filt.q !== '';\n}\n\nfunction applyFilter() {\n  const q = filt.q.toLowerCase();\n  filtered = allVenues.filter(v => {\n    if (filt.tipo  !== 'all' && !(v.cats).includes(filt.tipo)) return false;\n    if (filt.disc  !== 'all' && !v.disc.includes(filt.disc))   return false;\n    if (filt.lugar !== 'all' && v.ciudad !== filt.lugar && v.pais !== filt.lugar) return false;\n    if (q && !v.nombre.toLowerCase().includes(q)) return false;\n    return true;\n  });\n  applySort();\n}\n\nfunction applySort() {\n  if (sortMode === 'random') {\n    \/\/ Seeded shuffle \u2014 stable across filter changes within same session\n    filtered = seededShuffle(filtered);\n  } else {\n    filtered.sort((a, b) => {\n      if (sortMode === 'az')  return a.nombre.localeCompare(b.nombre, 'es');\n      if (sortMode === 'za')  return b.nombre.localeCompare(a.nombre, 'es');\n      if (sortMode === 'new') return b.id - a.id;\n      return 0;\n    });\n  }\n  \/\/ Featured always float to top of main grid when filters are active\n  if (isFiltered()) {\n    filtered.sort((a, b) => (b.featured ? 1 : 0) - (a.featured ? 1 : 0));\n  }\n  shown = 0;\n  render();\n}\n\n\/\/ \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\nfunction render() {\n  const grid     = document.getElementById('msp-grid');\n  const loadMore = document.getElementById('msp-load-more');\n  const empty    = document.getElementById('msp-empty');\n  const counter  = document.getElementById('msp-count');\n  const badge    = document.getElementById('msp-count-badge');\n\n  if (counter) counter.textContent = filtered.length.toLocaleString();\n  badge.textContent = filtered.length.toLocaleString();\n\n  if (filtered.length === 0) {\n    grid.innerHTML = '';\n    empty.classList.add('show');\n    loadMore.style.display = 'none';\n    document.getElementById('msp-featured').style.display = 'none';\n    return;\n  }\n\n  empty.classList.remove('show');\n\n  const featWrap = document.getElementById('msp-featured');\n  const featGrid = document.getElementById('msp-feat-grid');\n  const activeFilter = isFiltered();\n\n  if (!activeFilter) {\n    \/\/ Default view: featured strip (max 3) + non-featured in main grid\n    const featVenues = filtered.filter(v => v.featured).slice(0, 3);\n    if (featVenues.length > 0) {\n      featGrid.innerHTML = featVenues.map(v => renderFeatCard(v)).join('');\n      featWrap.style.display = '';\n    } else {\n      featWrap.style.display = 'none';\n    }\n    const nonFeat = filtered.filter(v => !v.featured);\n    shown = Math.min(BATCH, nonFeat.length);\n    grid.innerHTML = nonFeat.slice(0, shown).map(renderCard).join('');\n    if (shown < nonFeat.length) {\n      loadMore.style.display = 'block';\n      loadMore.textContent = `Ver m\u00e1s espacios \u2193 (${nonFeat.length - shown} restantes)`;\n    } else {\n      loadMore.style.display = 'none';\n    }\n  } else {\n    \/\/ Filtered view: no strip, featured float to top of main grid with badge\n    featWrap.style.display = 'none';\n    shown = Math.min(BATCH, filtered.length);\n    grid.innerHTML = filtered.slice(0, shown).map(renderCard).join('');\n    if (shown < filtered.length) {\n      loadMore.style.display = 'block';\n      loadMore.textContent = `Ver m\u00e1s espacios \u2193 (${filtered.length - shown} restantes)`;\n    } else {\n      loadMore.style.display = 'none';\n    }\n  }\n}\n\nfunction loadMore() {\n  const pool    = isFiltered() ? filtered : filtered.filter(v => !v.featured);\n  const grid    = document.getElementById('msp-grid');\n  const loadBtn = document.getElementById('msp-load-more');\n  const next    = pool.slice(shown, shown + BATCH);\n  grid.insertAdjacentHTML('beforeend', next.map(renderCard).join(''));\n  shown += next.length;\n  if (shown >= pool.length) {\n    loadBtn.style.display = 'none';\n  } else {\n    loadBtn.textContent = `Ver m\u00e1s espacios \u2193 (${pool.length - shown} restantes)`;\n  }\n}\n\n\/\/ \u2500\u2500 CARD TEMPLATES \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction imgOrInit(img, nombre, cls) {\n  if (img) {\n    const full = img.replace(\/-\\d+x\\d+(\\.[a-z]+)$\/i, '$1');\n    return `<img decoding=\"async\" src=\"${esc(full)}\" alt=\"${esc(nombre)}\" loading=\"lazy\" onerror=\"this.src='${esc(img)}';this.onerror=null;\">`;\n  }\n  return `<div class=\"${cls}\">${esc(nombre.charAt(0))}<\/div>`;\n}\n\nfunction renderFeatCard(v) {\n  const color  = tipoColor(v.tipo);\n  const tipo   = esc(v.tipo);\n  const tags   = v.disc.slice(0,3).map(d => `<span class=\"feat-tag\">${esc(d)}<\/span>`).join('');\n  return `\n<a class=\"feat-card\" href=\"${esc(v.url)}\" >\n  <div class=\"feat-card-img\">\n    ${imgOrInit(v.img, v.nombre, 'feat-card-img-init')}\n    <div class=\"feat-star\">\u2605 Destacado<\/div>\n  <\/div>\n  <div class=\"feat-card-info\">\n    <div class=\"feat-tipo-strip\" style=\"background:${color};\">\n      ${tipo} <span>\u203a<\/span>\n    <\/div>\n    <div class=\"feat-body\">\n      <div class=\"feat-name\">${esc(v.nombre)}<\/div>\n      <div class=\"feat-city\">${esc(v.ciudad)}${v.pais && v.pais !== v.ciudad ? ' \u00b7 ' + esc(v.pais) : ''}<\/div>\n      ${v.desc ? `<div class=\"feat-desc\">${esc(v.desc)}<\/div>` : ''}\n      ${tags ? `<div class=\"feat-tags\">${tags}<\/div>` : ''}\n    <\/div>\n  <\/div>\n<\/a>`;\n}\n\nfunction renderCard(v) {\n  const color = tipoColor(v.tipo);\n  const tipo  = v.cats.length > 1\n    ? v.cats.slice(0,2).map(esc).join(' \u00b7 ')\n    : esc(v.tipo);\n  const featBadge = v.featured\n    ? `<div style=\"position:absolute;top:0;left:0;background:var(--yellow);color:var(--black);font-family:var(--font-head);font-size:9px;font-weight:900;letter-spacing:.1em;text-transform:uppercase;padding:4px 9px;border-right:var(--border);border-bottom:var(--border);z-index:2;\">\u2605 Destacado<\/div>`\n    : '';\n  return `\n<a class=\"venue-card\" href=\"${esc(v.url)}\" >\n  <div class=\"venue-card-img\" style=\"position:relative;\">\n    ${imgOrInit(v.img, v.nombre, 'venue-card-img-init')}\n    ${featBadge}\n  <\/div>\n  <div class=\"venue-tipo-strip\" style=\"background:${color};\">${tipo}<\/div>\n  <div class=\"venue-card-body\">\n    <div class=\"venue-name\">${esc(v.nombre)}<\/div>\n    <div class=\"venue-city\">${esc(v.ciudad)}${v.pais && v.pais !== v.ciudad ? ' \u00b7 ' + esc(v.pais) : ''}<\/div>\n    ${v.desc ? `<div class=\"venue-desc\">${esc(v.desc)}<\/div>` : ''}\n  <\/div>\n<\/a>`;\n}\n\n\/\/ \u2500\u2500 DROPDOWNS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction buildDropdown({ triggerId, panelId, searchId, optsId, placeholder, colorFn, onSelect }) {\n  const trigger = document.getElementById(triggerId);\n  const panel   = document.getElementById(panelId);\n  const search  = document.getElementById(searchId);\n  const optsCt  = document.getElementById(optsId);\n  let current = 'all', options = [];\n\n  function renderOpts(q = '') {\n    const f = q ? options.filter(o => o.label.toLowerCase().includes(q.toLowerCase())) : options;\n    optsCt.innerHTML = f.map(o => {\n      const dot = (colorFn && o.value !== 'all')\n        ? `<span class=\"tipo-dot\" style=\"background:${esc(colorFn(o.value))};\"><\/span>`\n        : `<span style=\"width:9px;display:inline-block;flex-shrink:0;\"><\/span>`;\n      return `<button class=\"mesh-sel-opt${o.value === current ? ' active' : ''}\" data-v=\"${esc(o.value)}\">\n        ${dot}<span style=\"flex:1\">${esc(o.label)}<\/span>\n        ${o.count != null ? `<span class=\"mesh-sel-opt-count\">${o.count}<\/span>` : ''}\n      <\/button>`;\n    }).join('');\n  }\n\n  function openDrop() {\n    document.querySelectorAll('.mesh-sel-trigger.open').forEach(t => {\n      if (t !== trigger) { t.classList.remove('open'); t.nextElementSibling?.classList.remove('open'); }\n    });\n    trigger.classList.add('open'); panel.classList.add('open');\n    search.value = ''; renderOpts();\n    setTimeout(() => search.focus(), 50);\n  }\n  function closeDrop() { trigger.classList.remove('open'); panel.classList.remove('open'); }\n\n  trigger.addEventListener('click', e => {\n    e.stopPropagation();\n    panel.classList.contains('open') ? closeDrop() : openDrop();\n  });\n  search.addEventListener('input', () => renderOpts(search.value));\n  search.addEventListener('click', e => e.stopPropagation());\n  panel.addEventListener('click', e => e.stopPropagation());\n\n  optsCt.addEventListener('click', e => {\n    const btn = e.target.closest('.mesh-sel-opt');\n    if (!btn) return;\n    current = btn.dataset.v;\n    const valEl = document.getElementById(triggerId.replace('-trigger', '-val'));\n    if (current === 'all') {\n      valEl.textContent = placeholder; valEl.classList.add('ph');\n      const sq = trigger.querySelector('.trigger-color-sq'); if (sq) sq.remove();\n    } else {\n      valEl.textContent = current; valEl.classList.remove('ph');\n      if (colorFn) {\n        let sq = trigger.querySelector('.trigger-color-sq');\n        if (!sq) {\n          sq = document.createElement('span'); sq.className = 'trigger-color-sq';\n          sq.style.cssText = 'width:9px;height:9px;border:1.5px solid #0a0a0a;display:inline-block;flex-shrink:0;margin-right:6px;';\n          trigger.insertBefore(sq, valEl);\n        }\n        sq.style.background = colorFn(current);\n      }\n    }\n    onSelect(current); closeDrop();\n    if (window.innerWidth <= 860) closeSB();\n  });\n\n  document.addEventListener('click', () => closeDrop());\n\n  return {\n    setOptions(list) { options = list; },\n    setValue(v) { current = v; },\n  };\n}\n\n\/\/ \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\nfunction buildFilterUI(venues) {\n  const tc = {}, dc = {}, cityCount = {}, paisCount = {};\n\n  venues.forEach(v => {\n    (v.cats || [v.tipo]).forEach(t => { tc[t] = (tc[t] || 0) + 1; });\n    v.disc.forEach(d => { dc[d] = (dc[d] || 0) + 1; });\n    if (v.ciudad) cityCount[v.ciudad] = (cityCount[v.ciudad] || 0) + 1;\n    if (v.pais)   paisCount[v.pais]   = (paisCount[v.pais]   || 0) + 1;\n  });\n\n  const countries = Object.entries(paisCount).sort((a,b) => b[1]-a[1])\n    .map(([name, count]) => ({ value: name, label: name, count }));\n  const cities = Object.entries(cityCount).filter(([name]) => !paisCount[name])\n    .sort((a,b) => b[1]-a[1])\n    .map(([name, count]) => ({ value: name, label: name, count }));\n\n  tipoDrop.setOptions([\n    { value: 'all', label: 'Todos los tipos', count: venues.length },\n    ...Object.keys(tc).sort().map(t => ({ value: t, label: t, count: tc[t] })),\n  ]);\n  discDrop.setOptions([\n    { value: 'all', label: 'Todas las disciplinas', count: venues.length },\n    ...Object.keys(dc).sort().map(d => ({ value: d, label: d, count: dc[d] })),\n  ]);\n  lugarDrop.setOptions([\n    { value: 'all', label: 'Todos los lugares', count: venues.length },\n    ...countries, ...cities,\n  ]);\n}\n\n\/\/ \u2500\u2500 NAME SEARCH (filter only \u2014 no dropdown) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction initNameSearch() {\n  const inp = document.getElementById('msp-name-inp');\n  inp.addEventListener('input', () => {\n    filt.q = inp.value.trim();\n    applyFilter();\n  });\n}\n\n\/\/ \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\nfunction resetAll() {\n  filt = { tipo: 'all', disc: 'all', lugar: 'all', q: '' };\n  [tipoDrop, discDrop, lugarDrop].forEach(d => d.setValue('all'));\n  [\n    ['tipo-val',  'Todos los tipos'],\n    ['disc-val',  'Todas las disciplinas'],\n    ['lugar-val', 'Todos los lugares'],\n  ].forEach(([id, txt]) => {\n    const el = document.getElementById(id);\n    el.textContent = txt; el.classList.add('ph');\n    const sq = el.closest('.mesh-sel-trigger')?.querySelector('.trigger-color-sq');\n    if (sq) sq.remove();\n  });\n  document.getElementById('msp-name-inp').value = '';\n  applyFilter();\n}\n\n\/\/ \u2500\u2500 SORT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction initSort() {\n  document.getElementById('msp-sort-sel').addEventListener('change', function() {\n    sortMode = this.value;\n    applySort();\n  });\n}\n\n\/\/ \u2500\u2500 SWIPE SIDEBAR CLOSE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction initSidebarSwipe() {\n  const sb = document.getElementById('msp-sidebar');\n  let tsX = 0;\n  sb.addEventListener('touchstart', e => { tsX = e.touches[0].clientX; }, { passive: true });\n  sb.addEventListener('touchmove', e => {\n    if (window.innerWidth > 860) return;\n    const dx = Math.max(0, tsX - e.touches[0].clientX);\n    sb.style.transition = 'none';\n    sb.style.transform = `translateX(-${dx}px)`;\n  }, { passive: true });\n  sb.addEventListener('touchend', e => {\n    sb.style.transition = ''; sb.style.transform = '';\n    if (tsX - e.changedTouches[0].clientX > 60 && window.innerWidth <= 860) closeSB();\n  }, { passive: true });\n}\n\n\/\/ \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\nasync function init() {\n  \/\/ Build dropdowns\n  tipoDrop = buildDropdown({\n    triggerId: 'tipo-trigger', panelId: 'tipo-panel',\n    searchId: 'tipo-search', optsId: 'tipo-opts',\n    placeholder: 'Todos los tipos', colorFn: tipoColor,\n    onSelect: v => { filt.tipo = v; applyFilter(); },\n  });\n  discDrop = buildDropdown({\n    triggerId: 'disc-trigger', panelId: 'disc-panel',\n    searchId: 'disc-search', optsId: 'disc-opts',\n    placeholder: 'Todas las disciplinas', colorFn: null,\n    onSelect: v => { filt.disc = v; applyFilter(); },\n  });\n  lugarDrop = buildDropdown({\n    triggerId: 'lugar-trigger', panelId: 'lugar-panel',\n    searchId: 'lugar-search', optsId: 'lugar-opts',\n    placeholder: 'Todos los lugares', colorFn: null,\n    onSelect: v => { filt.lugar = v; applyFilter(); },\n  });\n\n  initSort();\n  initNameSearch();\n  initSidebarSwipe();\n\n  \/\/ Events\n  document.getElementById('msp-sb-x').addEventListener('click', closeSB);\n  document.getElementById('msp-bd').addEventListener('click', closeSB);\n  document.getElementById('msp-mob-filter').addEventListener('click', openSB);\n  document.getElementById('msp-rst').addEventListener('click', resetAll);\n  document.getElementById('msp-empty-rst').addEventListener('click', resetAll);\n  document.getElementById('msp-load-more').addEventListener('click', loadMore);\n\n  \/\/ Fetch\n  try {\n    allVenues = await loadVenues();\n  } catch (e) {\n    console.error('MESH Spaces:', e);\n    document.getElementById('msp-loading').innerHTML =\n      '<div class=\"ld-text\">Error cargando espacios.<\/div>';\n    return;\n  }\n\n  buildFilterUI(allVenues);\n  filtered = [...allVenues];\n  applySort(); \/\/ initial render\n  document.getElementById('msp-loading').style.display = 'none';\n}\n\nif (document.readyState === 'loading') {\n  document.addEventListener('DOMContentLoaded', init);\n} else {\n  setTimeout(init, 0);\n}\n})();\n<\/script>\n\n<!--\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n  PHP SNIPPET UPDATE REQUIRED\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n  In Snippet A (map-venues endpoint), add to each item:\n  'featured' => get_post_meta($post->ID, 'featured_venue', true) === '1',\n\n  Without this, no venues will appear in the Featured strip\n  (graceful \u2014 page still works, featured section just hidden).\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n-->\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>Espacios \u2014 espacios \u2715 Buscar por nombre Tipo de espacio Todos los tipos Disciplina Todas las disciplinas Lugar Todos los [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","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-47659","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47659","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=47659"}],"version-history":[{"count":71,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47659\/revisions"}],"predecessor-version":[{"id":48001,"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/pages\/47659\/revisions\/48001"}],"wp:attachment":[{"href":"https:\/\/themesh.art\/en\/wp-json\/wp\/v2\/media?parent=47659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}