{"id":25399,"date":"2026-07-28T17:16:06","date_gmt":"2026-07-28T23:16:06","guid":{"rendered":"https:\/\/urbanista.mx\/?page_id=25399"},"modified":"2026-08-13T20:13:48","modified_gmt":"2026-08-14T02:13:48","slug":"form-agenda","status":"publish","type":"page","link":"https:\/\/urbanista.mx\/en\/form-agenda\/","title":{"rendered":"\u00a1Agenda tu tour! &#8211; Urbanista"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"es-MX\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n<title>Agenda tu tour \u00b7 Urbanista<\/title>\n<meta name=\"description\" content=\"Agenda tu tour a un departamento Urbanista en CDMX. Sin aval, sin comisi\u00f3n de broker.\">\n<meta name=\"robots\" content=\"noindex, follow\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Bebas+Neue&#038;family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,700&#038;display=swap\" rel=\"stylesheet\">\n\n<style>\n\/* ============================================================\n   URBANISTA \u00b7 Agenda  (v6)\n   ============================================================ *\/\n:root{\n  --navy-dark:#003A4A; --navy:#004E64; --navy-light:#006580;\n  --mist:#EDF2F3; --concrete:#C9D6D9; --white:#fff; --ink:#0B1416;\n  --line:rgba(255,255,255,.18);\n  --shadow:0 1px 2px rgba(0,42,55,.06), 0 12px 32px -12px rgba(0,42,55,.18);\n  --r:14px; --ease:cubic-bezier(.2,.7,.2,1);\n}\n*{box-sizing:border-box}\nhtml,body{margin:0;padding:0}\nhtml{-webkit-text-size-adjust:100%}\nbody{font-family:'DM Sans',system-ui,-apple-system,sans-serif;color:var(--ink);background:var(--mist);line-height:1.5;-webkit-font-smoothing:antialiased}\nbutton,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}\nimg{max-width:100%;display:block}\n.u-display{font-family:'Bebas Neue',Impact,sans-serif;font-weight:400;letter-spacing:.01em;line-height:.92}\n.u-eyebrow{font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase}\n\n.shell{display:grid;grid-template-columns:minmax(0,58%) minmax(0,42%);min-height:100vh;min-height:100dvh}\n.main{grid-column:1;grid-row:1}\n.aside{grid-column:2;grid-row:1}\n\n\/* ---------- Navy ---------- *\/\n.aside{position:relative;background:var(--navy-dark);color:var(--white);padding:40px 44px;display:flex;flex-direction:column;gap:30px;overflow:hidden;isolation:isolate}\n.reel{position:absolute;inset:-6% -4%;z-index:0;display:grid;grid-template-columns:1fr 1fr;gap:14px;opacity:.34}\n.reel-col{display:flex;flex-direction:column;gap:14px;animation:reelUp 46s linear infinite}\n.reel-col--down{animation-name:reelDown;animation-duration:54s}\n.reel-col img{width:100%;height:auto;border-radius:6px;object-fit:cover;filter:grayscale(.35) contrast(1.05)}\n@keyframes reelUp{from{transform:translateY(0)}to{transform:translateY(-50%)}}\n@keyframes reelDown{from{transform:translateY(-50%)}to{transform:translateY(0)}}\n.aside::after{content:\"\";position:absolute;inset:0;z-index:1;background:linear-gradient(195deg,rgba(0,58,74,.80) 0%,rgba(0,58,74,.93) 50%,#003A4A 100%)}\n.aside > *:not(.reel):not(.hero-slides){position:relative;z-index:2}\n\n.brand{display:flex;align-items:center;justify-content:flex-end;gap:16px}\n.brand img.logo{width:112px}\n\n.pitch{margin-top:auto}\n.pitch h1{margin:0 0 14px;font-size:clamp(36px,3.6vw,54px)}\n.pitch h1 em{font-style:normal;color:var(--concrete);display:block}\n.pitch p{margin:0;max-width:32ch;color:rgba(255,255,255,.74);font-size:15px}\n\n.instruccion{display:flex;align-items:center;gap:11px;margin:0 0 -16px;font-size:13.5px;\n  line-height:1.45;color:rgba(255,255,255,.66);max-width:34ch}\n.instruccion .flecha{flex:none;font-size:20px;line-height:1;color:var(--concrete);animation:empujon 2.4s var(--ease) infinite}\n@keyframes empujon{0%,100%{transform:translateX(0)}50%{transform:translateX(-6px)}}\n.placa{border:1px solid var(--line);border-radius:4px;padding:18px 22px 16px;background:rgba(0,42,55,.5);backdrop-filter:blur(6px)}\n.placa-head{display:flex;justify-content:space-between;align-items:baseline;padding-bottom:12px;margin-bottom:6px;border-bottom:1px solid var(--line)}\n.placa-head .u-eyebrow{color:var(--concrete)}\n.placa-head span:last-child{font-size:11px;color:rgba(255,255,255,.5);font-variant-numeric:tabular-nums}\n.placa-row{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:9px 0;border-bottom:1px solid rgba(255,255,255,.08)}\n.placa-row:last-child{border-bottom:0;padding-bottom:0}\n.placa-row dt{font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.5);white-space:nowrap}\n.placa-row dd{margin:0;text-align:right;font-family:'Bebas Neue',sans-serif;font-size:19px;letter-spacing:.02em;color:rgba(255,255,255,.3);transition:color .3s var(--ease);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:62%}\n.placa-row dd.is-set{color:var(--white)}\n.placa-row dd.just-set{animation:pop .45s var(--ease)}\n@keyframes pop{0%{opacity:0;transform:translateY(6px)}100%{opacity:1;transform:none}}\n\n.trust{margin-top:auto;display:flex;flex-wrap:wrap;gap:8px;padding:0}\n.trust li{list-style:none;font-size:11.5px;color:rgba(255,255,255,.78);border:1px solid var(--line);border-radius:100px;padding:6px 12px;background:rgba(0,42,55,.4)}\n\n\/* ---------- Hero m\u00f3vil (carrusel de fondo) ---------- *\/\n.hero-slides{display:none}\n\n\/* ---------- Blanco ---------- *\/\n.main{background:var(--white);display:flex;flex-direction:column;min-width:0;min-height:100vh;min-height:100dvh}\n.progress{position:sticky;top:0;z-index:5;background:var(--white)}\n.progress-bar{height:3px;background:var(--mist)}\n.progress-fill{height:100%;width:0;background:var(--navy);transition:width .45s var(--ease)}\n.progress-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;\n  padding:16px 44px;font-size:12px;color:#5B6E73;width:100%;max-width:708px;margin:0 auto}\n.btn-back{background:none;border:0;padding:6px 0;cursor:pointer;color:#5B6E73;display:inline-flex;align-items:center;gap:7px;font-size:12.5px;border-radius:6px}\n.btn-back:hover{color:var(--navy)}\n.btn-back[hidden]{display:none}\n.step-count{font-variant-numeric:tabular-nums;letter-spacing:.1em;text-transform:uppercase;font-size:11px;font-weight:700;color:var(--navy-light)}\n\n.stage{flex:1;display:flex;align-items:center;justify-content:center;padding:8px 44px 56px}\n.stage-inner{width:100%;max-width:620px;margin-left:auto;margin-right:auto}\n\n.slide{display:none;animation:enter .38s var(--ease)}\n.slide.is-active{display:block}\n@keyframes enter{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}\n\n.kicker{color:var(--navy-light);margin:0 0 10px}\n.q-title{margin:0 0 8px;font-size:clamp(30px,3.2vw,42px);color:var(--navy-dark)}\n.q-help{margin:0 0 26px;color:#5B6E73;font-size:14.5px;max-width:48ch}\n\n.campo input,.campo select{width:100%;padding:18px;border:1.5px solid var(--concrete);border-radius:var(--r);background:var(--white);font-size:17px;transition:border-color .18s}\n.campo input:focus,.campo select:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(0,101,128,.12)}\n.campo input::placeholder{color:#9FB0B4}\n.campo.has-error input,.campo.has-error select{border-color:#B0243A}\n.err{display:none;color:#B0243A;font-size:13px;margin-top:8px}\n.campo.has-error .err{display:block}\n.tel-row{display:flex;gap:10px}\n.tel-row select{width:auto;flex:none;min-width:138px;appearance:none;padding-right:40px;cursor:pointer;\n  background-image:url(\"data:image\/svg+xml;utf8,<svg xmlns='http:\/\/www.w3.org\/2000\/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23004E64' stroke-width='2.4'><path d='M6 9l6 6 6-6'\/><\/svg>\");\n  background-repeat:no-repeat;background-position:right 16px center}\n.tel-row input{flex:1;min-width:0}\n\n.options{display:grid;gap:10px}\n.options.cols-2{grid-template-columns:1fr 1fr}\n.opt{display:flex;align-items:center;gap:14px;text-align:left;width:100%;background:var(--white);border:1.5px solid var(--concrete);border-radius:var(--r);padding:15px 18px;cursor:pointer;transition:border-color .18s,background .18s,transform .12s}\n.opt:hover{border-color:var(--navy);background:#F7FAFB}\n.opt:active{transform:scale(.99)}\n.opt.is-selected{border-color:var(--navy);background:var(--navy);color:var(--white)}\n.opt[disabled]{opacity:.5;cursor:not-allowed}\n.opt[disabled]:hover{border-color:var(--concrete);background:var(--white)}\n.opt-key{flex:none;width:26px;height:26px;border-radius:6px;background:var(--mist);color:var(--navy);font-size:11px;font-weight:700;display:grid;place-items:center;transition:.18s}\n.opt.is-selected .opt-key{background:rgba(255,255,255,.2);color:var(--white)}\n.opt-main{flex:1;min-width:0}\n.opt-label{font-weight:500;font-size:15.5px;display:block}\n.opt-note{font-size:12.5px;color:#728488;display:block;margin-top:1px;overflow:hidden;text-overflow:ellipsis}\n.opt.is-selected .opt-note{color:rgba(255,255,255,.75)}\n.opt-tag{flex:none;font-size:12px;font-weight:500;color:var(--navy);background:var(--mist);border-radius:10px;padding:6px 11px;white-space:nowrap;text-align:right;line-height:1.25}\n.opt-tag small{display:block;font-size:10.5px;font-weight:400;opacity:.72;letter-spacing:.02em}\n.opt.is-selected .opt-tag{background:rgba(255,255,255,.18);color:var(--white)}\n\n.cta{display:inline-flex;align-items:center;justify-content:center;gap:10px;background:var(--navy);color:var(--white);border:0;border-radius:var(--r);padding:18px 34px;font-size:16px;font-weight:500;cursor:pointer;margin-top:26px;box-shadow:var(--shadow);transition:background .18s,transform .12s}\n.cta:hover{background:var(--navy-light)}\n.cta:active{transform:scale(.99)}\n.cta[disabled]{background:var(--concrete);color:#7C9095;box-shadow:none;cursor:not-allowed}\n.cta--full{width:100%}\n.cta[hidden],.btn-next[hidden]{display:none!important}\n.hint{display:block;margin-top:12px;font-size:12.5px;color:#728488}\n.hint a{color:var(--navy)}\n.hint kbd{background:var(--mist);border-radius:4px;padding:1px 6px;font-size:11px;font-family:inherit}\n\n\/* Revisi\u00f3n *\/\n.check{border:1.5px solid var(--concrete);border-radius:var(--r);overflow:hidden}\n.check-row{display:flex;align-items:center;gap:14px;padding:16px 18px;border-bottom:1px solid var(--mist);background:var(--white)}\n.check-row:last-child{border-bottom:0}\n.check-tick{flex:none;width:24px;height:24px;border-radius:50%;background:var(--navy);color:var(--white);display:grid;place-items:center}\n.check-body{flex:1;min-width:0;margin:0}\n.check-body dt{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:#8A9CA0}\n.check-body dd{margin:2px 0 0;font-size:15.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis}\n.check-edit{background:none;border:0;color:var(--navy);font-size:13px;cursor:pointer;padding:6px 8px;border-radius:6px;text-decoration:underline}\n.check-edit:hover{background:var(--mist)}\n.aviso{display:none;margin-top:14px;color:#B0243A;font-size:13px}\n.aviso.is-on{display:block}\n.aviso a{color:var(--navy)}\n\n\/* Listo *\/\n.done{text-align:center;max-width:520px;margin:0 auto}\n.done .seal{width:64px;height:64px;border-radius:50%;background:var(--navy);color:var(--white);display:grid;place-items:center;margin:0 auto 22px}\n.done h2{font-size:clamp(34px,3.4vw,46px);color:var(--navy-dark);margin:0 0 12px}\n.done p{color:#5B6E73;margin:0 0 22px}\n#meetWrap{margin:26px 0 22px;text-align:left}\n#meetWrap.is-on{min-height:660px}\n.meetings-iframe-container{width:100%;min-height:660px}\n.meetings-iframe-container iframe{width:100%!important;min-height:660px;border:0}\n.meet-cargando{color:#8A9CA0;font-size:14px;text-align:center;padding:28px 0}\n.meet-alterno{display:block;text-align:center;font-size:13px;color:#728488;margin-bottom:18px}\n.meet-alterno a{color:var(--navy)}\n\n:focus-visible{outline:2px solid var(--navy-light);outline-offset:3px}\n\n#hsFrame{position:absolute;left:-9999px;top:0;width:620px;opacity:0;pointer-events:none}\n#hsFrame.visible{position:static;left:auto;width:auto;opacity:1;pointer-events:auto;margin-top:22px}\n#hsFrame .hs-form-field{margin:0 0 16px}\n#hsFrame .hs-form-field > label{display:block;font-size:12.5px;font-weight:500;color:#5B6E73;margin-bottom:8px}\n#hsFrame .hs-field-desc{font-size:12.5px;color:#8A9CA0;margin:-4px 0 10px}\n#hsFrame input[type=text],#hsFrame input[type=email],#hsFrame input[type=tel],\n#hsFrame input[type=number],#hsFrame select,#hsFrame textarea{\n  width:100%!important;padding:16px;border:1.5px solid var(--concrete);border-radius:var(--r);\n  background:var(--white);font-size:16px}\n#hsFrame input:focus,#hsFrame select:focus,#hsFrame textarea:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(0,101,128,.12)}\n#hsFrame ul{list-style:none;padding:0;margin:0}\n#hsFrame .hs-error-msgs label,#hsFrame .hs-error-msg{color:#B0243A;font-size:12.5px}\n#hsFrame .legal-consent-container{font-size:12.5px;color:#8A9CA0;margin-top:6px}\n#hsFrame .hs-button{display:flex;align-items:center;justify-content:center;width:100%;\n  background:var(--navy);color:var(--white);border:0;border-radius:var(--r);\n  padding:18px 34px;font-size:16px;font-weight:500;cursor:pointer;margin-top:22px;box-shadow:var(--shadow)}\n#hsFrame .hs-button:hover{background:var(--navy-light)}\n#hsFrame .hs-recaptcha,#hsFrame .grecaptcha-badge{margin:6px 0}\n#hsFrame .hs-form-field.oculto{display:none}\n#hsCargando{color:#8A9CA0;font-size:14px;margin-top:20px}\n\n\/* Panel de diagn\u00f3stico (?debug=1) *\/\n#diag{display:none;position:fixed;right:14px;bottom:14px;z-index:99;width:min(440px,calc(100vw - 28px));\n  max-height:56vh;overflow:auto;background:#0B1416;color:#D5E3E6;border-radius:12px;\n  font:12px\/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;box-shadow:0 18px 44px rgba(0,0,0,.4)}\n#diag.is-on{display:block}\n#diag header{position:sticky;top:0;background:#0B1416;padding:12px 14px;border-bottom:1px solid #1E2E32;\n  display:flex;justify-content:space-between;align-items:center;font-weight:700;letter-spacing:.08em;text-transform:uppercase;font-size:10.5px}\n#diag header button{background:none;border:0;color:#7FB2BE;cursor:pointer;font:inherit}\n#diag .lineas{padding:10px 14px 14px}\n#diag p{margin:0 0 8px;white-space:pre-wrap;word-break:break-word}\n#diag p.warn{color:#FFC98A}\n#diag p.bad{color:#FF8B9E}\n#diag p.good{color:#8EE6A8}\n#diag code{color:#7FB2BE}\n\n\/* ============================================================\n   Blindaje: el tema de WordPress pisa colores y tipograf\u00edas.\n   Se fuerza solo dentro de la landing.\n   ============================================================ *\/\n.shell,.shell *{font-family:'DM Sans',system-ui,-apple-system,sans-serif}\n.shell .u-display,.shell .u-display *{font-family:'Bebas Neue',Impact,sans-serif}\n.shell button{background-image:none;text-transform:none;letter-spacing:normal;box-shadow:none}\n.shell .btn-back{background:none!important;background-color:transparent!important;border:0!important;box-shadow:none!important;\n  color:#5B6E73!important;font-size:12.5px!important;font-weight:500!important;line-height:1.4!important;\n  padding:8px 14px!important;margin:0!important;border-radius:8px!important;min-height:0!important;height:auto!important;width:auto!important;\n  text-decoration:none!important;transition:background .18s var(--ease),color .18s var(--ease)}\n.shell .btn-back:hover,.shell .btn-back:focus{background:var(--mist)!important;background-color:var(--mist)!important;color:var(--navy)!important;border:0!important;box-shadow:none!important}\n.shell .btn-back:active{background:var(--concrete)!important;color:var(--navy-dark)!important}\n.shell .btn-back[hidden]{display:none!important}\n.shell a{text-decoration:none}\n.shell .stage{justify-content:center!important}\n.shell .stage-inner{margin-left:auto!important;margin-right:auto!important}\n.shell .q-title,.shell .done h2{color:var(--navy-dark)!important}\n.shell .kicker{color:var(--navy-light)!important}\n.shell .q-help,.shell .done p{color:#5B6E73!important}\n.shell .opt{background:var(--white)!important;border-color:var(--concrete)!important;color:var(--ink)!important}\n.shell .opt:hover{border-color:var(--navy)!important;background:#F7FAFB!important}\n.shell .opt .opt-label{color:var(--ink)!important;font-weight:500!important}\n.shell .opt .opt-note{color:#728488!important}\n.shell .opt .opt-key{background:var(--mist)!important;color:var(--navy)!important}\n.shell .opt .opt-tag{background:var(--mist)!important;color:var(--navy)!important}\n.shell .opt .opt-tag small{color:var(--navy)!important}\n.shell .opt.is-selected .opt-tag small{color:var(--white)!important}\n.shell .opt.is-selected{background:var(--navy)!important;border-color:var(--navy)!important;color:var(--white)!important}\n.shell .opt.is-selected .opt-label{color:var(--white)!important}\n.shell .opt.is-selected .opt-note{color:rgba(255,255,255,.75)!important}\n.shell .opt.is-selected .opt-key,.shell .opt.is-selected .opt-tag{background:rgba(255,255,255,.2)!important;color:var(--white)!important}\n.shell .cta{background:var(--navy)!important;color:var(--white)!important}\n.shell .cta:hover{background:var(--navy-light)!important}\n.shell .cta[disabled]{background:var(--concrete)!important;color:#7C9095!important}\n.shell .campo input,.shell .campo select{color:var(--ink)!important;background:var(--white)!important;border-color:var(--concrete)!important}\n.shell .check-row{background:var(--white)!important}\n.shell .check-body dt{color:#8A9CA0!important}\n.shell .check-body dd{color:var(--ink)!important}\n.shell .check-edit{color:var(--navy)!important;background:none!important}\n.shell .check-tick{background:var(--navy)!important;color:var(--white)!important}\n.shell .aside,.shell .aside *{color:var(--white)}\n.shell .aside .placa-row dt,.shell .aside .placa-head span:last-child{color:rgba(255,255,255,.5)!important}\n.shell .aside .pitch h1 em{color:var(--concrete)!important}\n.shell .aside .pitch p{color:rgba(255,255,255,.74)!important}\n\n@media (max-width:1024px){\n  .shell{grid-template-columns:1fr;min-height:0}\n  .main,.aside{grid-column:1}\n  .aside{grid-row:1;min-height:46vh;min-height:46dvh;padding:18px 20px 20px;gap:14px;justify-content:flex-end}\n  .main{grid-row:2}\n  .aside .reel{display:none}\n  .aside .hero-slides{display:block;position:absolute;inset:0;z-index:0}\n  .aside .hero-slides img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1.1s var(--ease)}\n  .aside .hero-slides img.is-on{opacity:1}\n  .aside::after{background:linear-gradient(180deg,rgba(0,58,74,.28) 0%,rgba(0,58,74,.42) 45%,rgba(0,58,74,.90) 100%)}\n  .aside .pitch h1{font-size:33px;text-shadow:0 2px 14px rgba(0,20,26,.35)}\n  .aside .pitch p,.placa,.instruccion{display:none}\n  .aside .pitch{margin-top:auto}\n  .brand img.logo{width:92px}\n  .trust{margin-top:2px}\n  .trust li:nth-child(n+3){display:none}\n  .progress-meta,.stage{padding-left:20px;padding-right:20px}\n  .main{min-height:0}\n  .stage{padding-top:4px;padding-bottom:40px;align-items:flex-start}\n  .q-title{font-size:27px}\n  .q-help{margin-bottom:20px;font-size:14px}\n  .options.cols-2{grid-template-columns:1fr}\n  .cta{width:100%}\n  .tel-row select{min-width:118px;font-size:15px}\n  .opt-tag{display:none}\n}\n@media (prefers-reduced-motion:reduce){\n  .reel-col,.strip-track{animation:none}\n  *{animation-duration:.01ms!important;transition-duration:.01ms!important}\n}\n<\/style>\n<script\n  src=\"https:\/\/performance.vambeai.com\/website-tracker\/v1.js\"\n  data-client-id=\"10e16990-8362-4d21-ad96-36a8d132c638\"\n  defer\n><\/script>\n<\/head>\n<body>\n\n<div class=\"shell\">\n\n  <aside class=\"aside\">\n    <div class=\"reel\" aria-hidden=\"true\"><div class=\"reel-col\" id=\"reelA\"><\/div><div class=\"reel-col reel-col--down\" id=\"reelB\"><\/div><\/div>\n    <div class=\"hero-slides\" id=\"heroSlides\" aria-hidden=\"true\"><\/div>\n\n    <div class=\"brand\">\n      <a href=\"https:\/\/urbanista.mx\/\"><img decoding=\"async\" class=\"logo\" src=\"https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/Logo-blanco-Urbanista.png.png\" alt=\"Urbanista\"><\/a>\n    <\/div>\n\n    <div class=\"pitch\">\n      <h1 class=\"u-display\">Agenda tu tour.<\/h1>\n      <p>Tu pr\u00f3ximo departamento est\u00e1 a un minuto de distancia. Solo necesitamos cinco datos para agendar tu visita.<\/p>\n    <\/div>\n\n    <p class=\"instruccion\">\n      <span class=\"flecha\" aria-hidden=\"true\">\u2190<\/span>\n      <span>Ve contestando las preguntas de la izquierda. Aqu\u00ed se arma tu solicitud.<\/span>\n    <\/p>\n\n    <dl class=\"placa\" id=\"placa\">\n      <div class=\"placa-head\"><span class=\"u-eyebrow\">Tu solicitud<\/span><span id=\"placaCount\">0 \/ 5<\/span><\/div>\n      <div id=\"placaBody\"><\/div>\n    <\/dl>\n\n    <ul class=\"trust\">\n      <li>Sin aval ni fianza<\/li>\n      <li>Aprobaci\u00f3n en 24 h<\/li>\n      <li>9 comunidades en CDMX<\/li>\n      <li>Amenidades premium<\/li>\n    <\/ul>\n  <\/aside>\n\n  <main class=\"main\">\n    <div class=\"progress\">\n      <div class=\"progress-bar\"><div class=\"progress-fill\" id=\"bar\"><\/div><\/div>\n      <div class=\"progress-meta\">\n        <button class=\"btn-back\" id=\"back\" hidden>\u2190 Regresar<\/button>\n        <span class=\"step-count\" id=\"count\">&nbsp;<\/span>\n      <\/div>\n    <\/div>\n\n    <div class=\"stage\">\n      <div class=\"stage-inner\">\n        <div id=\"slides\"><\/div>\n\n        <section class=\"slide\" id=\"slideCheck\">\n          <p class=\"u-eyebrow kicker\">\u00daltimo paso<\/p>\n          <h2 class=\"u-display q-title\">Ya casi terminamos<\/h2>\n          <p class=\"q-help\">Antes de confirmar, puedes revisar y editar cualquier dato.<\/p>\n          <dl class=\"check\" id=\"checkList\"><\/dl>\n          <input id=\"empresa_web\" name=\"empresa_web\" type=\"text\" tabindex=\"-1\" autocomplete=\"off\" aria-hidden=\"true\" style=\"position:absolute;left:-9999px;opacity:0;height:0;width:0\">\n          <div id=\"hsFrame\"><\/div>\n          <p id=\"hsCargando\" hidden>Preparando tu solicitud\u2026<\/p>\n          <button class=\"cta cta--full\" id=\"enviar\">Confirmar y agendar mi visita<\/button>\n          <p class=\"hint\" id=\"notaEmbed\" hidden>Tus datos ya quedaron cargados. Solo confirma el env\u00edo para apartar tu visita.<\/p>\n          <p class=\"aviso\" id=\"aviso\"><\/p>\n          <span class=\"hint\">Sin costo y sin compromiso. Consulta el <a href=\"https:\/\/urbanista.mx\/aviso-de-privacidad\/\" target=\"_blank\" rel=\"noopener\">aviso de privacidad<\/a>.<\/span>\n        <\/section>\n\n        <section class=\"slide\" id=\"slideDone\">\n          <div class=\"done\">\n            <div class=\"seal\" aria-hidden=\"true\"><svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"\/><\/svg><\/div>\n            <h2 class=\"u-display\" id=\"doneTitle\">Listo, tu visita est\u00e1 apartada<\/h2>\n            <p id=\"doneTexto\">Un asesor Urbanista te contacta para confirmar d\u00eda, hora y direcci\u00f3n.<\/p>\n            <div id=\"meetWrap\"><\/div>\n            <span class=\"meet-alterno\" id=\"meetAlterno\" hidden>\u00bfNo carga el calendario? <a id=\"meetLink\" target=\"_blank\" rel=\"noopener\">\u00c1brelo en una pesta\u00f1a nueva<\/a><\/span>\n          <\/div>\n        <\/section>\n      <\/div>\n    <\/div>\n  <\/main>\n<\/div>\n\n<aside id=\"diag\">\n  <header><span>Diagn\u00f3stico Urbanista<\/span><span><button type=\"button\" onclick=\"probarCampos()\">probar campos<\/button> \u00b7 <button type=\"button\" onclick=\"document.getElementById('diag').classList.remove('is-on')\">cerrar \u2715<\/button><\/span><\/header>\n  <div class=\"lineas\" id=\"diagBody\"><\/div>\n<\/aside>\n\n<script>\n\/* ============================================================\n   CONFIG\n   ============================================================ *\/\nconst CONFIG = {\n  portalId : '47830887',\n  formId   : '1c382be5-c8d7-4b18-a7bd-a439f410f56f',\n  region   : 'na1',\n  whatsapp : '525594886680',\n  thankYouUrl  : '',\n  edificioFijo : '',\n  ladaDefault  : '+52',\n  modoEnvio : 'embed',\n  webhookRespaldo : '',\n  camposFijos : {},\n  consentimiento : false,\n  depurar : true\n};\n\n\/* Ladas m\u00e1s usadas *\/\nconst LADAS = [\n  ['+52','\ud83c\uddf2\ud83c\uddfd +52 M\u00e9xico'], ['+1','\ud83c\uddfa\ud83c\uddf8 +1 EE.UU. \/ Canad\u00e1'], ['+34','\ud83c\uddea\ud83c\uddf8 +34 Espa\u00f1a'],\n  ['+54','\ud83c\udde6\ud83c\uddf7 +54 Argentina'], ['+57','\ud83c\udde8\ud83c\uddf4 +57 Colombia'], ['+56','\ud83c\udde8\ud83c\uddf1 +56 Chile'],\n  ['+51','\ud83c\uddf5\ud83c\uddea +51 Per\u00fa'], ['+55','\ud83c\udde7\ud83c\uddf7 +55 Brasil'], ['+58','\ud83c\uddfb\ud83c\uddea +58 Venezuela'],\n  ['+593','\ud83c\uddea\ud83c\udde8 +593 Ecuador'], ['+591','\ud83c\udde7\ud83c\uddf4 +591 Bolivia'], ['+598','\ud83c\uddfa\ud83c\uddfe +598 Uruguay'],\n  ['+595','\ud83c\uddf5\ud83c\uddfe +595 Paraguay'], ['+506','\ud83c\udde8\ud83c\uddf7 +506 Costa Rica'], ['+507','\ud83c\uddf5\ud83c\udde6 +507 Panam\u00e1'],\n  ['+502','\ud83c\uddec\ud83c\uddf9 +502 Guatemala'], ['+503','\ud83c\uddf8\ud83c\uddfb +503 El Salvador'], ['+504','\ud83c\udded\ud83c\uddf3 +504 Honduras'],\n  ['+505','\ud83c\uddf3\ud83c\uddee +505 Nicaragua'], ['+53','\ud83c\udde8\ud83c\uddfa +53 Cuba'], ['+1809','\ud83c\udde9\ud83c\uddf4 +1809 Rep. Dominicana'],\n  ['+351','\ud83c\uddf5\ud83c\uddf9 +351 Portugal'], ['+33','\ud83c\uddeb\ud83c\uddf7 +33 Francia'], ['+39','\ud83c\uddee\ud83c\uddf9 +39 Italia'],\n  ['+49','\ud83c\udde9\ud83c\uddea +49 Alemania'], ['+44','\ud83c\uddec\ud83c\udde7 +44 Reino Unido'], ['+41','\ud83c\udde8\ud83c\udded +41 Suiza'],\n  ['+31','\ud83c\uddf3\ud83c\uddf1 +31 Pa\u00edses Bajos'], ['+972','\ud83c\uddee\ud83c\uddf1 +972 Israel'], ['+61','\ud83c\udde6\ud83c\uddfa +61 Australia'],\n  ['+81','\ud83c\uddef\ud83c\uddf5 +81 Jap\u00f3n'], ['+82','\ud83c\uddf0\ud83c\uddf7 +82 Corea del Sur'], ['+86','\ud83c\udde8\ud83c\uddf3 +86 China'],\n  ['+91','\ud83c\uddee\ud83c\uddf3 +91 India']\n];\n\n\/* ============================================================\n   PRECIOS \u00b7 AGOSTO 2026\n   Precio \"desde\" por edificio y tipo de depa.\n   Regla: si un edificio tiene dos productos del mismo tipo\n   (ej. Studio y Studio Plus, One Bed y One Stunning),\n   aqu\u00ed va SOLO el m\u00e1s barato de ese tipo.\n   Tipo sin precio (omitido) = se muestra bloqueado como \"No disponible\".\n   Las llaves deben coincidir con el \"valor\" del edificio y del tipo.\n   ============================================================ *\/\nconst PRECIOS = {\n  'In\u00e9s':      { 'Studio': 27950, '1 Rec\u00e1mara': 39350 },\n  'Josefa':    { 'Studio': 27950, '1 Rec\u00e1mara': 40150, '2 Rec\u00e1maras': 43150 },\n  'Magda':     { 'Studio': 24350, '1 Rec\u00e1mara': 36250, '2 Rec\u00e1maras': 39750 },\n  'Amalia':    { 'Studio': 25300, '1 Rec\u00e1mara': 32550 },\n  'Joaquina':  { '1 Rec\u00e1mara': 27750 },\n  'Matilde':   { 'Studio': 16050 },\n  'Leona':     { 'Studio': 35350 },\n  'Natalia':   { '2 Rec\u00e1maras': 23350 },\n  'Enriqueta': null \/* Aurora: pr\u00f3ximamente, muestra tipos sin precio *\/\n};\nconst precioTxt = n => 'Desde $' + Number(n).toLocaleString('en-US');\n\n\/* ============================================================\n   SLIDES\n   ============================================================ *\/\nconst PREGUNTAS = [\n  { id:'nombre', tipo:'texto', campo:'firstname',\n    kicker:'Empecemos', titulo:'\u00bfCu\u00e1l es tu nombre?',\n    ayuda:'Queremos que tu experiencia sea cercana desde el primer momento.',\n    placeholder:'Ana Rivera', autocomplete:'name', placa:'Nombre' },\n\n  { id:'email', tipo:'email', campo:'email',\n    kicker:'Contacto', titulo:'\u00bfA qu\u00e9 correo te enviamos la informaci\u00f3n de tu tour?',\n    ayuda:'Recibir\u00e1s la confirmaci\u00f3n y todos los detalles para tu visita.',\n    placeholder:'ana@correo.com', autocomplete:'email', placa:'Correo' },\n\n  { id:'telefono', tipo:'tel', campo:'phone',\n    kicker:'Contacto', titulo:'\u00bfCu\u00e1l es tu n\u00famero de WhatsApp?',\n    ayuda:'Para recordarte de tu visita y resolver cualquier duda.',\n    placeholder:'55 1234 5678', autocomplete:'tel', placa:'WhatsApp' },\n\n  { id:'edificio', tipo:'opciones', campo:'edificio', buscarPor:['edificio','building'], columnas:1,\n    kicker:'Comunidad', titulo:'\u00bfQu\u00e9 edificio te interesa?',\n    ayuda:'Elige la comunidad que hace mejor match contigo en las mejores zonas de la CDMX.',\n    placa:'Edificio',\n    opciones:[\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-ines',    valor:'In\u00e9s',     etiqueta:'In\u00e9s \u00b7 Polanco'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-josefa',  valor:'Josefa',   etiqueta:'Josefa \u00b7 Reforma'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-magda',   valor:'Magda',    etiqueta:'Magda \u00b7 Roma'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-amalia',  valor:'Amalia',   etiqueta:'Amalia \u00b7 N\u00e1poles'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-joaquina?uuid=b126542a-da68-4812-965f-fbc9d41d345c', valor:'Joaquina', etiqueta:'Joaquina \u00b7 Del Valle'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-matilde', valor:'Matilde',  etiqueta:'Matilde \u00b7 Ju\u00e1rez'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-leona',   valor:'Leona',    etiqueta:'Leona \u00b7 Condesa'},\n      {meet:'https:\/\/meetings.hubspot.com\/urbanista\/tour-natalia', valor:'Natalia',  etiqueta:'Natalia \u00b7 Doctores'},\n      {valor:'Enriqueta', etiqueta:'Aurora \u00b7 Sta Mar\u00eda la Ribera', nota:'Pr\u00f3ximamente'}\n    ] },\n\n  { id:'tipo', tipo:'opciones', campo:'tipo_de_depa', buscarPor:['tipo','depa','recamara','bedroom'], columnas:2,\n    kicker:'Tu espacio', titulo:'\u00bfQu\u00e9 tipo de depa est\u00e1s buscando?',\n    ayuda:'Todos vienen listos para mudarte, con cocina equipada y acabados de dise\u00f1o.',\n    placa:'Tipo de depa',\n    \/* Notas gen\u00e9ricas: solo se usan si el edificio no tiene precios (ej. Aurora).\n       Con edificio elegido, la nota se reemplaza por el precio \"desde\" de PRECIOS. *\/\n    opciones:[\n      {valor:'Studio',      etiqueta:'Studio',      nota:'Para uno'},\n      {valor:'1 Rec\u00e1mara',  etiqueta:'1 rec\u00e1mara',  nota:'El m\u00e1s pedido'},\n      {valor:'2 Rec\u00e1maras', etiqueta:'2 rec\u00e1maras', nota:'Pareja o roomie'}\n    ] },\n\n  { id:'mudanza', tipo:'opciones', campo:'fecha_estimada_de_mudanza', buscarPor:['mudanza','mudarte','move','estimada'], columnas:1,\n    kicker:'Tiempos', titulo:'\u00bfCu\u00e1ndo quieres mudarte?',\n    ayuda:'As\u00ed revisamos qu\u00e9 est\u00e1 disponible justo en tus fechas.',\n    placa:'Mudanza',\n    opciones:[\n      {valor:'3 a 15 d\u00edas',    etiqueta:'3 a 15 d\u00edas',    nota:'Ya casi me mudo'},\n      {valor:'15 a 30 d\u00edas',   etiqueta:'15 a 30 d\u00edas',   nota:'Ya tengo fecha'},\n      {valor:'M\u00e1s de 30 d\u00edas', etiqueta:'M\u00e1s de 30 d\u00edas', nota:'Voy planeando'}\n    ] }\n];\n\nconst FOTOS = [\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/12\/657770b4-3bee-43fb-afcc-f7cdfaa052ff.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-terraza.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-gimnasio.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/cocina-magda.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-cine-en-casa.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-grill.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/0eba9048-ff87-49cb-95ac-11aea3489f75.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/futbolito-magda.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-hero.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/1-recamara-en-renta.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2025\/10\/magda-2-recamaras-renta.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2026\/04\/5990ff2c-2df5-48cd-bb6c-618e49d79832.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2024\/08\/Mirador-monumento-revolucion.jpg',\n  'https:\/\/urbanista.mx\/wp-content\/uploads\/2024\/08\/1-6.jpg'\n];\n\nconst $  = (s,c=document)=>c.querySelector(s);\nconst $$ = (s,c=document)=>[...c.querySelectorAll(s)];\n\n\/* ---------- Diagn\u00f3stico en pantalla ---------- *\/\nconst DEBUG = CONFIG.depurar && (new URLSearchParams(location.search).has('debug') || location.protocol === 'file:');\nfunction diag(texto, clase){\n  console[clase === 'bad' ? 'error' : clase === 'warn' ? 'warn' : 'log']('[Urbanista]', texto);\n  if(!DEBUG) return;\n  const panel = document.getElementById('diag');\n  if(!panel) return;\n  panel.classList.add('is-on');\n  const p = document.createElement('p');\n  if(clase) p.className = clase;\n  p.textContent = texto;\n  document.getElementById('diagBody').appendChild(p);\n}\nconst log = (...a)=> diag(a.map(x => typeof x === 'string' ? x : JSON.stringify(x)).join(' '));\n\nif(location.protocol === 'file:'){\n  diag('Nota: est\u00e1s en file:\/\/ (doble clic). Suele funcionar, pero el hubspotutk no se guarda y pierdes la atribuci\u00f3n. Para probar de verdad, s\u00edrvelo por http.', 'warn');\n}\n\n\/* ---------- Marquee (desktop) + Hero m\u00f3vil ---------- *\/\n(function(){\n  const mitad = Math.ceil(FOTOS.length\/2);\n  [['reelA',FOTOS.slice(0,mitad)],['reelB',FOTOS.slice(mitad)]].forEach(([id,lista])=>{\n    const col=$('#'+id); if(!col) return;\n    [...lista,...lista].forEach(src=>{const i=new Image();i.src=src;i.loading='lazy';i.alt='';col.appendChild(i);});\n  });\n  \/* Hero m\u00f3vil: crossfade con las mismas fotos *\/\n  const hero=$('#heroSlides');\n  if(hero){\n    FOTOS.forEach((src,i)=>{\n      const im=new Image(); im.src=src; im.alt=''; im.decoding='async';\n      im.loading = i===0 ? 'eager' : 'lazy';\n      if(i===0) im.classList.add('is-on');\n      hero.appendChild(im);\n    });\n    if(FOTOS.length>1 && !matchMedia('(prefers-reduced-motion: reduce)').matches){\n      let h=0;\n      setInterval(()=>{\n        const imgs=$$('img',hero); if(!imgs.length) return;\n        imgs[h].classList.remove('is-on');\n        h=(h+1)%imgs.length;\n        imgs[h].classList.add('is-on');\n      },4500);\n    }\n  }\n})();\n\n\/* ---------- Estado ---------- *\/\nconst activas = PREGUNTAS.filter(p => !(p.id === 'edificio' && CONFIG.edificioFijo));\nconst respuestas = {}, visibles = {};\nif(CONFIG.edificioFijo){ respuestas.edificio = CONFIG.edificioFijo; visibles.edificio = CONFIG.edificioFijo; }\nconst TOTAL = activas.length;\nlet indice = 0;\n\n\/* ---------- Render ---------- *\/\nconst optHTML = (o,n)=>`\n      <button class=\"opt\" type=\"button\" data-valor=\"${o.valor}\" data-etiqueta=\"${o.etiqueta}\" ${o.deshabilitada?'disabled':''}>\n        <span class=\"opt-key\">${n+1}<\/span>\n        <span class=\"opt-main\"><span class=\"opt-label\">${o.etiqueta}<\/span>${o.nota?`<span class=\"opt-note\">${o.nota}<\/span>`:''}<\/span>\n      <\/button>`;\n\nconst cont = $('#slides');\nactivas.forEach((p,i)=>{\n  const s = document.createElement('section');\n  s.className = 'slide'; s.dataset.idx = i;\n  let cuerpo = '';\n\n  if(p.tipo === 'opciones'){\n    const cols = p.columnas === 2 ? ' cols-2' : '';\n    cuerpo = `<div class=\"options${cols}\" data-id=\"${p.id}\">` + p.opciones.map(optHTML).join('') + `<\/div>`;\n\n  }else if(p.tipo === 'confirmacion'){\n    cuerpo = `<div class=\"options\" data-id=\"${p.id}\" data-confirm=\"1\">\n      <button class=\"opt\" type=\"button\" data-valor=\"Si\" data-etiqueta=\"Confirmado\">\n        <span class=\"opt-key\">\u2713<\/span>\n        <span class=\"opt-main\"><span class=\"opt-label\">${p.etiqueta}<\/span><span class=\"opt-note\">${p.nota||''}<\/span><\/span>\n      <\/button><\/div>`;\n\n  }else if(p.tipo === 'tel'){\n    cuerpo = `\n      <div class=\"campo\" data-id=\"${p.id}\">\n        <div class=\"tel-row\">\n          <select id=\"lada\" aria-label=\"C\u00f3digo de pa\u00eds\">${LADAS.map(([v,t])=>`<option value=\"${v}\"${v===CONFIG.ladaDefault?' selected':''}>${t}<\/option>`).join('')}<\/select>\n          <input id=\"in-${p.id}\" type=\"tel\" inputmode=\"tel\" autocomplete=\"tel-national\" placeholder=\"${p.placeholder||''}\">\n        <\/div>\n        <span class=\"err\"><\/span>\n      <\/div>\n      <button class=\"cta\" type=\"button\" data-next>Continuar<\/button>\n      <span class=\"hint\">O presiona <kbd>Enter<\/kbd><\/span>`;\n\n  }else{\n    const tipo = p.tipo === 'email' ? 'email' : 'text';\n    cuerpo = `\n      <div class=\"campo\" data-id=\"${p.id}\">\n        <input id=\"in-${p.id}\" type=\"${tipo}\" inputmode=\"${p.tipo==='email'?'email':'text'}\" autocomplete=\"${p.autocomplete||'on'}\" placeholder=\"${p.placeholder||''}\">\n        <span class=\"err\"><\/span>\n      <\/div>\n      <button class=\"cta\" type=\"button\" data-next>Continuar<\/button>\n      <span class=\"hint\">O presiona <kbd>Enter<\/kbd><\/span>`;\n  }\n\n  s.innerHTML = `\n    <p class=\"u-eyebrow kicker\">${p.kicker||''}<\/p>\n    <h2 class=\"u-display q-title\">${p.titulo}<\/h2>\n    ${p.ayuda?`<p class=\"q-help\">${p.ayuda}<\/p>`:''}\n    ${cuerpo}`;\n  cont.appendChild(s);\n});\n\n\/* Placa *\/\n(function(){\n  const body = $('#placaBody');\n  activas.filter(p=>p.tipo!=='confirmacion').forEach(p=>{\n    const row = document.createElement('div');\n    row.className = 'placa-row';\n    row.innerHTML = `<dt>${p.placa||p.titulo}<\/dt><dd data-placa=\"${p.id}\">\u2014<\/dd>`;\n    body.appendChild(row);\n  });\n  $('#placaCount').textContent = `0 \/ ${$$('#placaBody dd').length}`;\n})();\nfunction contarPlaca(){\n  const total = $$('#placaBody dd').length;\n  $('#placaCount').textContent = `${Math.min(Object.keys(visibles).filter(k=>k!=='humano').length, total)} \/ ${total}`;\n}\nfunction pintarPlaca(id){\n  const dd = $(`[data-placa=\"${id}\"]`); if(!dd) return;\n  dd.textContent = visibles[id] || '\u2014';\n  dd.classList.add('is-set','just-set');\n  setTimeout(()=>dd.classList.remove('just-set'),460);\n  contarPlaca();\n}\n\n\/* ---------- Navegaci\u00f3n ---------- *\/\nconst lista = () => [...$$('#slides .slide'), $('#slideCheck'), $('#slideDone')];\nfunction ir(i){\n  indice = i;\n  const todos = lista();\n  todos.forEach((s,n)=> s.classList.toggle('is-active', n === i));\n  $('#bar').style.width = Math.min((i\/TOTAL)*100, 100) + '%';\n  $('#count').textContent = i < TOTAL ? `Paso ${i+1} de ${TOTAL}` : (i === TOTAL ? 'Revisi\u00f3n' : '\u00a1Listo!');\n  $('#back').hidden = (i === 0 || i > TOTAL);\n  if(i === TOTAL){ pintarCheck(); if(CONFIG.modoEnvio === 'embed' && !pareceBot()) montarFormReal(); }\n  const activo = todos[i];\n  if(activo){\n    activo.scrollIntoView({block:'nearest', behavior:'smooth'});\n    const input = activo.querySelector('input');\n    if(input) setTimeout(()=>input.focus({preventScroll:true}), 340);\n  }\n}\n$('#back').addEventListener('click', ()=> ir(Math.max(0, indice-1)));\n\n\/* ---------- Validaci\u00f3n ---------- *\/\nfunction valida(p, valor){\n  if(p.tipo === 'email') return \/^[^@\\s]+@[^@\\s]+\\.[a-z]{2,}$\/i.test(valor) ? '' : 'Revisa tu correo, algo no cuadra.';\n  if(p.tipo === 'tel'){\n    const digitos = valor.replace(\/\\D\/g,'');\n    const lada = $('#lada').value;\n    if(lada === '+52') return digitos.length === 10 ? '' : 'En M\u00e9xico son 10 d\u00edgitos, sin el 1 ni el 044.';\n    return digitos.length >= 7 ? '' : 'Escribe tu n\u00famero completo, sin la lada del pa\u00eds.';\n  }\n  if(p.id === 'nombre') return valor.trim().split(\/\\s+\/).filter(Boolean).length >= 2 ? '' : 'Escribe tu nombre y al menos un apellido.';\n  return valor.trim() ? '' : 'Este dato es necesario para continuar.';\n}\n\nfunction guardarTexto(i){\n  const p = activas[i];\n  const campo = $(`.campo[data-id=\"${p.id}\"]`);\n  const input = $('input', campo);\n  const msg = valida(p, input.value);\n  if(msg){\n    campo.classList.add('has-error');\n    $('.err', campo).textContent = msg;\n    input.focus();\n    return false;\n  }\n  campo.classList.remove('has-error');\n  if(p.tipo === 'tel'){\n    const lada = $('#lada').value;\n    const num  = input.value.replace(\/\\D\/g,'');\n    respuestas[p.id] = `${lada}${num}`;\n    visibles[p.id]   = `${lada} ${num}`;\n  }else{\n    respuestas[p.id] = input.value.trim();\n    visibles[p.id]   = input.value.trim();\n  }\n  pintarPlaca(p.id);\n  return true;\n}\n\n$$('[data-next]').forEach(b=> b.addEventListener('click', ()=>{ if(guardarTexto(indice)) ir(indice+1); }));\n$$('.campo input').forEach(input=>{\n  input.addEventListener('input', ()=> input.closest('.campo').classList.remove('has-error'));\n  input.addEventListener('keydown', e=>{ if(e.key === 'Enter'){ e.preventDefault(); if(guardarTexto(indice)) ir(indice+1); } });\n});\nconst selLada = $('#lada');\nif(selLada) selLada.addEventListener('change', ()=> selLada.closest('.campo').classList.remove('has-error'));\n\n\/* ---------- Opciones (bind reutilizable) ---------- *\/\nfunction bindOpciones(group){\n  const id = group.dataset.id;\n  $$('.opt', group).forEach(btn=>{\n    if(btn.disabled) return;\n    btn.addEventListener('click', ()=>{\n      $$('.opt', group).forEach(b=>b.classList.remove('is-selected'));\n      btn.classList.add('is-selected');\n      respuestas[id] = btn.dataset.valor;\n      visibles[id]   = btn.dataset.etiqueta;\n      pintarPlaca(id);\n      if(id === 'edificio') pintarTipos(btn.dataset.valor);\n      setTimeout(()=> ir(indice+1), 280);\n    });\n  });\n}\n$$('.options').forEach(bindOpciones);\n\n\/* ---------- Tipos de depa din\u00e1micos seg\u00fan edificio ---------- *\/\nfunction pintarTipos(edificio){\n  const grupo = $('.options[data-id=\"tipo\"]');\n  const pTipo = activas.find(p=>p.id==='tipo');\n  if(!grupo || !pTipo) return;\n\n  const precios = PRECIOS[edificio];\n  let ops;\n  if(precios && Object.keys(precios).length){\n    ops = pTipo.opciones.map(o => precios[o.valor] != null\n      ? {...o, nota: precioTxt(precios[o.valor]), deshabilitada:false}\n      : {...o, nota: 'No disponible', deshabilitada:true});\n  }else{\n    ops = pTipo.opciones; \/* sin datos (Aurora): tipos gen\u00e9ricos sin precio *\/\n  }\n\n  grupo.innerHTML = ops.map(optHTML).join('');\n  diag(`Tipos para ${edificio}: ` + ops.map(o=>`${o.valor}${o.deshabilitada?' (bloqueado)':o.nota?` (${o.nota})`:''}`).join(' \u00b7 '));\n\n  \/* Si cambi\u00f3 de edificio y el tipo elegido ya no est\u00e1 disponible, se limpia *\/\n  const validos = ops.filter(o=>!o.deshabilitada).map(o=>o.valor);\n  if(respuestas.tipo && !validos.includes(respuestas.tipo)){\n    delete respuestas.tipo; delete visibles.tipo;\n    const dd = $('[data-placa=\"tipo\"]');\n    if(dd){ dd.textContent='\u2014'; dd.classList.remove('is-set'); }\n    contarPlaca();\n  }else if(respuestas.tipo){\n    const sel = $$('.opt', grupo).find(b=>b.dataset.valor===respuestas.tipo);\n    if(sel) sel.classList.add('is-selected');\n  }\n  bindOpciones(grupo);\n}\nif(CONFIG.edificioFijo) pintarTipos(CONFIG.edificioFijo);\n\ndocument.addEventListener('keydown', e=>{\n  if(indice >= TOTAL || !\/^[1-9]$\/.test(e.key)) return;\n  if(['INPUT','TEXTAREA','SELECT'].includes(document.activeElement.tagName)) return;\n  const opts = $$('.opt', lista()[indice]);\n  if(opts[+e.key-1] && !opts[+e.key-1].disabled) opts[+e.key-1].click();\n});\n\n\/* ---------- Revisi\u00f3n ---------- *\/\nfunction pintarCheck(){\n  $('#checkList').innerHTML = activas.map((p,i)=> p.tipo === 'confirmacion' ? '' : `\n    <div class=\"check-row\">\n      <span class=\"check-tick\" aria-hidden=\"true\"><svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"\/><\/svg><\/span>\n      <dl class=\"check-body\"><dt>${p.placa||p.titulo}<\/dt><dd>${visibles[p.id]||'\u2014'}<\/dd><\/dl>\n      <button class=\"check-edit\" type=\"button\" data-editar=\"${i}\">Cambiar<\/button>\n    <\/div>`).join('');\n  $$('[data-editar]').forEach(b=> b.addEventListener('click', ()=> ir(+b.dataset.editar)));\n}\n\n\/* ============================================================\n   HubSpot \u00b7 env\u00edo por Forms API v3\n   ============================================================ *\/\nconst utm  = k => new URLSearchParams(location.search).get(k) || '';\nconst hutk = () => (document.cookie.match(\/hubspotutk=([^;]+)\/)||[])[1] || '';\n\nfunction datosFinales(){\n  const partes = (respuestas.nombre||'').trim().split(\/\\s+\/);\n  const d = {\n    firstname : partes.shift() || '',\n    lastname  : partes.join(' '),\n    email     : respuestas.email || '',\n    phone     : respuestas.telefono || '',\n    ...CONFIG.camposFijos,\n    utm_source : utm('utm_source'), utm_medium : utm('utm_medium'),\n    utm_campaign : utm('utm_campaign'), utm_content : utm('utm_content'), utm_term : utm('utm_term')\n  };\n  PREGUNTAS.forEach(p=>{\n    if(['nombre','email','telefono','humano'].includes(p.id) || !p.campo) return;\n    if(respuestas[p.id]) d[p.campo] = respuestas[p.id];\n  });\n  Object.keys(d).forEach(k => { if(!d[k]) delete d[k]; });\n  return d;\n}\n\nconst ENDPOINT = `https:\/\/api.hsforms.com\/submissions\/v3\/integration\/submit\/${CONFIG.portalId}\/${CONFIG.formId}`;\n\nasync function postHubspot(datos, sinHutk){\n  const ctx = { pageUri: location.href, pageName: document.title };\n  const token = hutk();\n  if(token && !sinHutk) ctx.hutk = token;\n  const cuerpo = { fields: Object.entries(datos).map(([name,value])=>({name, value:String(value)})), context: ctx };\n  if(CONFIG.consentimiento){\n    cuerpo.legalConsentOptions = { consent:{ consentToProcess:true, text:'Acepto el aviso de privacidad de Urbanista.' } };\n  }\n  const res = await fetch(ENDPOINT, {\n    method:'POST', headers:{'Content-Type':'application\/json'}, body: JSON.stringify(cuerpo)\n  });\n  return { ok: res.ok, status: res.status, texto: await res.text() };\n}\n\nconst camposRechazados = texto =>\n  [...new Set([...texto.matchAll(\/fields\\.([A-Za-z0-9_.]+)\/g)].map(m => m[1]))];\n\nconst ABIERTO_EN = Date.now();\nfunction pareceBot(){\n  const trampa = $('#empresa_web');\n  if(trampa && trampa.value.trim()){ diag('Trampa de spam activada: campo oculto relleno.', 'warn'); return true; }\n  if(Date.now() - ABIERTO_EN < 4000){ diag('Trampa de spam activada: formulario enviado en menos de 4 s.', 'warn'); return true; }\n  return false;\n}\n\n\/* ============================================================\n   MODO EMBED \u00b7 monta el form real de HubSpot ya prellenado.\n   ============================================================ *\/\nlet hsForm = null, formListo = false, enviando = false;\nconst sinAcentos = t => (t||'').toString().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase();\n\nfunction setCampo(nombre, valor){\n  if(!hsForm || valor === undefined || valor === '') return false;\n  const nodos = $$(`[name=\"${nombre}\"]`, hsForm);\n  if(!nodos.length) return false;\n  const el = nodos[0];\n  if(el.type === 'hidden' && String(el.value).trim()){\n    diag(`\u00ab${nombre}\u00bb ya ven\u00eda con \u00ab${el.value}\u00bb desde el form. No se toca.`);\n    return true;\n  }\n  if(el.type === 'radio' || el.type === 'checkbox'){\n    const m = nodos.find(n=>n.value===valor) || nodos.find(n=>(n.closest('label')?.textContent||'').trim()===valor);\n    if(!m) return false;\n    m.checked = true; m.dispatchEvent(new Event('change',{bubbles:true}));\n    return true;\n  }\n  if(el.tagName === 'SELECT'){\n    const v = sinAcentos(valor).replace(\/[^a-z0-9]\/g,'');\n    const norm = t => sinAcentos(t).replace(\/[^a-z0-9]\/g,'');\n    const opt = [...el.options].find(o=>o.value===valor)\n             || [...el.options].find(o=>o.text.trim()===valor)\n             || [...el.options].find(o=>o.value && (norm(o.value)===v || norm(o.text)===v))\n             || [...el.options].find(o=>o.value && (norm(o.value).includes(v) || v.includes(norm(o.value))));\n    if(!opt || !opt.value){\n      diag(`\"${valor}\" no empata con ninguna opci\u00f3n de \u00ab${nombre}\u00bb. Opciones reales: ${[...el.options].map(o=>o.value).filter(Boolean).join(' | ')}`, 'warn');\n      return false;\n    }\n    el.value = opt.value;\n    el.classList.remove('is-placeholder','invalid','error');\n    el.closest('.hs-form-field')?.querySelector('.hs-error-msgs')?.remove();\n  }else{\n    el.value = valor;\n  }\n  el.dispatchEvent(new Event('input',{bubbles:true}));\n  el.dispatchEvent(new Event('change',{bubbles:true}));\n  el.dispatchEvent(new Event('blur',{bubbles:true}));\n  return true;\n}\n\nfunction setCampoPorPista(palabras, valor){\n  if(!hsForm) return false;\n  for(const f of $$('.hs-form-field', hsForm)){\n    const el = f.querySelector('select,input:not([type=hidden]),textarea');\n    if(!el || !el.name) continue;\n    const pistas = sinAcentos([\n      f.className, el.name, el.getAttribute('placeholder') || '',\n      f.querySelector(':scope > label')?.textContent || '',\n      el.tagName === 'SELECT' ? ([...el.options].find(op=>!op.value)?.text || '') : ''\n    ].join(' '));\n    if(!palabras.some(w => pistas.includes(sinAcentos(w)))) continue;\n    if(setCampo(el.name, valor)) return el.name;\n  }\n  return false;\n}\n\nfunction rellenarForm(){\n  if(!hsForm) return {llenados:[], faltantes:[]};\n  const datos = datosFinales();\n  const llenados = [], faltantes = [];\n  Object.entries(datos).forEach(([k,v]) => (setCampo(k,v) ? llenados : faltantes).push(k));\n  PREGUNTAS.forEach(pr=>{\n    if(!pr.buscarPor || !respuestas[pr.id] || llenados.includes(pr.campo)) return;\n    const real = setCampoPorPista(pr.buscarPor, respuestas[pr.id]);\n    if(real){\n      llenados.push(real);\n      const i = faltantes.indexOf(pr.campo); if(i>=0) faltantes.splice(i,1);\n      diag(`\u00ab${pr.placa}\u00bb se coloc\u00f3 en el campo \u00ab${real}\u00bb. Para que sea directo, pon campo:'${real}' en PREGUNTAS.`, 'good');\n    }\n  });\n  const telVis = hsForm.querySelector('.hs-fieldtype-intl-phone input[type=tel]');\n  if(telVis && respuestas.telefono){\n    telVis.value = respuestas.telefono;\n    telVis.dispatchEvent(new Event('input',{bubbles:true}));\n    telVis.dispatchEvent(new Event('change',{bubbles:true}));\n  }\n  return {llenados, faltantes};\n}\n\nfunction pendientes(){\n  return $$('.hs-form-field', hsForm).filter(f=>{\n    if(f.querySelector('.hs-recaptcha, .grecaptcha-badge')) return false;\n    const el = f.querySelector('select,input:not([type=hidden]),textarea');\n    if(!el || !el.name) return false;\n    const obligatorio = el.required || el.getAttribute('required') !== null;\n    return obligatorio && !String(el.value).trim();\n  });\n}\n\nfunction montarFormReal(){\n  if(hsForm || formListo) return;\n  formListo = true;\n  const sc = document.createElement('script');\n  sc.src = 'https:\/\/js.hsforms.net\/forms\/embed\/v2.js';\n  sc.charset = 'utf-8';\n  sc.onerror = () => diag('No carg\u00f3 el motor de formularios de HubSpot.', 'bad');\n  sc.onload = () => window.hbspt.forms.create({\n    portalId: CONFIG.portalId, formId: CONFIG.formId, region: CONFIG.region,\n    target: '#hsFrame', css: '',\n    onFormReady: function($f){\n      hsForm = ($f && $f.length) ? $f[0] : document.querySelector('#hsFrame form');\n      if(!hsForm){ diag('No encontr\u00e9 el <form> de HubSpot.', 'bad'); return; }\n      diag('Form de HubSpot listo (invisible). Campos: ' +\n        $$('[name]', hsForm).map(n=>n.name).filter((v,i,a)=>v && a.indexOf(v)===i).join(', '));\n      const {llenados, faltantes} = rellenarForm();\n      diag('Prellenados: ' + (llenados.join(', ') || 'ninguno'), llenados.length ? 'good' : 'warn');\n      if(faltantes.length) diag('Sin colocar: ' + faltantes.join(', '), 'warn');\n    },\n    onFormSubmitted: function(){ exito('form de HubSpot'); }\n  });\n  document.body.appendChild(sc);\n}\n\nfunction revelarForm(motivo){\n  $('#hsFrame').classList.add('visible');\n  $('#notaEmbed').hidden = false;\n  $('#notaEmbed').textContent = motivo;\n  $('#enviar').hidden = true;\n  diag('Se revel\u00f3 el form: ' + motivo, 'warn');\n}\n\nwindow.addEventListener('message', e => {\n  if(!e.data || e.data.type !== 'hsFormCallback') return;\n  if(e.data.eventName === 'onFormSubmitted') exito('form de HubSpot');\n});\n\n\/* ---------- Env\u00edo ---------- *\/\n$('#enviar').addEventListener('click', async ()=>{\n  const btn = $('#enviar'), aviso = $('#aviso');\n  aviso.classList.remove('is-on');\n  if(enviando) return;\n\n  if(pareceBot()){ return exito('descartado'); }\n\n  if(CONFIG.modoEnvio !== 'embed'){\n    btn.disabled = true; btn.textContent = 'Apartando tu visita\u2026';\n    const datos = datosFinales();\n    diag('Datos a enviar: ' + JSON.stringify(datos, null, 1));\n    return enviar(datos, btn, aviso);\n  }\n\n  if(!hsForm){\n    aviso.innerHTML = 'Estamos preparando tu solicitud, dale otra vez en un segundo.';\n    aviso.classList.add('is-on');\n    montarFormReal();\n    return;\n  }\n\n  enviando = true;\n  btn.disabled = true; btn.textContent = 'Apartando tu visita\u2026';\n\n  rellenarForm();\n  const faltan = pendientes();\n  if(faltan.length){\n    enviando = false; btn.disabled = false; btn.textContent = 'Confirmar y agendar mi visita';\n    return revelarForm('Falta un dato para completar tu solicitud. Compl\u00e9talo aqu\u00ed abajo y confirma.');\n  }\n\n  const submit = hsForm.querySelector('input[type=submit],button[type=submit]');\n  if(!submit){\n    enviando = false;\n    return revelarForm('Completa tu solicitud aqu\u00ed abajo.');\n  }\n\n  diag('Disparando el env\u00edo de HubSpot (el reCAPTCHA invisible corre solo)\u2026');\n  submit.click();\n\n  setTimeout(()=>{\n    if($('#slideDone').classList.contains('is-active')) return;\n    enviando = false; btn.disabled = false; btn.textContent = 'Confirmar y agendar mi visita';\n    const errs = $$('.hs-error-msg, .hs-error-msgs li', hsForm).map(e=>e.textContent.trim()).filter(Boolean);\n    diag('No se confirm\u00f3 el env\u00edo. Errores: ' + (errs.join(' \u00b7 ') || '(ninguno visible)'), 'warn');\n    revelarForm('Necesitamos confirmar un par de datos. Rev\u00edsalos aqu\u00ed abajo y env\u00eda.');\n  }, 8000);\n});\n\nasync function enviar(datos, btn, aviso, intento = 1, sinHutk = false){\n  let r;\n  try{\n    r = await postHubspot(datos, sinHutk);\n  }catch(err){\n    diag('Error de red al llamar a HubSpot: ' + err +\n         (location.protocol === 'file:' ? ' \u2014 es el bloqueo CORS de file:\/\/' : ''), 'bad');\n    return fallar(btn, aviso);\n  }\n\n  if(r.ok){ diag('\u2713 Lead registrado en HubSpot.', 'good'); return exito('api v3'); }\n\n  diag(`HubSpot rechaz\u00f3 el env\u00edo (HTTP ${r.status}): ${r.texto}`, 'bad');\n\n  if(\/RECAPTCHA|Captcha\/i.test(r.texto)){\n    diag('CAUSA: el form tiene el CAPTCHA activado. Ap\u00e1galo en HubSpot (editor del form \u2192 Opciones \u2192 protecci\u00f3n antispam) o usa un form aparte sin captcha para esta landing. Ning\u00fan reintento va a funcionar.', 'bad');\n    if(CONFIG.webhookRespaldo) return porWebhook(datos, btn, aviso);\n    return fallar(btn, aviso);\n  }\n\n  if(\/hutk\/i.test(r.texto) && !sinHutk && intento < 6){\n    diag('Reintentando sin hutk\u2026', 'warn');\n    return enviar(datos, btn, aviso, intento+1, true);\n  }\n  const invalidos = camposRechazados(r.texto);\n  const limpios = {...datos};\n  invalidos.forEach(k => delete limpios[k]);\n  if(invalidos.length && Object.keys(limpios).length && intento < 6){\n    diag('Estos campos no existen en el form y se quitan: ' + invalidos.join(', '), 'warn');\n    return enviar(limpios, btn, aviso, intento+1, sinHutk);\n  }\n  if(intento < 7){\n    const minimo = {};\n    ['firstname','lastname','email','phone'].forEach(k => { if(datos[k]) minimo[k] = datos[k]; });\n    if(Object.keys(minimo).length && Object.keys(minimo).length < Object.keys(datos).length){\n      diag('Reintentando solo con nombre, correo y tel\u00e9fono\u2026', 'warn');\n      return enviar(minimo, btn, aviso, 7, sinHutk);\n    }\n  }\n  fallar(btn, aviso);\n}\n\nasync function porWebhook(datos, btn, aviso){\n  diag('Mandando el lead al webhook de respaldo\u2026', 'warn');\n  try{\n    const res = await fetch(CONFIG.webhookRespaldo, {\n      method:'POST', headers:{'Content-Type':'application\/json'},\n      body: JSON.stringify({ ...datos, hutk: hutk(), pageUri: location.href })\n    });\n    if(!res.ok) throw new Error('HTTP ' + res.status);\n    diag('\u2713 Lead entregado por webhook.', 'good');\n    return exito('webhook');\n  }catch(err){\n    diag('El webhook de respaldo tambi\u00e9n fall\u00f3: ' + err, 'bad');\n    return fallar(btn, aviso);\n  }\n}\n\nfunction fallar(btn, aviso){\n  btn.disabled = false; btn.textContent = 'Confirmar y agendar mi visita';\n  aviso.innerHTML = `No pudimos enviar tu solicitud. Int\u00e9ntalo de nuevo o <a href=\"https:\/\/wa.me\/${CONFIG.whatsapp}\" target=\"_blank\" rel=\"noopener\">escr\u00edbenos por WhatsApp<\/a>.`;\n  aviso.classList.add('is-on');\n}\n\nfunction exito(via){\n  if($('#slideDone').classList.contains('is-active')) return;\n  diag('Lead registrado v\u00eda ' + via + '.', 'good');\n  if(window.dataLayer) window.dataLayer.push({event:'tour_agendado', edificio: respuestas.edificio||''});\n  if(CONFIG.thankYouUrl){ location.href = CONFIG.thankYouUrl; return; }\n  const nombre = (respuestas.nombre||'').split(' ')[0];\n  if(nombre) $('#doneTitle').textContent = `Listo ${nombre}, tu visita est\u00e1 apartada`;\n  const opcEdif = (PREGUNTAS.find(p=>p.id==='edificio')?.opciones || []).find(o=>o.valor === respuestas.edificio);\n\n  if(opcEdif && opcEdif.meet){\n    const corto = opcEdif.etiqueta.split(' \u00b7 ')[0];\n    if(nombre) $('#doneTitle').textContent = `Ya casi ${nombre}, elige tu horario`;\n    $('#doneTexto').textContent = `Selecciona el d\u00eda y la hora que mejor te acomode para conocer ${corto}. Tus datos ya van cargados.`;\n\n    let url;\n    try{\n      url = new URL(opcEdif.meet);\n      url.searchParams.set('embed','true');\n      const partes = (respuestas.nombre||'').trim().split(\/\\s+\/);\n      if(partes[0]) url.searchParams.set('firstname', partes.shift());\n      if(partes.length) url.searchParams.set('lastname', partes.join(' '));\n      if(respuestas.email) url.searchParams.set('email', respuestas.email);\n      if(respuestas.telefono) url.searchParams.set('phone', respuestas.telefono);\n      url = url.toString();\n    }catch(e){\n      url = opcEdif.meet + (opcEdif.meet.includes('?') ? '&' : '?') + 'embed=true';\n    }\n\n    const wrap = $('#meetWrap');\n    wrap.classList.add('is-on');\n    wrap.innerHTML = '<p class=\"meet-cargando\">Cargando los horarios disponibles\u2026<\/p>';\n\n    const caja = document.createElement('div');\n    caja.className = 'meetings-iframe-container';\n    caja.setAttribute('data-src', url);\n    wrap.appendChild(caja);\n\n    const sc = document.createElement('script');\n    sc.type = 'text\/javascript';\n    sc.src = 'https:\/\/static.hsappstatic.net\/MeetingsEmbed\/ex\/MeetingsEmbedCode.js';\n    sc.onerror = () => { wrap.querySelector('.meet-cargando').textContent = 'No pudimos cargar el calendario.'; };\n    document.body.appendChild(sc);\n\n    const vigilante = new MutationObserver(()=>{\n      if(caja.querySelector('iframe')){\n        wrap.querySelector('.meet-cargando')?.remove();\n        vigilante.disconnect();\n      }\n    });\n    vigilante.observe(caja, {childList:true, subtree:true});\n    setTimeout(()=>{\n      if(!caja.querySelector('iframe')){\n        wrap.querySelector('.meet-cargando')?.remove();\n        diag('El calendario no mont\u00f3 el iframe. Queda el enlace alterno.', 'warn');\n      }\n      vigilante.disconnect();\n    }, 6000);\n\n    $('#meetLink').href = url.replace('embed=true','');\n    $('#meetAlterno').hidden = false;\n    $('.stage-inner').style.maxWidth = '860px';\n    diag('Calendario incrustado: ' + url);\n\n  }else if(respuestas.edificio === 'Enriqueta'){\n    $('#doneTexto').textContent = 'Aurora abre pronto. Te avisamos en cuanto haya fecha para visitarla.';\n  }\n\n  ir(TOTAL+1);\n  $('#bar').style.width = '100%';\n}\n\nasync function probarCampos(){\n  const prueba = {\n    firstname:'Prueba', lastname:'Campos', email:'esto-no-es-un-correo', phone:'+525500000000',\n    ...CONFIG.camposFijos\n  };\n  PREGUNTAS.forEach(p=>{\n    if(['nombre','email','telefono','humano'].includes(p.id) || !p.campo) return;\n    prueba[p.campo] = (p.opciones && p.opciones[0]) ? p.opciones[0].valor : 'prueba';\n  });\n  diag('Probando estos campos: ' + Object.keys(prueba).join(', '));\n  try{\n    const r = await postHubspot(prueba, true);\n    const malos = camposRechazados(r.texto);\n    const buenos = Object.keys(prueba).filter(k => !malos.includes(k));\n    diag('\u2713 S\u00cd existen en el form: ' + (buenos.join(', ') || '(ninguno)'), 'good');\n    diag(malos.length ? '\u2717 NO existen (hay que agregarlos como campos ocultos): ' + malos.join(', ')\n                      : '\u2717 NO existen: ninguno. Todo empata.', malos.length ? 'warn' : 'good');\n    diag('Respuesta completa: ' + r.texto);\n  }catch(err){\n    diag('No se pudo probar: ' + err, 'bad');\n  }\n}\nwindow.probarCampos = probarCampos;\n\nir(0);\n<\/script>\n<\/body>\n<\/html>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Agenda tu visita.<br \/>\nCinco datos y te apartamos el departamento que s\u00ed te toca. Toma menos de un minuto.<\/p>","protected":false},"author":3,"featured_media":21955,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-25399","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/pages\/25399","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/comments?post=25399"}],"version-history":[{"count":52,"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/pages\/25399\/revisions"}],"predecessor-version":[{"id":25551,"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/pages\/25399\/revisions\/25551"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/media\/21955"}],"wp:attachment":[{"href":"https:\/\/urbanista.mx\/en\/wp-json\/wp\/v2\/media?parent=25399"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}