+Math.round(Number(n)||0).toLocaleString('es-MX');return withMXN?val+' MXN':val}\nfunction formatCurrencyInput(el){const n=parseCurrency(el.value);el.value=n?money(n):''}\nfunction addDays(v,days){if(!v)return '';const d=new Date(v+'T12:00:00');d.setDate(d.getDate()+days);return d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate())}\nfunction endDate(){const start=$('fechaInstalacion').value,dur=Number($('duracionProyecto').value)||0;return(start\u0026amp;\u0026amp;dur)?addDays(start,dur-1):''}\nfunction durationLabel(){const n=Number($('duracionProyecto').value)||0;return n?(n+' '+(n===1?'d\u00eda':'d\u00edas')):'\u2014'}\nfunction modalityLabel(){return $('modalidadPago').value==='unico'?'Pago \u00fanico':$('modalidadPago').value==='plan'?'Plan de pagos':'\u2014'}\nfunction frequencyLabel(){const v=$('frecuenciaPagos').value;return v==='semanal'?'Semanal':v==='quincenal'?'Quincenal':v==='manual'?'Manual':'\u2014'}\nfunction selectedOrDash(id){return $(id).value||'\u2014'}\n\nfunction fillQty(id,label){\n const s=$(id);s.innerHTML='\u0026lt;option value=\"0\"\u0026gt;'+label+'\u0026lt;\/option\u0026gt;';\n for(let i=1;i\u0026lt;=15;i++)s.innerHTML+='\u0026lt;option value=\"'+i+'\"\u0026gt;'+i+'\u0026lt;\/option\u0026gt;';\n}\n\nfunction syncStructuralFields(){\n const vig=Number($('viguetasCantidad').value)||0;\n $('viguetasMedida').disabled=vig===0;\n if(vig===0)$('viguetasMedida').value='';\n\n const rip=Number($('ripasCantidad').value)||0;\n $('ripasMedida').disabled=rip===0;\n if(rip===0)$('ripasMedida').value='';\n\n const col=Number($('columnas').value)||0;\n $('medidaColumnas').disabled=col===0;\n if(col===0)$('medidaColumnas').value='';\n}\n\nfunction syncPaymentMode(){\n const mode=$('modalidadPago').value;\n const modeChanged=mode!==lastPaymentMode;\n\n $('paymentConfig').classList.toggle('hidden',!mode);\n $('singleOptions').classList.toggle('hidden',mode!=='unico');\n $('singlePayHelper').classList.toggle('hidden',mode!=='unico');\n $('planOptions').classList.toggle('hidden',mode!=='plan');\n $('planPayHelper').classList.toggle('hidden',mode!=='plan');\n\n if(modeChanged){\n if(mode==='plan'){\n $('numeroPagos').value='';\n $('frecuenciaPagos').value='';\n $('anticipo').value='';\n $('fechaAnticipoPlan').value=$('fechaAnticipo').value||todayISO();\n planAdvanceEdited=false;\n manualDates={};\n }else if(mode==='unico'){\n $('numeroPagos').value='';\n $('frecuenciaPagos').value='';\n $('anticipo').value='';\n planAdvanceEdited=false;\n manualDates={};\n }else{\n $('numeroPagos').value='';\n $('frecuenciaPagos').value='';\n $('anticipo').value='';\n planAdvanceEdited=false;\n manualDates={};\n }\n lastPaymentMode=mode;\n }\n\n const count=Number($('numeroPagos').value)||0;\n const freq=$('frecuenciaPagos').value;\n\n $('planFrequencyStep').classList.toggle('hidden',mode!=='plan'||count\u0026lt;2);\n $('planAdvanceStep').classList.toggle('hidden',mode!=='plan'||count\u0026lt;2||!freq);\n\n if(mode!=='unico')$('anticipoAutoTexto').textContent='$0';\n\n if(mode==='plan'\u0026amp;\u0026amp;count\u0026gt;=2){\n const total=parseCurrency($('precioFinal').value);\n if(total\u0026amp;\u0026amp;!planAdvanceEdited){\n const suggested=Math.floor(total\/count);\n $('anticipo').value=money(suggested);\n }\n }\n}\n\nfunction getNextFolio(){\n const y=new Date().getFullYear(),key='fichaFolio_'+y;\n const next=Number(localStorage.getItem(key)||0)+1;\n return 'PROY-'+y+'-'+String(next).padStart(3,'0');\n}\nfunction commitFolio(f){\n const m=f.match(\/^PROY-(\\d{4})-(\\d+)$\/);if(!m)return;\n const key='fichaFolio_'+m[1],n=Number(m[2]),cur=Number(localStorage.getItem(key)||0);\n if(n\u0026gt;cur)localStorage.setItem(key,String(n));\n}\n\nfunction buildPayments(){\n const total=parseCurrency($('precioFinal').value);\n const mode=$('modalidadPago').value;\n if(!total||!mode)return [];\n\n const start=mode==='plan'?$('fechaAnticipoPlan').value:$('fechaAnticipo').value;\n\n if(mode==='unico'){\n const advance=Math.round(total*0.35);\n const finalAmount=total-advance;\n $('anticipoAutoTexto').textContent=money(advance);\n return [\n {label:'Anticipo 35%',amount:advance,date:start,index:0},\n {label:'Liquidaci\u00f3n final',amount:finalAmount,date:endDate(),index:1}\n ];\n }\n\n const count=Number($('numeroPagos').value)||0;\n const freq=$('frecuenciaPagos').value;\n if(count\u0026lt;2||!freq)return [];\n\n const advance=Math.min(total,parseCurrency($('anticipo').value));\n const rows=[{label:'Anticipo',amount:advance,date:start,index:0}];\n const remaining=Math.max(0,total-advance),other=count-1,base=other?Math.floor(remaining\/other):0;\n let used=0;\n\n for(let i=1;i\u0026lt;count;i++){\n const last=i===count-1;\n const amount=last?remaining-used:base;used+=amount;\n let date='';\n if(freq==='semanal')date=addDays(start,7*i);\n else if(freq==='quincenal')date=addDays(start,14*i);\n else date=manualDates[i]||'';\n rows.push({label:last?'Pago final':'Pago '+(i+1),amount,date,index:i});\n }\n return rows;\n}\n\nfunction qtyText(idCount,idMeasure,zero){\n const n=Number($(idCount).value)||0;\n if(!n)return zero;\n return n+' \u00b7 '+($(idMeasure).value||'medida pendiente');\n}\n\nfunction renderPayments(){\n const mode=$('modalidadPago').value;\n const rows=buildPayments();\n const list=$('paymentList');\n\n if(!mode){\n list.innerHTML='';\n $('paymentStatus').textContent='Selecciona la modalidad de pago.';\n $('paymentNotice').style.display='none';\n return rows;\n }\n\n if(!rows.length){\n list.innerHTML='';\n $('paymentStatus').textContent=mode==='plan'?'Completa los datos del plan de pagos.':'Ingresa el precio final.';\n $('paymentNotice').style.display='none';\n return rows;\n }\n\n const freq=$('frecuenciaPagos').value;\n list.innerHTML=rows.map((r,i)=\u0026gt;{\n const date=(mode==='plan'\u0026amp;\u0026amp;freq==='manual'\u0026amp;\u0026amp;i\u0026gt;0)\n ? '\u0026lt;input type=\"date\" class=\"manual-date\" data-index=\"'+r.index+'\" value=\"'+(r.date||'')+'\"\u0026gt;'\n : '\u0026lt;div class=\"payvalue\"\u0026gt;'+fmtDate(r.date)+'\u0026lt;\/div\u0026gt;';\n return '\u0026lt;div class=\"payment-row\"\u0026gt;\u0026lt;div\u0026gt;\u0026lt;div class=\"paylabel\"\u0026gt;Pago\u0026lt;\/div\u0026gt;\u0026lt;div class=\"payvalue\"\u0026gt;'+r.label+'\u0026lt;\/div\u0026gt;\u0026lt;\/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;div class=\"paylabel\"\u0026gt;Monto\u0026lt;\/div\u0026gt;\u0026lt;div class=\"payvalue\"\u0026gt;'+money(r.amount)+'\u0026lt;\/div\u0026gt;\u0026lt;\/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;div class=\"paylabel\"\u0026gt;Fecha\u0026lt;\/div\u0026gt;'+date+'\u0026lt;\/div\u0026gt;\u0026lt;\/div\u0026gt;';\n }).join('');\n\n document.querySelectorAll('.manual-date').forEach(el=\u0026gt;el.addEventListener('input',e=\u0026gt;{\n manualDates[Number(e.target.dataset.index)]=e.target.value;\n update(false);\n }));\n\n const assigned=rows.reduce((sum,r)=\u0026gt;sum+r.amount,0);\n $('paymentStatus').textContent='Total programado: '+money(assigned);\n\n const notice=$('paymentNotice');\n let msg='';\n if(mode==='unico'\u0026amp;\u0026amp;!endDate())msg='Selecciona la fecha de inicio y la duraci\u00f3n estimada para calcular la fecha de liquidaci\u00f3n.';\n else if(mode==='plan'\u0026amp;\u0026amp;parseCurrency($('anticipo').value)\u0026gt;parseCurrency($('precioFinal').value))msg='El anticipo no puede ser mayor que el precio final.';\n else if(rows.some(r=\u0026gt;!r.date))msg='Hay pagos sin fecha.';\n notice.style.display=msg?'block':'none';\n notice.textContent=msg;\n return rows;\n}\n\nfunction update(render=true){\n syncStructuralFields();\n syncPaymentMode();\n\n const a=Number($('ancho').value)||0,l=Number($('largo').value)||0,area=a*l;\n const medidas=a\u0026amp;\u0026amp;l?a.toFixed(2)+' \u00d7 '+l.toFixed(2)+' m':'\u2014';\n const alturas=($('alturaFrontal').value||$('alturaPosterior').value)?(($('alturaFrontal').value||'\u2014')+' \/ '+($('alturaPosterior').value||'\u2014')+' m'):'\u2014';\n const columnas=Number($('columnas').value)?$('columnas').value+' \u00b7 '+($('medidaColumnas').value||'medida pendiente'):'Sin columnas';\n const viguetas=qtyText('viguetasCantidad','viguetasMedida','Sin viguetas');\n const ripas=qtyText('ripasCantidad','ripasMedida','Sin ripas');\n const fin=endDate();\n $('areaTexto').textContent=area.toFixed(2)+' m\u00b2';\n $('fechaFinTexto').textContent=fmtDate(fin);\n\n const rows=render?renderPayments():buildPayments();\n const mode=$('modalidadPago').value;\n const freqText=mode==='plan'\u0026amp;\u0026amp;$('frecuenciaPagos').value?'Frecuencia: '+frequencyLabel():'';\n\n const map={\n previewFolio:$('folio').value||'\u2014',previewFolioDetalle:$('folio').value||'\u2014',previewFechaVisita:fmtDate($('fechaVisita').value),\n previewNombre:$('nombre').value||'\u2014',previewTelefono:$('telefono').value||'\u2014',previewDireccion:$('direccion').value||'\u2014',\n previewMedidas:medidas,previewArea:area.toFixed(2)+' m\u00b2',previewTipo:selectedOrDash('tipoInstalacion'),previewAlturas:alturas,previewCaida:selectedOrDash('caida'),\n previewColumnas:columnas,previewViguetas:viguetas,previewRipas:ripas,previewCubierta:selectedOrDash('cubierta'),previewRevestimiento:selectedOrDash('revestimiento'),\n previewFechaInstalacion:fmtDate($('fechaInstalacion').value),previewDuracion:durationLabel(),previewFechaFin:fmtDate(fin),previewHora:$('horaInstalacion').value||'\u2014',\n previewModalidad:modalityLabel(),previewFrecuencia:freqText,previewPrecio:money(parseCurrency($('precioFinal').value),true),\n previewObservaciones:$('observaciones').value.trim()||'Sin observaciones.'\n };\n Object.entries(map).forEach(([k,v])=\u0026gt;$(k).textContent=v);\n\n $('previewPayments').innerHTML=rows.map(r=\u0026gt;'\u0026lt;div class=\"detail\"\u0026gt;\u0026lt;span\u0026gt;'+r.label+'\u0026lt;br\u0026gt;\u0026lt;small style=\"color:#777\"\u0026gt;'+fmtDate(r.date)+'\u0026lt;\/small\u0026gt;\u0026lt;\/span\u0026gt;\u0026lt;strong\u0026gt;'+money(r.amount)+'\u0026lt;\/strong\u0026gt;\u0026lt;\/div\u0026gt;').join('');\n\n const pdf={\n pdfFolio:$('folio').value||'\u2014',pdfFolioDetalle:$('folio').value||'\u2014',\n pdfNombre:$('nombre').value||'\u2014',pdfTelefono:$('telefono').value||'\u2014',pdfDireccion:$('direccion').value||'\u2014',\n pdfMedidas:medidas,pdfArea:area.toFixed(2)+' m\u00b2',pdfTipo:selectedOrDash('tipoInstalacion'),pdfAlturas:alturas,pdfCaida:selectedOrDash('caida'),\n pdfVigaPrincipal:selectedOrDash('vigaPrincipal'),pdfVigaSecundaria:selectedOrDash('vigaSecundaria'),pdfColumnas:columnas,pdfViguetas:viguetas,pdfRipas:ripas,\n pdfCubierta:selectedOrDash('cubierta'),pdfRevestimiento:selectedOrDash('revestimiento'),pdfFechaVisita:fmtDate($('fechaVisita').value),\n pdfFechaInstalacion:fmtDate($('fechaInstalacion').value),pdfDuracion:durationLabel(),pdfFechaFin:fmtDate(fin),pdfHora:$('horaInstalacion').value||'\u2014',\n pdfModalidad:modalityLabel(),pdfFrecuencia:freqText,pdfPrecio:money(parseCurrency($('precioFinal').value),true),pdfObservaciones:$('observaciones').value.trim()||'Sin observaciones.'\n };\n Object.entries(pdf).forEach(([k,v])=\u0026gt;$(k).textContent=v);\n $('pdfPayments').innerHTML=rows.map(r=\u0026gt;'\u0026lt;div class=\"pdf-pay\"\u0026gt;\u0026lt;div\u0026gt;'+r.label+'\u0026lt;\/div\u0026gt;\u0026lt;div\u0026gt;'+fmtDate(r.date)+'\u0026lt;\/div\u0026gt;\u0026lt;div style=\"text-align:right;font-weight:800\"\u0026gt;'+money(r.amount)+'\u0026lt;\/div\u0026gt;\u0026lt;\/div\u0026gt;').join('');\n}\n\nfunction collect(){\n const ids=['folio','fechaVisita','fechaInstalacion','duracionProyecto','horaInstalacion','nombre','telefono','direccion','ancho','largo','alturaFrontal','alturaPosterior','tipoInstalacion','columnas','caida','vigaPrincipal','vigaSecundaria','viguetasCantidad','viguetasMedida','ripasCantidad','ripasMedida','medidaColumnas','cubierta','revestimiento','precioFinal','modalidadPago','anticipo','numeroPagos','fechaAnticipo','fechaAnticipoPlan','frecuenciaPagos','observaciones'];\n const o={manualDates:{...manualDates}};\n ids.forEach(id=\u0026gt;o[id]=$(id).value);\n return o;\n}\n\nfunction apply(d){\n Object.entries(d).forEach(([k,v])=\u0026gt;{if(k!=='manualDates'\u0026amp;\u0026amp;$(k))$(k).value=v});\n manualDates=d.manualDates||{};\n planAdvanceEdited=$('modalidadPago').value==='plan'\u0026amp;\u0026amp;!!$('anticipo').value;\n lastPaymentMode=$('modalidadPago').value;\n if($('precioFinal').value)formatCurrencyInput($('precioFinal'));\n if($('anticipo').value)formatCurrencyInput($('anticipo'));\n update();\n}\n\nfunction getSaved(){try{return JSON.parse(localStorage.getItem('fichasProyecto')||'{}')}catch(e){return {}}}\nfunction setSaved(o){localStorage.setItem('fichasProyecto',JSON.stringify(o))}\nfunction refreshSaved(){\n const saved=getSaved(),sel=$('savedSelect'),cur=sel.value;\n sel.innerHTML='\u0026lt;option value=\"\"\u0026gt;Selecciona una ficha guardada\u0026lt;\/option\u0026gt;';\n Object.keys(saved).sort().reverse().forEach(k=\u0026gt;{const op=document.createElement('option');op.value=k;op.textContent=k+(saved[k].nombre?' \u00b7 '+saved[k].nombre:'');sel.appendChild(op)});\n if(saved[cur])sel.value=cur;\n}\nfunction saveCurrent(){\n const d=collect();if(!d.folio.trim()){alert('Agrega un folio.');return}\n const saved=getSaved();saved[d.folio]=d;setSaved(saved);commitFolio(d.folio);refreshSaved();$('savedSelect').value=d.folio;alert('Ficha guardada correctamente.');\n}\n\nfunction newFicha(){\n manualDates={};\n planAdvanceEdited=false;\n lastPaymentMode='';\n document.querySelectorAll('input[type=text],input[type=tel],input[type=number],textarea').forEach(el=\u0026gt;el.value='');\n $('folio').value=getNextFolio();\n $('fechaVisita').value=todayISO();\n $('fechaInstalacion').value='';$('duracionProyecto').value='';$('horaInstalacion').value='';\n $('tipoInstalacion').value='';$('columnas').value='0';$('caida').value='';\n $('vigaPrincipal').value='';$('vigaSecundaria').value='';\n $('viguetasCantidad').value='0';$('viguetasMedida').value='';\n $('ripasCantidad').value='0';$('ripasMedida').value='';\n $('medidaColumnas').value='';$('cubierta').value='';$('revestimiento').value='';\n $('precioFinal').value='';$('modalidadPago').value='';$('anticipo').value='';$('numeroPagos').value='';$('frecuenciaPagos').value='';\n $('fechaAnticipo').value=todayISO();\n $('fechaAnticipoPlan').value=todayISO();\n syncStructuralFields();syncPaymentMode();update();\n}\n\nasync function downloadPDF(){\n update();\n const rows=buildPayments(),notice=$('pdfNotice');\n if(!$('modalidadPago').value){notice.style.display='block';notice.textContent='Selecciona una modalidad de pago antes de descargar el PDF.';return}\n if(!parseCurrency($('precioFinal').value)){notice.style.display='block';notice.textContent='Ingresa el precio final antes de descargar el PDF.';return}\n if(!rows.length||rows.some(r=\u0026gt;!r.date)){notice.style.display='block';notice.textContent='Completa las fechas del esquema de pago antes de descargar el PDF.';return}\n notice.style.display='none';\n\n if(typeof html2pdf==='undefined'){\n alert('No se pudo cargar el generador de PDF. Revisa tu conexi\u00f3n a internet.');\n return;\n }\n\n const filename=($('folio').value||'Ficha_Proyecto').replace(\/[^a-zA-Z0-9_-]\/g,'_')+'.pdf';\n\n \/\/ El PDF se genera desde una copia exacta de la tarjeta-resumen visible.\n const stage=document.createElement('div');\n stage.className='pdf-export-stage';\n\n const card=document.querySelector('.preview-card').cloneNode(true);\n stage.appendChild(card);\n document.body.appendChild(stage);\n\n try{\n await html2pdf().set({\n margin:[18,18,18,18],\n filename,\n image:{type:'jpeg',quality:.98},\n html2canvas:{scale:2,useCORS:true,backgroundColor:'#f3f3f3'},\n jsPDF:{unit:'pt',format:'a4',orientation:'portrait'},\n pagebreak:{mode:['avoid-all','css','legacy']}\n }).from(card).save();\n }finally{\n stage.remove();\n }\n}\n\nfillQty('viguetasCantidad','Sin viguetas');\nfillQty('ripasCantidad','Sin ripas');\n\nconst ids=['folio','fechaVisita','fechaInstalacion','duracionProyecto','horaInstalacion','nombre','telefono','direccion','ancho','largo','alturaFrontal','alturaPosterior','tipoInstalacion','columnas','caida','vigaPrincipal','vigaSecundaria','viguetasCantidad','viguetasMedida','ripasCantidad','ripasMedida','medidaColumnas','cubierta','revestimiento','modalidadPago','numeroPagos','fechaAnticipo','fechaAnticipoPlan','frecuenciaPagos','observaciones'];\nids.forEach(id=\u0026gt;{\n $(id).addEventListener('input',()=\u0026gt;{\n if(id==='frecuenciaPagos'\u0026amp;\u0026amp;$('frecuenciaPagos').value!=='manual')manualDates={};\n if(id==='numeroPagos'){planAdvanceEdited=false;manualDates={};}\n update();\n });\n $(id).addEventListener('change',()=\u0026gt;{\n if(id==='frecuenciaPagos'\u0026amp;\u0026amp;$('frecuenciaPagos').value!=='manual')manualDates={};\n if(id==='numeroPagos'){planAdvanceEdited=false;manualDates={};}\n update();\n });\n});\n\n$('precioFinal').addEventListener('input',()=\u0026gt;{\n formatCurrencyInput($('precioFinal'));\n if($('modalidadPago').value==='plan')planAdvanceEdited=false;\n update();\n});\n$('precioFinal').addEventListener('blur',()=\u0026gt;{formatCurrencyInput($('precioFinal'));update()});\n\n$('anticipo').addEventListener('input',()=\u0026gt;{\n planAdvanceEdited=true;\n formatCurrencyInput($('anticipo'));\n update();\n});\n$('anticipo').addEventListener('blur',()=\u0026gt;{formatCurrencyInput($('anticipo'));update()});\n\n$('btnActualizar').addEventListener('click',()=\u0026gt;update());\n$('btnPDF').addEventListener('click',downloadPDF);\n$('btnGuardar').addEventListener('click',saveCurrent);\n$('btnNueva').addEventListener('click',()=\u0026gt;{if(confirm('\u00bfCrear una nueva ficha? Los datos no guardados se limpiar\u00e1n.'))newFicha()});\n$('btnCargar').addEventListener('click',()=\u0026gt;{const k=$('savedSelect').value,s=getSaved();if(k\u0026amp;\u0026amp;s[k])apply(s[k])});\n$('btnEliminar').addEventListener('click',()=\u0026gt;{const k=$('savedSelect').value;if(!k)return;if(confirm('\u00bfEliminar la ficha '+k+'?')){const s=getSaved();delete s[k];setSaved(s);refreshSaved()}});\nrefreshSaved();\nnewFicha();\n\u0026lt;\/script\u0026gt;\n\u0026lt;\/body\u0026gt;\n\u0026lt;\/html\u0026gt;","render_as_iframe":true,"selected_app_name":"HtmlApp","app_list":"{\"HtmlApp\":9333751}"}}}],"title":"Ficha de proyecto","uid":"fcba79f7-0b22-4980-b6c9-2e59688bce44","path":"\/ficha-de-proyecto","autoPath":true,"authorized":true},{"type":"Page","id":"f_df2a4406-e8ed-4237-9521-00111949ca77","sections":[{"type":"Slide","id":"f_407c3ecf-5e9c-4c1e-98c8-1ac31cf2c76a","defaultValue":true,"template_name":"html","template_version":"","components":{"slideSettings":{"type":"SlideSettings","id":"f_f525b0b3-9887-4fb5-9715-b6f11425327a","defaultValue":true,"show_nav":true,"hidden_section":false,"hidden_mobile_section":false,"name":"App Store","sync_key":null,"padding":{"top":"none","bottom":"half"}},"text1":{"type":"RichText","id":"f_8411d1a8-dae8-40c7-80d4-10391379a1cc","defaultValue":false,"value":"","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":null},"defaultDataProcessed":true},"text2":{"type":"RichText","id":"f_c71882f5-018b-4bdf-ba93-b1d7e5dabba4","defaultValue":false,"value":"","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":null},"defaultDataProcessed":true},"background1":{"type":"Background","id":"f_787a8924-52e3-453a-8296-e09baff90c64","defaultValue":true,"url":"","textColor":"light","backgroundVariation":"","sizing":"cover","videoUrl":"","videoHtml":""},"html1":{"type":"HtmlComponent","id":27591130,"defaultValue":false,"value":"\u0026lt;!doctype html\u0026gt;\n\u0026lt;html lang=\"es\"\u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;meta charset=\"utf-8\"\u0026gt;\n\u0026lt;meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\u0026gt;\n\u0026lt;meta name=\"theme-color\" content=\"#faf6ef\"\u0026gt;\n\u0026lt;title\u0026gt;Simulador 3D de P\u00e9rgola\u0026lt;\/title\u0026gt;\n\u0026lt;style\u0026gt;\n:root{\n --accent:#8b5e34;\n --accent2:#c49b66;\n --bg:#f3f3f3;\n --panel:#ffffff;\n --soft:#faf6ef;\n --line:#eadcc9;\n --text:#111111;\n --muted:#666666;\n --shadow:0 14px 34px rgba(63,43,25,.10);\n}\n*{box-sizing:border-box}\nhtml,body{margin:0;min-height:100%;background:var(--bg);color:var(--text);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif}\nbody{overflow:auto}\n\/* Evita que el propio documento agregue un ancho m\u00e1ximo al simulador. *\/\nbody \u0026gt; .app{max-width:none}\nbutton,input{font:inherit}\nbutton{-webkit-tap-highlight-color:transparent}\n\n.app{\n --sidebar-w:clamp(420px,36vw,520px);\n width:100vw;\n min-height:100svh;\n display:grid;\n grid-template-columns:var(--sidebar-w) minmax(0,1fr);\n background:var(--bg);\n}\n.sidebar{\n min-width:0;\n min-height:100svh;\n padding:28px 26px 40px;\n background:var(--panel);\n border-right:1px solid var(--line);\n}\n.header{display:flex;justify-content:space-between;align-items:flex-start;gap:14px;margin-bottom:26px}\n.header h1{margin:0;color:var(--accent);font-size:32px;line-height:1.08;font-weight:900;letter-spacing:-.025em}\n.header p{margin:8px 0 0;color:var(--muted);font-size:16px}\n.tag{flex:0 0 auto;border:1px solid var(--line);background:var(--soft);color:var(--accent);border-radius:999px;padding:9px 12px;font-size:12px;font-weight:850}\n.section{padding:22px 0;border-top:1px solid #f1e9df}\n.section:first-of-type{padding-top:0;border-top:0}\n.section-title{margin:0 0 14px;font-size:14px;text-transform:uppercase;letter-spacing:.105em;color:#777;font-weight:900}\n.wall-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}\n.wall-btn,.side-btn{border:2px solid #e3e3e3;background:#fff;color:#3d3d3d;border-radius:14px;padding:14px 10px;font-size:16px;font-weight:850;cursor:pointer;transition:.15s ease}\n.wall-btn:hover,.side-btn:hover{border-color:var(--accent2)}\n.wall-btn.active,.side-btn.active{border-color:var(--accent);background:linear-gradient(135deg,var(--accent),var(--accent2));color:#fff}\n.side-choice{display:none;margin-top:10px;padding:10px;border:1px solid var(--line);border-radius:14px;background:var(--soft)}\n.side-choice.visible{display:block}\n.side-choice .mini-title{margin:0 0 8px;color:#6e6258;font-size:10.5px;font-weight:800}\n.side-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px}\n.column-placement{margin-top:14px}\n.column-placement .side-choice{margin-top:10px;padding:12px}\n.column-placement .mini-title{font-size:12.5px;letter-spacing:.02em;color:#5f554d}\n.column-placement .side-btn{font-size:14px;padding:10px 8px}\n.side-btn{padding:8px 7px;border-width:1.5px;background:#fff}\n.hint{margin-top:11px;color:#7a7068;font-size:13px;line-height:1.45}\n.control{margin-bottom:22px}\n.control:last-child{margin-bottom:0}\n.label-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}\n.label-row label{font-size:15.5px;font-weight:850;color:#44372d}\n.limits{display:flex;justify-content:space-between;margin-bottom:5px;color:#8b8178;font-size:12px}\ninput[type=range]{width:100%;margin:0;cursor:pointer;accent-color:var(--accent);background:transparent}\ninput[type=range]::-webkit-slider-runnable-track{height:7px;border-radius:999px;background:linear-gradient(90deg,var(--accent),var(--accent2))}\ninput[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:23px;height:23px;margin-top:-8px;border-radius:50%;background:#fff;border:4px solid var(--accent);box-shadow:0 1px 5px rgba(0,0,0,.14)}\ninput[type=range]::-moz-range-track{height:6px;border-radius:999px;background:linear-gradient(90deg,var(--accent),var(--accent2))}\ninput[type=range]::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:#fff;border:4px solid var(--accent)}\n.value-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;margin-top:7px;overflow:hidden;border:2px solid #e4e4e4;border-radius:14px;background:#fff}\n.value-row:focus-within{border-color:var(--accent2)}\n.value-row input{width:100%;min-width:0;padding:11px 12px;border:0;outline:0;background:#fff;color:#2e2a26;font-size:15px;font-weight:750}\n.unit{display:flex;align-items:center;padding:0 13px;border-left:1px solid var(--line);background:var(--soft);color:#6d6258;font-size:12px}\n.actions{display:grid;grid-template-columns:1fr 1fr;gap:9px}\n.action{border:2px solid #ddd;background:#fff;color:#4d443d;border-radius:14px;padding:13px 10px;font-size:14px;font-weight:850;cursor:pointer}\n.action.primary{border-color:transparent;background:linear-gradient(135deg,var(--accent),var(--accent2));color:#fff}\n.note{margin-top:11px;color:#847a72;font-size:12px;line-height:1.5}\n\n\/* VISOR DE ESCRITORIO: el canvas ocupa TODO el panel derecho.\n La informaci\u00f3n y los botones flotan encima del canvas y ya no consumen altura. *\/\n.viewer{\n min-width:0;\n min-height:100svh;\n position:relative;\n overflow:hidden;\n background:#fff;\n}\n.viewer-top{\n position:absolute;\n z-index:7;\n top:20px;\n left:22px;\n right:22px;\n display:flex;\n align-items:flex-start;\n justify-content:space-between;\n gap:18px;\n pointer-events:none;\n}\n.info{\n min-width:270px;\n max-width:48%;\n padding:13px 16px;\n border:1px solid var(--line);\n border-radius:16px;\n background:rgba(255,255,255,.95);\n box-shadow:var(--shadow);\n backdrop-filter:blur(4px);\n pointer-events:auto;\n}\n.info strong{display:block;color:var(--accent);font-size:19px;line-height:1.15}\n.info span{display:block;margin-top:5px;color:#746b63;font-size:14px;line-height:1.35}\n.views{display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap;pointer-events:auto}\n.views button{\n padding:11px 15px;\n border:1px solid var(--line);\n border-radius:13px;\n background:rgba(255,255,255,.95);\n color:#51473e;\n font-size:14px;\n font-weight:850;\n cursor:pointer;\n box-shadow:0 6px 16px rgba(69,49,32,.06)\n}\n.views button.active{border-color:var(--accent2);background:var(--soft);color:var(--accent)}\n.stage-wrap{\n position:absolute;\n inset:0;\n width:100%;\n height:100%;\n overflow:hidden;\n background:linear-gradient(180deg,#fff 0%,#fbfaf8 100%);\n}\n.stage-wrap::before{content:\"\";position:absolute;inset:12px;border:1px solid var(--line);border-radius:20px;pointer-events:none;z-index:2}\n.viewer canvas{position:absolute;inset:0;width:100%;height:100%;display:block;touch-action:none}\n.viewer-bottom{position:absolute;z-index:6;left:24px;bottom:24px;padding:10px 13px;border:1px solid var(--line);border-radius:12px;background:rgba(255,255,255,.94);color:#756a61;font-size:12px;pointer-events:none}\n.status{position:absolute;z-index:8;right:24px;bottom:24px;display:none;padding:9px 11px;border-radius:12px;background:linear-gradient(135deg,var(--accent),var(--accent2));color:#fff;font-size:10.5px;font-weight:800;box-shadow:var(--shadow)}\n\n@media (min-width:841px){\n \/* Escritorio sin iframe: el simulador permanece dentro del flujo normal\n de la p\u00e1gina. As\u00ed ocupa una pantalla completa, pero cualquier footer\n que exista despu\u00e9s comienza DEBAJO del simulador y nunca se superpone. *\/\n html{\n width:100%;\n min-width:0;\n min-height:100%;\n overflow-x:hidden;\n }\n body{\n width:100%;\n min-width:0;\n min-height:100vh;\n min-height:100dvh;\n height:auto;\n overflow-x:hidden;\n overflow-y:auto;\n }\n .app{\n --sidebar-w:clamp(390px,32vw,510px);\n position:relative;\n inset:auto;\n\n \/* FULL-BLEED: rompe cualquier max-width del contenedor de la p\u00e1gina.\n Esto permite que el simulador llegue f\u00edsicamente de borde a borde\n aunque el bloque HTML est\u00e9 dentro de una columna centrada. *\/\n width:100vw;\n max-width:100vw;\n margin-left:calc(50% - 50vw);\n margin-right:calc(50% - 50vw);\n\n height:100vh;\n height:100dvh;\n min-height:0;\n display:grid;\n grid-template-columns:var(--sidebar-w) minmax(0,1fr);\n overflow:hidden;\n isolation:isolate;\n }\n .sidebar{\n height:100%;\n min-height:0;\n overflow-y:auto;\n overflow-x:hidden;\n overscroll-behavior:contain;\n scrollbar-gutter:stable;\n padding:30px 28px 42px;\n }\n .sidebar::-webkit-scrollbar{width:10px}\n .sidebar::-webkit-scrollbar-track{background:transparent}\n .sidebar::-webkit-scrollbar-thumb{background:#dfd0bd;border:3px solid #fff;border-radius:999px}\n .viewer{\n position:relative;\n height:100%;\n min-height:0;\n width:100%;\n }\n}\n\n\/* En laptops con poca altura no encogemos toda la interfaz. Solamente hacemos\n m\u00e1s compactos los elementos flotantes; el canvas sigue midiendo 100% de alto. *\/\n@media (min-width:841px) and (max-height:560px){\n .viewer-top{top:12px;left:16px;right:16px;gap:10px}\n .info{min-width:235px;padding:9px 12px;border-radius:13px}\n .info strong{font-size:16px}.info span{font-size:12px;margin-top:3px}\n .views{gap:5px;max-width:55%}\n .views button{padding:8px 10px;font-size:12px;border-radius:11px}\n .viewer-bottom{left:18px;bottom:14px;padding:7px 10px;font-size:10px}\n .status{right:18px;bottom:14px}\n .stage-wrap::before{inset:8px;border-radius:16px}\n}\n\n@media (max-width:840px){\n .app{display:flex;min-height:100svh;flex-direction:column;width:100%;max-width:none;margin-left:0;margin-right:0}\n .viewer{order:1;width:100%;height:54svh;min-height:390px;max-height:560px;display:flex;flex-direction:column;position:relative}\n .sidebar{order:2;min-height:0;width:100%;padding:20px 16px 32px;border-right:0;border-top:1px solid var(--line)}\n .viewer-top{position:relative;top:auto;left:auto;right:auto;z-index:7;flex:0 0 auto;padding:12px 12px 9px;align-items:flex-start;flex-direction:column;gap:8px;pointer-events:auto}\n .info{min-width:0;max-width:82%;padding:8px 10px;border-radius:13px}\n .info strong{font-size:15px}.info span{font-size:12px}\n .views{width:100%;justify-content:flex-start;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px;scrollbar-width:none}\n .views::-webkit-scrollbar{display:none}\n .views button{flex:0 0 auto;padding:7px 9px;font-size:12px}\n .stage-wrap{position:relative;inset:auto;flex:1 1 auto;min-height:0;width:100%;height:auto}\n .stage-wrap::before{inset:8px;border-radius:16px}\n .viewer-bottom{left:16px;bottom:16px;max-width:calc(100% - 32px);font-size:9.5px}\n .status{right:16px;bottom:16px}\n .header h1{font-size:22px}.header p{font-size:13px}.section-title{font-size:11.5px}\n .wall-btn{font-size:12px;padding:10px 6px}.label-row label{font-size:13px}.limits{font-size:10px}\n .value-row input{font-size:12.5px;padding:8px 10px}.unit{font-size:10.5px;padding:0 10px}\n}\n@media (max-width:520px){\n .viewer{height:49svh;min-height:350px;max-height:470px}\n .header h1{font-size:20px}.tag{font-size:9px;padding:6px 8px}.viewer-bottom{display:none}\n}\n\u0026lt;\/style\u0026gt;\n\u0026lt;\/head\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;div class=\"app\"\u0026gt;\n \u0026lt;aside class=\"sidebar\"\u0026gt;\n \u0026lt;div class=\"header\"\u0026gt;\n \u0026lt;div\u0026gt;\u0026lt;h1\u0026gt;Simulador 3D de P\u00e9rgola\u0026lt;\/h1\u0026gt;\u0026lt;p\u0026gt;Propuesta visual para cliente\u0026lt;\/p\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n\n \u0026lt;section class=\"section\"\u0026gt;\n \u0026lt;div class=\"section-title\"\u0026gt;Tipo de instalaci\u00f3n\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"wall-grid\"\u0026gt;\n \u0026lt;button class=\"wall-btn active\" data-walls=\"0\"\u0026gt;Independiente\u0026lt;\/button\u0026gt;\n \u0026lt;button class=\"wall-btn\" data-walls=\"1\"\u0026gt;Endosada a pared\u0026lt;\/button\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"hint\" id=\"wallHint\"\u0026gt;Estructura independiente, sin muro de apoyo.\u0026lt;\/div\u0026gt;\n \u0026lt;\/section\u0026gt;\n\n \u0026lt;section class=\"section\"\u0026gt;\u0026lt;div class=\"section-title\"\u0026gt;Dimensiones generales\u0026lt;\/div\u0026gt;\u0026lt;div id=\"dimensions\"\u0026gt;\u0026lt;\/div\u0026gt;\u0026lt;\/section\u0026gt;\n \u0026lt;section class=\"section\"\u0026gt;\u0026lt;div class=\"section-title\"\u0026gt;Secciones de la estructura\u0026lt;\/div\u0026gt;\u0026lt;div id=\"structure\"\u0026gt;\u0026lt;\/div\u0026gt;\u0026lt;\/section\u0026gt;\n \u0026lt;section class=\"section\"\u0026gt;\n \u0026lt;div class=\"section-title\"\u0026gt;Cantidad\u0026lt;\/div\u0026gt;\n \u0026lt;div id=\"counts\"\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"column-placement\" id=\"columnPlacement\"\u0026gt;\n \u0026lt;div class=\"side-choice\" id=\"singleColumnChoice\"\u0026gt;\n \u0026lt;div class=\"mini-title\"\u0026gt;Ubicaci\u00f3n de la columna\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"side-grid\"\u0026gt;\n \u0026lt;button class=\"side-btn active\" type=\"button\" data-column-side=\"left\"\u0026gt;Izquierda\u0026lt;\/button\u0026gt;\n \u0026lt;button class=\"side-btn\" type=\"button\" data-column-side=\"right\"\u0026gt;Derecha\u0026lt;\/button\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"side-choice\" id=\"thirdColumnChoice\"\u0026gt;\n \u0026lt;div class=\"mini-title\"\u0026gt;Ubicaci\u00f3n de la columna posterior\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"side-grid\"\u0026gt;\n \u0026lt;button class=\"side-btn active\" type=\"button\" data-third-side=\"left\"\u0026gt;Izquierda\u0026lt;\/button\u0026gt;\n \u0026lt;button class=\"side-btn\" type=\"button\" data-third-side=\"right\"\u0026gt;Derecha\u0026lt;\/button\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/section\u0026gt;\n\n \u0026lt;section class=\"section\"\u0026gt;\n \u0026lt;div class=\"section-title\"\u0026gt;Herramientas\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"actions\"\u0026gt;\n \u0026lt;button class=\"action\" id=\"resetModel\"\u0026gt;Restablecer\u0026lt;\/button\u0026gt;\n \u0026lt;button class=\"action primary\" id=\"saveImage\"\u0026gt;Guardar imagen\u0026lt;\/button\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"note\"\u0026gt;Simulador visual para propuesta al cliente. No sustituye un c\u00e1lculo estructural.\u0026lt;\/div\u0026gt;\n \u0026lt;\/section\u0026gt;\n \u0026lt;\/aside\u0026gt;\n\n \u0026lt;main class=\"viewer\" id=\"viewer\"\u0026gt;\n \u0026lt;div class=\"viewer-top\"\u0026gt;\n \u0026lt;div class=\"info\"\u0026gt;\u0026lt;strong id=\"projectTitle\"\u0026gt;P\u00e9rgola independiente\u0026lt;\/strong\u0026gt;\u0026lt;span id=\"projectDims\"\u0026gt;3.50 \u00d7 2.40 m \u00b7 altura 2.50 m\u0026lt;\/span\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"views\"\u0026gt;\n \u0026lt;button class=\"active\" data-view=\"iso\"\u0026gt;Isom\u00e9trica\u0026lt;\/button\u0026gt;\n \u0026lt;button data-view=\"front\"\u0026gt;Frente\u0026lt;\/button\u0026gt;\n \u0026lt;button data-view=\"side\"\u0026gt;Lateral\u0026lt;\/button\u0026gt;\n \u0026lt;button data-view=\"top\"\u0026gt;Superior\u0026lt;\/button\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"stage-wrap\" id=\"stageWrap\"\u0026gt;\n \u0026lt;canvas id=\"stage\" aria-label=\"Vista 3D de la p\u00e9rgola\"\u0026gt;\u0026lt;\/canvas\u0026gt;\n \u0026lt;div class=\"viewer-bottom\"\u0026gt;Arrastra para girar \u00b7 rueda\/pellizco para acercar\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"status\" id=\"status\"\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;\n \u0026lt;\/main\u0026gt;\n\u0026lt;\/div\u0026gt;\n\n\u0026lt;script\u0026gt;\n(()=\u0026gt;{\n'use strict';\n\nconst defaults={\n walls:0,\n length:3500,\n width:2400,\n height:2500,\n column:120,\n beamW:100,\n beamH:180,\n joistW:55,\n joistH:110,\n joists:14,\n columns:4,\n singleColumnSide:'left',\n thirdColumnSide:'left'\n};\nconst state={...defaults};\n\nconst groups={\n dimensions:[\n {key:'length',label:'Largo',min:2000,max:8000,step:10,unit:'mm'},\n {key:'width',label:'Ancho',min:1500,max:6000,step:10,unit:'mm'},\n {key:'height',label:'Altura',min:1800,max:4000,step:10,unit:'mm'}\n ],\n structure:[\n {key:'column',label:'Grosor de columnas',min:60,max:300,step:5,unit:'mm'},\n {key:'beamW',label:'Ancho de vigas',min:60,max:300,step:5,unit:'mm'},\n {key:'beamH',label:'Alto de vigas',min:80,max:400,step:5,unit:'mm'},\n {key:'joistW',label:'Ancho de viguetas',min:25,max:180,step:5,unit:'mm'},\n {key:'joistH',label:'Alto de viguetas',min:40,max:260,step:5,unit:'mm'}\n ],\n counts:[\n {key:'joists',label:'N\u00famero de viguetas',min:2,max:30,step:1,unit:'pzas'},\n {key:'columns',label:'N\u00famero de columnas',min:0,max:6,step:1,unit:'pzas'}\n ]\n};\nconst allSpecs=()=\u0026gt;[...groups.dimensions,...groups.structure,...groups.counts];\nconst fmtLimit=(v,u)=\u0026gt;u==='mm'\u0026amp;\u0026amp;v\u0026gt;=1000?(v\/1000).toFixed(v%1000?2:1)+' m':v+' '+u;\nfunction controlHTML(s){\n return `\u0026lt;div class=\"control\" data-control=\"${s.key}\"\u0026gt;\n \u0026lt;div class=\"label-row\"\u0026gt;\u0026lt;label\u0026gt;${s.label}\u0026lt;\/label\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;div class=\"limits\"\u0026gt;\u0026lt;span\u0026gt;${fmtLimit(s.min,s.unit)}\u0026lt;\/span\u0026gt;\u0026lt;span\u0026gt;${fmtLimit(s.max,s.unit)}\u0026lt;\/span\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;input type=\"range\" data-range=\"${s.key}\" min=\"${s.min}\" max=\"${s.max}\" step=\"${s.step}\" value=\"${state[s.key]}\"\u0026gt;\n \u0026lt;div class=\"value-row\"\u0026gt;\u0026lt;input inputmode=\"numeric\" type=\"number\" data-number=\"${s.key}\" min=\"${s.min}\" max=\"${s.max}\" step=\"${s.step}\" value=\"${state[s.key]}\"\u0026gt;\u0026lt;span class=\"unit\"\u0026gt;${s.unit}\u0026lt;\/span\u0026gt;\u0026lt;\/div\u0026gt;\n \u0026lt;\/div\u0026gt;`;\n}\ndocument.getElementById('dimensions').innerHTML=groups.dimensions.map(controlHTML).join('');\ndocument.getElementById('structure').innerHTML=groups.structure.map(controlHTML).join('');\ndocument.getElementById('counts').innerHTML=groups.counts.map(controlHTML).join('');\n\nconst canvas=document.getElementById('stage');\nconst viewer=document.getElementById('viewer');\nconst stageWrap=document.getElementById('stageWrap');\nconst ctx=canvas.getContext('2d',{alpha:false});\nlet yaw=-0.72,pitch=0.48,zoom=1,drag=false,lastX=0,lastY=0;\nlet sceneBoxes=[];\n\nconst rgb={\n structure:[49,52,56],\n wall:[247,244,240],\n wallEdge:[211,199,187]\n};\nconst faces=[\n {idx:[0,1,2,3],n:[0,0,-1]},\n {idx:[4,7,6,5],n:[0,0,1]},\n {idx:[0,4,5,1],n:[-1,0,0]},\n {idx:[3,2,6,7],n:[1,0,0]},\n {idx:[0,3,7,4],n:[0,-1,0]},\n {idx:[1,5,6,2],n:[0,1,0]}\n];\nconst light=normalize([-.35,.8,.55]);\n\nfunction mm(v){return v\/1000}\nfunction addBox(cx,cy,cz,w,h,d,kind='structure'){sceneBoxes.push({cx,cy,cz,w,h,d,kind})}\n\nfunction rebuildScene(){\n sceneBoxes=[];\n const L=mm(state.length),W=mm(state.width),H=mm(state.height),C=mm(state.column);\n const BW=mm(state.beamW),BH=mm(state.beamH),JW=mm(state.joistW),JH=mm(state.joistH);\n const beamY=H-BH\/2;\n const colH=Math.max(.25,H-BH);\n const colY=colH\/2;\n const frontZ=W\/2-C\/2;\n const backZ=-W\/2+C\/2;\n\n \/\/ Marco superior.\n addBox(0,beamY,W\/2-BW\/2,L,BH,BW);\n addBox(0,beamY,-W\/2+BW\/2,L,BH,BW);\n addBox(-L\/2+BW\/2,beamY,0,BW,BH,Math.max(.12,W-2*BW));\n addBox(L\/2-BW\/2,beamY,0,BW,BH,Math.max(.12,W-2*BW));\n\n \/\/ Viguetas repartidas uniformemente a lo largo.\n const n=Math.max(2,Math.round(state.joists));\n const x0=-L\/2+BW+JW\/2;\n const x1=L\/2-BW-JW\/2;\n for(let i=0;i\u0026lt;n;i++){\n const t=n===1?.5:i\/(n-1);\n addBox(x0+(x1-x0)*t,H-JH\/2,0,JW,JH,Math.max(.12,W-2*BW));\n }\n\n \/\/ Muros de apoyo: fondo y, opcionalmente, laterales.\n addWalls(L,W,H);\n\n \/\/ Columnas. 0 es una opci\u00f3n v\u00e1lida.\n addColumns(Math.max(0,Math.round(state.columns)),L,W,C,colH,colY,frontZ,backZ);\n\n updateColumnPlacementUI();\n updateSummary();\n requestRender();\n}\n\nfunction addWalls(L,W,H){\n if(state.walls!==1)return;\n const wt=.13;\n const gap=.035;\n const wallH=H+1.05;\n const backZ=-W\/2-wt\/2-gap;\n addBox(0,wallH\/2,backZ,L+1.15,wallH,wt,'wall');\n addBox(0,wallH+.035,backZ,L+1.15,.07,wt+.04,'wallEdge');\n}\n\nfunction addColumns(count,L,W,C,colH,colY,frontZ,backZ){\n \/* Posiciones deliberadamente predefinidas.\n 1\u20134 columnas: SOLO esquinas; nunca se reparten matem\u00e1ticamente.\n 5 columnas: cuatro esquinas + centro frontal.\n 6 columnas: cuatro esquinas + centro frontal + centro posterior. *\/\n count=Math.max(0,Math.min(6,Math.round(count)));\n if(count\u0026lt;=0)return;\n\n const leftX=-L\/2+C\/2;\n const rightX=L\/2-C\/2;\n const FL=[leftX,frontZ];\n const FR=[rightX,frontZ];\n const BL=[leftX,backZ];\n const BR=[rightX,backZ];\n const FC=[0,frontZ];\n const BC=[0,backZ];\n\n let positions=[];\n if(count===1){\n positions=[state.singleColumnSide==='right'?FR:FL];\n }else if(count===2){\n positions=[FL,FR];\n }else if(count===3){\n positions=[FL,FR,state.thirdColumnSide==='right'?BR:BL];\n }else if(count===4){\n positions=[FL,FR,BL,BR];\n }else if(count===5){\n positions=[FL,FR,BL,BR,FC];\n }else if(count===6){\n positions=[FL,FR,BL,BR,FC,BC];\n }\n\n for(const [x,z] of positions){\n addBox(x,colY,z,C,colH,C);\n }\n}\nfunction vertices(b){\n const x=b.w\/2,y=b.h\/2,z=b.d\/2;\n return [[-x,-y,-z],[-x,y,-z],[x,y,-z],[x,-y,-z],[-x,-y,z],[-x,y,z],[x,y,z],[x,-y,z]].map(p=\u0026gt;[p[0]+b.cx,p[1]+b.cy,p[2]+b.cz]);\n}\nfunction rotatePoint(p){\n const pivotY=mm(state.height)*.46;\n const py=p[1]-pivotY;\n const cy=Math.cos(yaw),sy=Math.sin(yaw),cp=Math.cos(pitch),sp=Math.sin(pitch);\n const x1=p[0]*cy+p[2]*sy;\n const z1=-p[0]*sy+p[2]*cy;\n const y2=py*cp-z1*sp;\n const z2=py*sp+z1*cp;\n return [x1,y2+pivotY,z2];\n}\nfunction rotateNormal(n){\n const cy=Math.cos(yaw),sy=Math.sin(yaw),cp=Math.cos(pitch),sp=Math.sin(pitch);\n const x1=n[0]*cy+n[2]*sy;\n const z1=-n[0]*sy+n[2]*cy;\n return [x1,n[1]*cp-z1*sp,n[1]*sp+z1*cp];\n}\nfunction normalize(v){const l=Math.hypot(...v)||1;return v.map(x=\u0026gt;x\/l)}\nfunction dot(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]}\nfunction colorFor(kind,factor){\n const base=rgb[kind]||rgb.structure;\n const k=Math.max(.45,Math.min(1.25,factor));\n return `rgb(${Math.round(Math.min(255,base[0]*k))},${Math.round(Math.min(255,base[1]*k))},${Math.round(Math.min(255,base[2]*k))})`;\n}\n\nfunction canvasMetrics(){\n const rect=stageWrap.getBoundingClientRect();\n const cssW=Math.max(1,Math.round(rect.width));\n const cssH=Math.max(1,Math.round(rect.height));\n const dpr=Math.min(window.devicePixelRatio||1,2);\n const pxW=Math.max(1,Math.round(cssW*dpr));\n const pxH=Math.max(1,Math.round(cssH*dpr));\n if(canvas.width!==pxW || canvas.height!==pxH){canvas.width=pxW;canvas.height=pxH;}\n return {w:pxW,h:pxH,dpr,cssW,cssH};\n}\n\nfunction projector(m){\n \/* Ajuste por l\u00edmites reales de la p\u00e9rgola. Esto evita que en pantallas Retina\n de poca altura el modelo quede diminuto por reservar demasiado espacio. *\/\n const pts=[];\n for(const b of sceneBoxes){\n for(const v of vertices(b)) pts.push(rotatePoint(v));\n }\n if(!pts.length) pts.push([-1,0,0],[1,mm(state.height),0]);\n\n let minX=Infinity,maxX=-Infinity,minY=Infinity,maxY=-Infinity;\n for(const p of pts){\n if(p[0]\u0026lt;minX)minX=p[0]; if(p[0]\u0026gt;maxX)maxX=p[0];\n if(p[1]\u0026lt;minY)minY=p[1]; if(p[1]\u0026gt;maxY)maxY=p[1];\n }\n const bw=Math.max(.25,maxX-minX), bh=Math.max(.25,maxY-minY);\n const mobile=window.innerWidth\u0026lt;=840;\n const lowDesktop=!mobile \u0026amp;\u0026amp; m.cssH\u0026lt;=560;\n const leftCss=mobile?14:22;\n const rightCss=mobile?14:22;\n \/\/ En escritorio el canvas est\u00e1 detr\u00e1s de los controles flotantes. Reservamos\n \/\/ solo una franja peque\u00f1a, para que la p\u00e9rgola conserve un tama\u00f1o grande.\n const topCss=mobile?12:(lowDesktop?58:86);\n const bottomCss=mobile?14:(lowDesktop?18:26);\n const targetW=Math.max(120*m.dpr,m.w-(leftCss+rightCss)*m.dpr);\n const targetH=Math.max(110*m.dpr,m.h-(topCss+bottomCss)*m.dpr);\n\n \/* El canvas ya no est\u00e1 debajo de los botones. Podemos usar casi el 100% del \u00e1rea. *\/\n const fit=(mobile?.90:(lowDesktop?.98:.96))*Math.min(targetW\/bw,targetH\/bh);\n const s=fit*zoom;\n const centerWorldX=(minX+maxX)\/2;\n const centerWorldY=(minY+maxY)\/2;\n const cx=leftCss*m.dpr+targetW\/2;\n const cy=topCss*m.dpr+targetH\/2;\n\n return p=\u0026gt;{\n const r=rotatePoint(p);\n return {x:cx+(r[0]-centerWorldX)*s,y:cy-(r[1]-centerWorldY)*s,z:r[2],s};\n };\n}\n\nfunction polygon(points,fill,stroke='rgba(20,20,20,.15)',lw=1){\n ctx.beginPath();ctx.moveTo(points[0].x,points[0].y);\n for(let i=1;i\u0026lt;points.length;i++)ctx.lineTo(points[i].x,points[i].y);\n ctx.closePath();ctx.fillStyle=fill;ctx.fill();\n if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();}\n}\n\nlet raf=0;\nfunction requestRender(){\n if(raf)return;\n raf=requestAnimationFrame(()=\u0026gt;{raf=0;render();});\n}\n\nfunction render(){\n const m=canvasMetrics();\n const P=projector(m);\n ctx.clearRect(0,0,m.w,m.h);\n ctx.fillStyle='#fff';ctx.fillRect(0,0,m.w,m.h);\n drawGround(P,m);\n drawShadow(P,m);\n\n const drawFaces=[];\n for(const b of sceneBoxes){\n const vs=vertices(b),rv=vs.map(rotatePoint);\n for(const f of faces){\n const rn=rotateNormal(f.n);\n if(rn[2]\u0026lt;=.002)continue;\n const pts=f.idx.map(i=\u0026gt;P(vs[i]));\n const depth=f.idx.reduce((a,i)=\u0026gt;a+rv[i][2],0)\/4;\n const lightVal=.72+.33*Math.max(0,dot(normalize(rn),light));\n drawFaces.push({pts,depth,fill:colorFor(b.kind,lightVal),kind:b.kind});\n }\n }\n drawFaces.sort((a,b)=\u0026gt;a.depth-b.depth);\n for(const f of drawFaces){\n const stroke=f.kind==='wall'?'rgba(156,140,126,.30)':'rgba(15,15,15,.20)';\n polygon(f.pts,f.fill,stroke,Math.max(1,m.dpr*.55));\n }\n}\n\nfunction drawGround(P,m){\n const S=Math.max(mm(state.length),mm(state.width))*2.35+3.5;\n const corners=[[-S\/2,0,-S\/2],[-S\/2,0,S\/2],[S\/2,0,S\/2],[S\/2,0,-S\/2]].map(P);\n polygon(corners,'#faf9f7',null);\n const step=.5,half=Math.ceil(S\/(2*step))*step;\n ctx.lineWidth=Math.max(.6,m.dpr*.42);\n ctx.strokeStyle='rgba(139,94,52,.10)';\n for(let x=-half;x\u0026lt;=half+.001;x+=step){const a=P([x,0,-half]),b=P([x,0,half]);ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke();}\n for(let z=-half;z\u0026lt;=half+.001;z+=step){const a=P([-half,0,z]),b=P([half,0,z]);ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke();}\n}\nfunction drawShadow(P,m){\n const L=mm(state.length),W=mm(state.width),off=.28;\n const pts=[[-L\/2+off,0,-W\/2+off],[-L\/2+off,0,W\/2+off],[L\/2+off,0,W\/2+off],[L\/2+off,0,-W\/2+off]].map(P);\n ctx.save();ctx.filter=`blur(${10*m.dpr}px)`;polygon(pts,'rgba(73,55,39,.10)',null);ctx.restore();\n}\n\nfunction installName(){\n return state.walls===1?'P\u00e9rgola endosada a pared':'P\u00e9rgola independiente';\n}\nfunction updateSummary(){\n document.getElementById('projectTitle').textContent=installName();\n document.getElementById('projectDims').textContent=`${(state.length\/1000).toFixed(2)} \u00d7 ${(state.width\/1000).toFixed(2)} m \u00b7 altura ${(state.height\/1000).toFixed(2)} m \u00b7 ${state.columns} columna${state.columns===1?'':'s'}`;\n}\nfunction updateWallUI(){\n document.querySelectorAll('.wall-btn').forEach(b=\u0026gt;b.classList.toggle('active',Number(b.dataset.walls)===state.walls));\n document.getElementById('wallHint').textContent=state.walls===1\n ?'La parte posterior de la p\u00e9rgola queda endosada a un solo muro.'\n :'Estructura independiente, sin muro de apoyo.';\n}\n\nfunction updateColumnPlacementUI(){\n const count=Math.max(0,Math.min(6,Math.round(state.columns)));\n const one=document.getElementById('singleColumnChoice');\n const three=document.getElementById('thirdColumnChoice');\n if(one)one.classList.toggle('visible',count===1);\n if(three)three.classList.toggle('visible',count===3);\n\n document.querySelectorAll('[data-column-side]').forEach(btn=\u0026gt;{\n btn.classList.toggle('active',btn.dataset.columnSide===state.singleColumnSide);\n });\n document.querySelectorAll('[data-third-side]').forEach(btn=\u0026gt;{\n btn.classList.toggle('active',btn.dataset.thirdSide===state.thirdColumnSide);\n });\n}\n\nfunction specFor(k){return allSpecs().find(s=\u0026gt;s.key===k)}\nfunction clamp(k,v){\n const s=specFor(k);let n=Number(v);if(!Number.isFinite(n))n=state[k];\n n=Math.max(s.min,Math.min(s.max,n));return Math.round(n\/s.step)*s.step;\n}\nfunction sync(k){\n const r=document.querySelector(`[data-range=\"${k}\"]`);\n const n=document.querySelector(`[data-number=\"${k}\"]`);\n if(r)r.value=state[k];if(n)n.value=state[k];\n}\n\ndocument.querySelectorAll('[data-range]').forEach(el=\u0026gt;el.addEventListener('input',()=\u0026gt;{\n const k=el.dataset.range;state[k]=clamp(k,el.value);sync(k);rebuildScene();\n}));\ndocument.querySelectorAll('[data-number]').forEach(el=\u0026gt;{\n el.addEventListener('change',()=\u0026gt;{const k=el.dataset.number;state[k]=clamp(k,el.value);sync(k);rebuildScene();});\n el.addEventListener('keydown',e=\u0026gt;{if(e.key==='Enter')el.blur();});\n});\n\ndocument.querySelectorAll('.wall-btn').forEach(btn=\u0026gt;btn.addEventListener('click',()=\u0026gt;{\n state.walls=Number(btn.dataset.walls);\n updateWallUI();rebuildScene();setView('iso');\n}));\n\ndocument.querySelectorAll('[data-column-side]').forEach(btn=\u0026gt;btn.addEventListener('click',()=\u0026gt;{\n state.singleColumnSide=btn.dataset.columnSide==='right'?'right':'left';\n updateColumnPlacementUI();rebuildScene();\n}));\ndocument.querySelectorAll('[data-third-side]').forEach(btn=\u0026gt;btn.addEventListener('click',()=\u0026gt;{\n state.thirdColumnSide=btn.dataset.thirdSide==='right'?'right':'left';\n updateColumnPlacementUI();rebuildScene();\n}));\nfunction setView(v){\n if(v==='front'){yaw=0;pitch=.08;}\n else if(v==='side'){yaw=Math.PI\/2;pitch=.08;}\n else if(v==='top'){yaw=0;pitch=1.48;}\n else{yaw=-.72;pitch=.48;v='iso';}\n zoom=1;\n document.querySelectorAll('[data-view]').forEach(b=\u0026gt;b.classList.toggle('active',b.dataset.view===v));\n requestRender();\n}\ndocument.querySelectorAll('[data-view]').forEach(b=\u0026gt;b.addEventListener('click',()=\u0026gt;setView(b.dataset.view)));\n\ncanvas.addEventListener('pointerdown',e=\u0026gt;{\n drag=true;lastX=e.clientX;lastY=e.clientY;\n try{canvas.setPointerCapture(e.pointerId);}catch(_){ }\n});\ncanvas.addEventListener('pointermove',e=\u0026gt;{\n if(!drag)return;\n const dx=e.clientX-lastX,dy=e.clientY-lastY;lastX=e.clientX;lastY=e.clientY;\n yaw+=dx*.008;pitch=Math.max(.03,Math.min(1.50,pitch+dy*.006));requestRender();\n});\ncanvas.addEventListener('pointerup',()=\u0026gt;drag=false);\ncanvas.addEventListener('pointercancel',()=\u0026gt;drag=false);\ncanvas.addEventListener('wheel',e=\u0026gt;{\n e.preventDefault();zoom*=Math.exp(-e.deltaY*.001);zoom=Math.max(.58,Math.min(2.25,zoom));requestRender();\n},{passive:false});\n\nlet pinchDist=null;\ncanvas.addEventListener('touchstart',e=\u0026gt;{\n if(e.touches.length===2)pinchDist=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY);\n},{passive:true});\ncanvas.addEventListener('touchmove',e=\u0026gt;{\n if(e.touches.length===2\u0026amp;\u0026amp;pinchDist){\n const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY);\n zoom*=d\/pinchDist;zoom=Math.max(.58,Math.min(2.25,zoom));pinchDist=d;requestRender();\n }\n},{passive:true});\ncanvas.addEventListener('touchend',()=\u0026gt;pinchDist=null,{passive:true});\n\nconst ro=('ResizeObserver' in window)?new ResizeObserver(()=\u0026gt;requestRender()):null;\nif(ro)ro.observe(stageWrap);\nwindow.addEventListener('resize',requestRender);\nwindow.addEventListener('orientationchange',()=\u0026gt;setTimeout(requestRender,120));\nif(window.visualViewport)window.visualViewport.addEventListener('resize',requestRender);\n\ndocument.getElementById('resetModel').addEventListener('click',()=\u0026gt;{\n Object.assign(state,defaults);\n allSpecs().forEach(s=\u0026gt;sync(s.key));\n updateWallUI();updateColumnPlacementUI();setView('iso');rebuildScene();flash('Medidas restablecidas');\n});\n\ndocument.getElementById('saveImage').addEventListener('click',()=\u0026gt;{\n render();\n const ratio=Math.min(window.devicePixelRatio||1,2),footer=86*ratio,pad=30*ratio;\n const out=document.createElement('canvas');out.width=canvas.width;out.height=canvas.height+footer;\n const c=out.getContext('2d');c.fillStyle='#fff';c.fillRect(0,0,out.width,out.height);c.drawImage(canvas,0,0);\n c.fillStyle='#fff';c.fillRect(0,canvas.height,out.width,footer);\n c.fillStyle='#8b5e34';c.font=`700 ${17*ratio}px Arial`;\n c.fillText(`Propuesta visual \u00b7 ${installName()}`,pad,canvas.height+29*ratio);\n c.fillStyle='#665c53';c.font=`${12*ratio}px Arial`;\n c.fillText(`${(state.length\/1000).toFixed(2)} m largo \u00d7 ${(state.width\/1000).toFixed(2)} m ancho \u00b7 altura ${(state.height\/1000).toFixed(2)} m \u00b7 ${state.joists} viguetas \u00b7 ${state.columns} columnas`,pad,canvas.height+54*ratio);\n try{\n const a=document.createElement('a');a.download=`pergola-3d-${new Date().toISOString().slice(0,10)}.png`;a.href=out.toDataURL('image\/png');a.click();flash('Imagen guardada');\n }catch(_){flash('No se pudo guardar en este navegador');}\n});\n\nlet timer;\nfunction flash(t){\n const e=document.getElementById('status');e.textContent=t;e.style.display='block';clearTimeout(timer);timer=setTimeout(()=\u0026gt;e.style.display='none',1700);\n}\n\nupdateWallUI();\nupdateColumnPlacementUI();\nrebuildScene();\nsetView('iso');\nrequestAnimationFrame(()=\u0026gt;requestAnimationFrame(()=\u0026gt;{rebuildScene();requestRender();}));\nsetTimeout(requestRender,250);\n})();\n\u0026lt;\/script\u0026gt;\n\u0026lt;\/body\u0026gt;\n\u0026lt;\/html\u0026gt;","render_as_iframe":false,"selected_app_name":"HtmlApp","app_list":"{\"HtmlApp\":9333797}"}}}],"title":"Simulador 3D","uid":"e55f0baa-d3de-4446-b9b3-bc3b7e49358d","path":"\/simulador-3d","autoPath":true,"authorized":true}],"menu":{"type":"Menu","id":"f_a2a8e5fc-1aa2-430f-80b1-775f972d618f","defaultValue":null,"template_name":"navbar","logo":null,"components":{"image1":{"type":"Image","id":"bd41e443-ea47-46a4-8cc2-9a0a7a3b291d","defaultValue":true,"link_url":"https:\/\/www.creativvo.mx\/","thumb_url":"!","url":"!","caption":"","description":"","storageKey":"7829410\/510188_39069","storage":"s","storagePrefix":null,"format":"png","border_radius":null,"aspect_ratio":null,"h":300,"w":1080,"s":38969,"new_target":false,"noCompression":true,"focus":null},"image2":{"type":"Image","id":"f_04c902e2-9e5c-4037-b715-1eed89c3b78f","defaultValue":true,"link_url":"","thumb_url":"\/images\/icons\/transparent.png","url":"\/images\/icons\/transparent.png","caption":"","description":"","storageKey":null,"storage":null,"storagePrefix":null,"format":null,"h":null,"w":null,"s":null,"new_target":true,"noCompression":null,"cropMode":null,"focus":{}},"text1":{"type":"RichText","id":"f_654173b3-cd1e-4cf9-82bf-b6794301e142","defaultValue":false,"alignment":null,"value":"","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":null},"defaultDataProcessed":true},"background1":{"type":"Background","id":"f_8ae7161d-ac4d-439d-b7f5-6aab8f91003a","defaultValue":true,"url":"\/assets\/themes\/profile\/bg.jpg","textColor":"light","backgroundVariation":"","sizing":"cover","userClassName":null,"linkUrl":null,"linkTarget":null,"videoUrl":null,"videoHtml":null,"storageKey":null,"storage":null,"format":null,"h":null,"w":null,"s":null,"useImage":null,"noCompression":null,"focus":{}},"text2":{"type":"RichText","id":"f_7dc59986-9eed-4932-85d3-183a2aba463e","defaultValue":true,"value":"Subtitle Text","backupValue":null,"version":null},"button1":{"type":"Button","id":"f_809c18ad-fe1d-405f-9738-4217e4a4cd17","defaultValue":false,"alignment":"center","text":"Agendar una demostraci\u00f3n","link_type":"Web","page_id":null,"section_id":null,"size":"small","mobile_size":"automatic","style":"solid","color":"","font":"Montserrat","url":"https:\/\/www.creativvo.com.mx\/programar-llamada","new_target":false,"backgroundSettings":{"default":"#00acee","preIndex":null,"type":"default","id":"f_749080dd-7af9-4d75-b7db-59850f8c75fb"}},"image3":{"type":"Image","id":"f5ebb380-1c3e-45a9-8ecc-e472ac57b30f","defaultValue":true,"link_url":"","thumb_url":"!","url":"!","caption":"","description":"","storageKey":"7829410\/413570_215982","storage":"s","storagePrefix":null,"format":"png","h":150,"w":300,"s":739327,"new_target":true,"noCompression":true,"focus":null}}},"footer":{"type":"Footer","id":"f_027e0664-4457-4c60-85c1-3ce4d408a11c","defaultValue":false,"socialMedia":null,"copyright":null,"components":{"background1":{"type":"Background","id":"f_0defc920-8588-40c0-9d90-3d6b2cb1e671","defaultValue":false,"url":"","textColor":"","backgroundVariation":"","sizing":"","userClassName":"","linkUrl":null,"linkTarget":null,"videoUrl":"","videoHtml":"","storageKey":null,"storage":null,"format":null,"h":null,"w":null,"s":null,"useImage":false,"noCompression":null,"focus":null,"backgroundColor":{"themeColorRangeIndex":null,"value":"#FFFFFF","type":null},"useSameBg":true,"backgroundApplySettings":{}},"text1":{"type":"RichText","id":"f_3cc97805-c3e8-4f0f-af5e-146a4a0746c1","defaultValue":false,"value":"\u003cdiv class=\"s-rich-text-wrapper\" style=\"display: block; \"\u003e\u003cp class=\" s-rich-text-wrapper\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003cstrong\u003eEmpresa\u003c\/strong\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\"\u003e\u003cspan style=\"display: inline-block\"\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"http:\/\/www.creativvo.mx\/nosotros\" data-type=\"\" target=\"_blank\"\u003eSobre nosotros\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"http:\/\/www.creativvo.mx\/como-funciona\" data-type=\"\" target=\"_blank\"\u003eC\u00f3mo funciona\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/api.whatsapp.com\/send?phone=526645792792\" data-type=\"\" target=\"_blank\"\u003eCont\u00e1ctanos\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.com.mx\/programar-llamada\" data-type=\"undefined\" target=\"_blank\"\u003eAgenda una\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.com.mx\/programar-llamada\" data-type=\"undefined\" target=\"_blank\"\u003edemostraci\u00f3n\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003c\/div\u003e","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":"left"},"defaultDataProcessed":true},"text2":{"type":"RichText","id":"f_0316ed58-c88f-4410-95a3-69dc2c92e8f3","defaultValue":false,"alignment":null,"value":"\u003cdiv class=\"s-rich-text-wrapper\" style=\"display: block; \"\u003e\u003cp class=\" #(className) s-rich-text-wrapper\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003cstrong\u003eServicios\u003c\/strong\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" #(className) s-rich-text-wrapper\"\u003e\u003cspan style=\"display: inline-block\"\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.mx\/voiceover\" data-type=\"\" target=\"_blank\"\u003eVoiceOver\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.mx\/copywriting\" data-type=\"\" target=\"_blank\"\u003eCopywriting\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.mx\/contenido-digital\" data-type=\"\" target=\"_blank\"\u003eContenido digital\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.mx\/anuncios\" data-type=\"\" target=\"_blank\"\u003eAnuncios\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" #(className) s-rich-text-wrapper\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"https:\/\/www.creativvo.mx\/paginas-web\" data-type=\"\" target=\"_blank\"\u003eP\u00e1ginas web\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003c\/div\u003e","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":null},"defaultDataProcessed":true},"text3":{"type":"RichText","id":"f_8f372bd1-beb8-4d6c-9395-ddc137f955aa","defaultValue":false,"value":"\u003cdiv class=\"s-rich-text-wrapper\" style=\"display: block; \"\u003e\u003cp class=\" s-rich-text-wrapper\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003cstrong\u003eRecursos\u003c\/strong\u003e\u003c\/span\u003e\u003cspan style=\"color: #50555c;\"\u003e \u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" s-rich-text-wrapper\"\u003e\u003cspan style=\"display: inline-block\"\u003e\u003c\/span\u003e\u003c\/p\u003e\u003cp class=\" #(className) s-rich-text-wrapper\" style=\"text-align: left; font-size: 16px;\"\u003e\u003cspan style=\"color: #383838;\"\u003e\u003ca style=\"color: #383838;\" href=\"http:\/\/www.creativvo.mx\/blog\" data-type=\"\" target=\"_blank\"\u003eBlog\u003c\/a\u003e\u003c\/span\u003e\u003c\/p\u003e\u003c\/div\u003e","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":null,"lastLineTextAlign":"left"},"defaultDataProcessed":true},"text4":{"type":"RichText","id":"f_5818b519-ea5d-4d20-82e0-55352ed04f6a","defaultValue":false,"alignment":null,"value":"\u003cp\u003e\u003cstrong\u003eSuscr\u00edbete a nuestro bolet\u00edn\u003c\/strong\u003e\u003c\/p\u003e","backupValue":null,"version":1},"copyright":{"type":"RichText","id":"f_669e8eaf-7e73-44dd-93a4-c50ddb9b215e","defaultValue":false,"value":"\u003cdiv class=\"s-rich-text-wrapper\" style=\"display: block; \"\u003e\u003cp class=\" s-rich-text-wrapper font-size-tag-custom s-text-font-size-over-default\" style=\"text-align: left; font-size: 12px;\"\u003e \u003cspan style=\"color: #0e001a;\"\u003e\u00a9 2025 Todos los derechos reservados, Creativvo\u003c\/span\u003e\u003cspan style=\"color: #0e001a;\"\u003e\u003csup\u003e\u00ae\u003c\/sup\u003e\u003c\/span\u003e\u003c\/p\u003e\u003c\/div\u003e","backupValue":null,"version":1,"lineAlignment":{"firstLineTextAlign":"left","lastLineTextAlign":"left"},"defaultDataProcessed":true},"email1":{"type":"EmailForm","id":"f_cbec063d-ee2c-4831-b4ef-112045290d48","defaultValue":null,"hideMessageBox":false,"hide_name":false,"hide_email":false,"hide_phone_number":true,"name_label":"Nombre","email_label":"Email","phone_number_label":"Tel\u00e9fono","message_label":"Message","submit_label":"Suscr\u00edbete","thanksMessage":"\u00a1Gracias por tu env\u00edo!","recipient":"","label":null},"image1":{"type":"Image","id":"f_e7142fbe-2ac0-4dbf-b9f6-04668b1e4a9b","defaultValue":true,"link_url":"","thumb_url":"!","url":"!","caption":"","description":"","storageKey":"7829410\/59958_287354","storage":"s","storagePrefix":null,"format":"png","border_radius":null,"aspect_ratio":null,"h":300,"w":300,"s":60180,"new_target":true,"noCompression":null,"cropMode":null,"focus":null},"socialMedia":{"type":"SocialMediaList","id":"f_64dff20e-ab66-4242-aa84-7b8367b47566","defaultValue":false,"link_list":[{"type":"SocialMediaItem","id":"871e3430-225a-11f0-9521-05f7782e3234","url":"https:\/\/www.facebook.com\/SomosCreativvo","className":"fab fa-facebook-f","show_button":true},{"type":"SocialMediaItem","id":"acf6ecb0-225a-11f0-9521-05f7782e3234","url":"https:\/\/www.instagram.com\/_creativvo_\/","className":"fab fa-instagram","show_button":true}],"button_list":[{"type":"Facebook","id":"f_27d2f361-29c9-4565-aa1b-035d3c044712","defaultValue":null,"url":"","link_url":"","share_text":"","show_button":true,"app_id":543870062356274},{"type":"Twitter","id":"f_bd6c5b6f-7f93-41eb-abf1-bb1051de4773","defaultValue":null,"url":"","link_url":"","share_text":"","show_button":true},{"type":"LinkedIn","id":"f_dc1dea16-ee5b-4a54-b96a-d0ecb6af7edf","defaultValue":null,"url":"","link_url":"","share_text":"","show_button":false},{"type":"Pinterest","id":"f_94ed8e4c-62c3-4f55-bcae-d07c781ca7a4","defaultValue":null,"url":"","link_url":null,"share_text":null,"show_button":false}],"contact_list":[{"type":"SocialMediaPhone","id":"4f0fd90e-041f-11ee-8ab3-296018cf2373","defaultValue":"","className":"fas fa-phone-alt"},{"type":"SocialMediaEmail","id":"4f0fd90f-041f-11ee-8ab3-296018cf2373","defaultValue":"hola@creativvo.com.mx","className":"fas fa-envelope"}],"list_type":"link"}},"layout_variation":"grid","padding":{}},"submenu":{"type":"SubMenu","id":"f_37ccca79-01d4-4974-a695-7f7b82a1eaf7","defaultValue":null,"list":[],"components":{"link":{"type":"Button","id":"f_000de008-d04d-40c5-ace8-332c32feb7d4","defaultValue":null,"text":"Facebook","link_type":null,"page_id":null,"section_id":null,"url":"http:\/\/www.facebook.com","new_target":true}}},"customColors":{"type":"CustomColors","id":"f_10d2a659-0c72-4ba7-94c3-c1db65e8f871","active":true,"highlight1":"#060606","highlight2":"#00acee"},"animations":{"type":"Animations","id":"f_1e864d09-1899-4c92-98b3-d7c80ca2377e","defaultValue":null,"page_scroll":"slide_in","background":"none","image_link_hover":"zoom_in"},"s5Theme":{"type":"Theme","id":"f_247e5d2c-d437-4993-a487-1c633cb2e339","defaultValue":null,"version":"11","nav":{"type":"NavTheme","id":"f_a7eefaef-c78a-4fe1-925d-f515062961c4","defaultValue":null,"name":"topBar","layout":"c","padding":"small","sidebarWidth":"medium","topContentWidth":"full","horizontalContentAlignment":"center","verticalContentAlignment":"middle","fontSize":"medium","backgroundColor1":"#fff","highlightColor":null,"presetColorName":"whiteMinimal","itemColor":"#000","itemSpacing":"large","dropShadow":"no","socialMediaListType":"link","isTransparent":false,"isSticky":true,"keptOldLayout":false,"showSocialMedia":false,"highlight":{"blockBackgroundColor":null,"blockTextColor":null,"blockBackgroundColorSettings":{"id":"2fc56573-c010-491b-a8b6-d2591bcd1e7f","default":"#6b6b6b","preIndex":null,"type":"custom"},"blockTextColorSettings":{"id":"873b3b4a-b3b9-4be7-97a0-15462631dbc4","default":"#ffffff","preIndex":null,"type":"custom"},"blockShape":"pill","textColor":"#00acf0","textColorSettings":{"id":"fff52bf5-7048-474b-97af-d61ab8fb7a21","default":"#6b6b6b","preIndex":7,"type":"pre-color"},"type":"color","id":"f_abbbf7ac-d504-4009-b31e-6fba0a97e77f"},"border":{"enable":true,"borderColor":"#000000","position":"bottom","thickness":"small","borderColorSettings":{"preIndex":null,"type":"custom","default":"#ffffff","id":"f_3b66a4e6-e481-4906-8cc8-00b72ac8d4c8"}},"layoutsVersionStatus":{"a":{"status":"done","from":"v1","to":"v2","currentVersion":"v2"},"b":{"status":"done","from":"v1","to":"v2","currentVersion":"v2"},"g":{"status":"done","from":"v1","to":"v2","currentVersion":"v2"}},"socialMedia":[{"type":"SocialMediaItem","id":"871e3430-225a-11f0-9521-05f7782e3234","url":"https:\/\/www.facebook.com\/SomosCreativvo","className":"fab fa-facebook-f","show_button":true},{"type":"SocialMediaItem","id":"acf6ecb0-225a-11f0-9521-05f7782e3234","url":"https:\/\/www.instagram.com\/_creativvo_\/","className":"fab fa-instagram","show_button":true}],"socialMediaButtonList":[{"type":"Facebook","id":"4f0fd908-041f-11ee-8ab3-296018cf2373","url":"","link_url":"","share_text":"","show_button":false},{"type":"Twitter","id":"4f0fd909-041f-11ee-8ab3-296018cf2373","url":"","link_url":"","share_text":"","show_button":false},{"type":"LinkedIn","id":"4f0fd90a-041f-11ee-8ab3-296018cf2373","url":"","link_url":"","share_text":"","show_button":false},{"type":"Pinterest","id":"4f0fd90b-041f-11ee-8ab3-296018cf2373","url":"","link_url":"","share_text":"","show_button":false}],"socialMediaContactList":[{"type":"SocialMediaPhone","id":"4f0fd90e-041f-11ee-8ab3-296018cf2373","defaultValue":"","className":"fas fa-phone-alt"},{"type":"SocialMediaEmail","id":"4f0fd90f-041f-11ee-8ab3-296018cf2373","defaultValue":"hola@creativvo.com.mx","className":"fas fa-envelope"}],"backgroundColorSettings":{"id":"f8addda6-c021-4f55-8c0b-b325534dc38b","default":"#ffffff","preIndex":null,"type":"default"},"highlightColorSettings":{"id":"b8c17469-d12f-4bb8-a949-d0204bc34ca5","default":"#6b6b6b","preIndex":null,"type":"custom"},"itemColorSettings":{"id":"ca3bb206-0d02-4642-8595-f68239e29b41","default":"#000000","preIndex":null,"type":"default"}},"section":{"type":"SectionTheme","id":"f_4fc6197e-5182-4a82-a157-ca9ae223252b","defaultValue":null,"padding":"normal","contentWidth":"normal","contentAlignment":"center","baseFontSize":16,"titleFontSize":24,"subtitleFontSize":18,"itemTitleFontSize":24,"itemSubtitleFontSize":16,"textHighlightColor":null,"baseColor":"#50555c","titleColor":"#0d0d0d","subtitleColor":"#060606","itemTitleColor":"#0d0d0d","itemSubtitleColor":"#00acf0","textHighlightSelection":{"type":"TextHighlightSelection","id":"f_100266f9-faa6-4a20-8290-809532d31c19","defaultValue":null,"title":false,"subtitle":true,"itemTitle":false,"itemSubtitle":true},"base":{"preIndex":null,"type":"default","default":"#50555c","id":"f_2f1c2b11-88e9-40c5-b9ee-a3b469ffbdde"},"title":{"preIndex":0,"type":"pre-color","default":"#1D2023","id":"f_d72ac34a-f5cd-4731-a4f2-697024f5bb97"},"subtitle":{"preIndex":null,"type":"default","default":"#060606","id":"f_9fbe5aa6-7f11-4209-bcc2-d250edf2c467"},"itemTitle":{"preIndex":0,"type":"pre-color","default":"#1D2023","id":"f_88544b35-696c-4e9b-a825-04af675b3aa7"},"itemSubtitle":{"preIndex":7,"type":"pre-color","default":"#060606","id":"f_65e959c4-7d58-4ff0-bbf2-b6ecb95c8877"}},"firstSection":{"type":"FirstSectionTheme","id":"f_9f9203be-cabb-4145-b07c-4de2ccc75783","defaultValue":null,"height":"normal","shape":"none"},"button":{"type":"ButtonTheme","id":"f_78383a89-ed4d-4cda-9d68-f5c72825706d","defaultValue":null,"backgroundColor":"#060606","shape":"rounded","fill":"solid","backgroundSettings":{"preIndex":null,"type":"default","default":"#060606","id":"f_4a938243-195a-453f-a6d4-85c620c5b7b6"}}},"navigation":{"items":[{"id":"6cc5a773-71ec-4e41-af7d-ae4fdae06edf","type":"page","visibility":false},{"type":"dropdown","title":"Servicios","id":"1aac21d1-7463-4e98-a03a-3198304c95ad","items":[{"id":"f661f254-cf78-418e-9cc3-1ffdfc3ac284","type":"page","visibility":true},{"id":"858ead57-5db6-4c49-845b-204e9ebd56ae","type":"page","visibility":true},{"id":"abd77f5b-30f7-4673-99b8-30d962a8aa12","type":"page","visibility":true},{"id":"b699141f-ca35-44ae-a3df-7da2f0f30d28","type":"page","visibility":true},{"id":"645a4112-6a00-4c13-b23b-29898ea6690f","type":"page","visibility":true}]},{"id":"7f8ecc9d-9908-48d8-bfec-773dc8f0543e","type":"page","visibility":true},{"id":"4f3fe031-ee60-4c43-8b7d-0821b36c4308","type":"page","visibility":false},{"id":"fef03dff-7ee8-425e-b955-d107b07c2c21","type":"page","visibility":false},{"id":"6e8bc220-3a45-42bc-badb-993b8776c606","type":"page","visibility":false},{"id":"b73f936e-6350-49bb-a5ff-4699878d6e50","type":"page","visibility":false},{"id":"73e66e19-9c1a-4499-9aec-37154100be5d","type":"page","visibility":false},{"id":"5f81ba6f-090d-451a-b324-4b326b94509e","type":"page","visibility":false},{"id":"d02610a5-d7bf-45b1-a27e-f18c7767f69f","type":"page","visibility":false},{"id":"cf1f36aa-cced-4c95-8466-8df338b07dff","type":"page","visibility":false},{"id":"ada00f97-4e48-45c7-bf68-69d6dd866063","type":"page","visibility":false},{"id":"80cb04ec-dde8-4640-b68f-a162a09112f2","type":"page","visibility":false},{"id":"fd9a9c4e-f6c7-49c8-bf9b-b385d9045ccf","type":"page","visibility":false},{"id":"3bd130c9-5808-4193-84a0-ba67988e035e","type":"page","visibility":false},{"id":"267bab57-d786-4f06-a9b1-9291653ffb6b","type":"page","visibility":false},{"id":"95d58ea4-cb9e-4b46-9ddd-53b775dd7152","type":"page","visibility":false},{"id":"b7473e81-e8d1-464c-bb04-ba13937a8bb4","type":"page","visibility":false},{"id":"4efdf67c-71b6-4c14-ab47-230dade9a4b2","type":"page","visibility":false},{"id":"e580453a-ead7-47b8-93b2-8ab14ed004ec","type":"page","visibility":false},{"id":"36cc2b18-73e2-43db-a3ac-ede97bf69a74","type":"page","visibility":false},{"id":"e9f50f2c-90e9-4d9a-8e0d-2e68844a3ec9","type":"page","visibility":false},{"id":"ea030c78-30a8-4d08-ab10-056f5e0cf3e7","type":"page","visibility":false},{"id":"49df11d7-abde-4370-ac91-75883f60e577","type":"page","visibility":false},{"id":"86c9ff98-569f-4645-b930-5b4059bd19f1","type":"page","visibility":true},{"id":"fcba79f7-0b22-4980-b6c9-2e59688bce44","type":"page","visibility":true},{"id":"e55f0baa-d3de-4446-b9b3-bc3b7e49358d","type":"page","visibility":true}],"links":[]},"migrateFeatures":{"migratedRtlFeatureListE":true,"migratedRtlBlogImageAlignment":true,"migratedRtlSlider":true,"migratedS6SectionPadding":false,"migrateS6SectionContentPosition":false}}};$S.siteData={"terms_text":"\u00daltima revisi\u00f3n: 22 de mayo de 2024\n\nEl presente documento establece los t\u00e9rminos y condiciones generales del uso (\u201cT\u00e9rminos y Condiciones Generales\u201d) que ser\u00e1n aplicables cuando usted visite el Sitio Web https:\/\/www.creativvo.mx\/ (en adelante, de manera conjunta \u201cEl sitio\u201d), cuyas titularidades y contenido son de total autor\u00eda de JORGE RIVERA ESPINOSA (\u201cCREATIVVO\u201d), establecido como persona f\u00edsica cono actividad empresarial con RFC RIEJ9011015D4.\n\nAceptaci\u00f3n de las condiciones\nCREATIVVO ha puesto a su disposici\u00f3n el sitio web, por lo que, al acceder a el, usted debe de leer, comprender y aceptar estos t\u00e9rminos y condiciones (las \u201cCondiciones\u201d) Asimismo, queda sujeto a estas Condiciones que, junto con nuestras Pol\u00edticas de Privacidad, rigen nuestra relaci\u00f3n con usted dentro de la Plataforma. Solo podr\u00e1 registrarse y ser Usuario de la Plataforma, despu\u00e9s de haber aceptado las Condiciones, en caso de no aceptarlos, se le solicita que no haga uso, ni acceda, ni manipule la informaci\u00f3n de los Servicios ofrecidos por la Plataforma, ya que usted estar\u00eda haciendo un uso inadecuado de \u00e9sta.","privacy_policy_text":"Avisos de privacidad \n\u00daltima revisi\u00f3n: 22 de mayo de 2024\n\nEn cumplimiento a la Ley Federal de Protecci\u00f3n de Datos Personales en Posesi\u00f3n de los Particulares (la \u201cLey\u201d), JORGE RIVERA ESPINOSA (CREATIVVO), protege y salvaguarda sus datos personales para evitar el da\u00f1o, p\u00e9rdida, destrucci\u00f3n, robo, extrav\u00edo, alteraci\u00f3n, as\u00ed como el tratamiento no autorizado de los mismos. A continuaci\u00f3n, hacemos de su conocimiento los t\u00e9rminos y condiciones del Aviso de Privacidad de Datos Personales (\u201cAviso de Privacidad\u201d) de CREATIVVO.\n\n\u00bfQu\u00e9 informaci\u00f3n recopilamos?\n\nLos datos que usted libre y voluntariamente proporcione a CREATIVVO, mediante nuestros servicios, en l\u00ednea, por escrito, v\u00eda telef\u00f3nica y\/o por otros medios distintos, podr\u00e1n incluir de manera enunciativa m\u00e1s no limitativa: (i) datos personales, (ii) datos laborales, y (iii) datos patrimoniales y financieros. Asimismo, y s\u00f3lo en caso de ser aplicable, podremos recabar a trav\u00e9s de la informaci\u00f3n que usted nos proporcione, algunos datos personales en general y datos laborales seg\u00fan corresponda, de terceros como sus hijos, c\u00f3nyuge, tarjetahabientes adicionales que usted designe, as\u00ed como del obligado solidario (de requerirse seg\u00fan nuestras pol\u00edticas de cr\u00e9dito), as\u00ed como referencias personales para fines de consulta y verificaci\u00f3n de sus datos por parte de CREATIVVO. Para cerciorarse de que los datos personales que usted libremente proporciona son correctos y actuales, CREATIVVO podr\u00e1 recopilar informaci\u00f3n de otras fuentes como lo son sociedades de informaci\u00f3n crediticia. Igualmente, y de acuerdo con las pol\u00edticas de cr\u00e9dito de CREATIVVO, podremos requerirle copia de su identificaci\u00f3n oficial con fotograf\u00eda y comprobante de su domicilio. Trat\u00e1ndose de los terceros cuyos datos personales recopilamos a trav\u00e9s de usted, igualmente tomamos las medidas de seguridad y de confidencialidad para el tratamiento de su informaci\u00f3n, de conformidad con los t\u00e9rminos y condiciones en este Aviso de Privacidad. Usted manifiesta su conocimiento expreso a que sus datos personales sean tratados de acuerdo con los t\u00e9rminos y condiciones de este Aviso de Privacidad.\n\n\u00bfPara qu\u00e9 utilizamos su informaci\u00f3n?\n\nLos datos personales que recopilamos los destinamos de manera enunciativa mas no limitativa para los siguientes prop\u00f3sitos: (i) fines de identificaci\u00f3n y verificaci\u00f3n, (ii) contacto, (iii) ofrecerle y entregarle nuestros bienes y servicios, (iv) identificar historial de compras, y otros fines an\u00e1logos, (v) mejorar y actualizar nuestros servicios, (vi) procesar las solicitudes y los pedidos de cursos, productos, servicios espec\u00edficos, informaci\u00f3n o funciones que realiza el usuario, (vii) comunicarnos con el usuario y generar preferencias de cuenta. En la recolecci\u00f3n y tratamiento de datos personales que usted nos proporcione, cumplimos todos los principios que marca la Ley (art\u00edculo 6): licitud, calidad, consentimiento, informaci\u00f3n, finalidad, lealtad, proporcionalidad y responsabilidad.\n\n\u00bfCon qui\u00e9n compartimos su informaci\u00f3n?\n\nCREATIVVO podr\u00e1 contratar a uno o varios terceros como proveedores de servicios seleccionados para apoyar las actividades de promoci\u00f3n y comercializaci\u00f3n de nuestros bienes y servicios, manejo y administraci\u00f3n de los datos personales que se recaban en l\u00ednea, o por cualquier otro medio distinto, as\u00ed como para fines de verificaci\u00f3n de la informaci\u00f3n que usted nos proporciona, por lo que CREATIVVO podr\u00eda incluso transferirlos a dicho(s) tercero(s) sin un fin comercial, sino \u00fanicamente para cumplir con la prestaci\u00f3n de los servicios contratados. De igual manera CREATIVVO, en ning\u00fan caso comercializar\u00e1, vender\u00e1 o rentar\u00e1 informaci\u00f3n personal sobre usted a un tercero sin un consentimiento previo de su parte. Se entiende que ha otorgado su consentimiento a la transferencia de sus datos personales, si no manifiesta su oposici\u00f3n a que los mismos sean transferidos. Los datos personales que usted proporcione a CREATIVVO, podr\u00e1n compilarse y fijarse en una base de datos propiedad exclusiva de CREATIVVO. Las ligas a sitios externos a nuestro portal no son responsabilidad de DESPEGUE CREATIVO, por lo que no asumimos responsabilidad alguna con respecto al contenido y pol\u00edticas de privacidad en dichos sitios.","show_terms_and_conditions":true,"show_privacy_policy":true,"gdpr_html":null,"live_chat":false};$S.stores={"fonts_v2":[{"name":"open sans","fontType":"google","displayName":"Open Sans","cssValue":"\"open sans\"","settings":{"weight":"300,regular,500,600,700,800,300italic,italic,500italic,600italic,700italic,800italic"},"hidden":false,"cssFallback":"sans-serif","disableBody":false,"isSuggested":false},{"name":"outfit","fontType":"google","displayName":"Outfit","cssValue":"\"outfit\"","settings":{"weight":"100,200,300,regular,500,600,700,800,900"},"hidden":false,"cssFallback":"sans-serif","disableBody":false,"isSuggested":true},{"name":"montserrat","fontType":"google","displayName":"Montserrat","cssValue":"montserrat, helvetica","settings":{"weight":"400,700"},"hidden":false,"cssFallback":"sans-serif","disableBody":null,"isSuggested":true}],"features":{"allFeatures":[{"name":"ecommerce_shipping_region","canBeUsed":true,"hidden":false},{"name":"ecommerce_taxes","canBeUsed":true,"hidden":false},{"name":"ecommerce_category","canBeUsed":true,"hidden":false},{"name":"product_page","canBeUsed":true,"hidden":false},{"name":"ecommerce_free_shipping","canBeUsed":true,"hidden":false},{"name":"ecommerce_custom_product_url","canBeUsed":true,"hidden":false},{"name":"ecommerce_coupon","canBeUsed":true,"hidden":false},{"name":"ecommerce_checkout_form","canBeUsed":true,"hidden":false},{"name":"mobile_actions","canBeUsed":true,"hidden":false},{"name":"ecommerce_layout","canBeUsed":true,"hidden":false},{"name":"portfolio_layout","canBeUsed":true,"hidden":false},{"name":"analytics","canBeUsed":true,"hidden":false},{"name":"fb_image","canBeUsed":true,"hidden":false},{"name":"twitter_card","canBeUsed":true,"hidden":false},{"name":"favicon","canBeUsed":true,"hidden":false},{"name":"style_panel","canBeUsed":true,"hidden":false},{"name":"google_analytics","canBeUsed":true,"hidden":false},{"name":"blog_custom_url","canBeUsed":true,"hidden":false},{"name":"page_collaboration","canBeUsed":true,"hidden":false},{"name":"bookings","canBeUsed":true,"hidden":false},{"name":"membership","canBeUsed":true,"hidden":false},{"name":"social_feed_facebook_page","canBeUsed":true,"hidden":false},{"name":"portfolio_category","canBeUsed":true,"hidden":false},{"name":"premium_templates","canBeUsed":true,"hidden":false},{"name":"custom_domain","canBeUsed":true,"hidden":false},{"name":"premium_support","canBeUsed":true,"hidden":false},{"name":"remove_branding_title","canBeUsed":true,"hidden":false},{"name":"full_analytics","canBeUsed":true,"hidden":false},{"name":"ecommerce_layout","canBeUsed":true,"hidden":false},{"name":"portfolio_layout","canBeUsed":true,"hidden":false},{"name":"ecommerce_digital_download","canBeUsed":true,"hidden":false},{"name":"disable_captcha","canBeUsed":true,"hidden":false},{"name":"password_protection","canBeUsed":true,"hidden":false},{"name":"remove_logo","canBeUsed":true,"hidden":false},{"name":"optimizely","canBeUsed":true,"hidden":false},{"name":"custom_code","canBeUsed":true,"hidden":false},{"name":"blog_custom_code","canBeUsed":true,"hidden":false},{"name":"premium_assets","canBeUsed":true,"hidden":false},{"name":"premium_apps","canBeUsed":true,"hidden":false},{"name":"premium_sections","canBeUsed":true,"hidden":false},{"name":"blog_mailchimp_integration","canBeUsed":true,"hidden":false},{"name":"multiple_page","canBeUsed":true,"hidden":false},{"name":"ecommerce_layout","canBeUsed":true,"hidden":false},{"name":"portfolio_layout","canBeUsed":true,"hidden":false},{"name":"facebook_pixel","canBeUsed":true,"hidden":false},{"name":"blog_category","canBeUsed":true,"hidden":false},{"name":"custom_font","canBeUsed":true,"hidden":false},{"name":"blog_post_amp","canBeUsed":true,"hidden":false},{"name":"site_search","canBeUsed":true,"hidden":false},{"name":"portfolio_category","canBeUsed":true,"hidden":false},{"name":"popup","canBeUsed":true,"hidden":false},{"name":"custom_form","canBeUsed":true,"hidden":false},{"name":"portfolio_custom_product_url","canBeUsed":true,"hidden":false},{"name":"email_automation","canBeUsed":true,"hidden":false},{"name":"blog_password_protection","canBeUsed":true,"hidden":false},{"name":"custom_ads","canBeUsed":true,"hidden":false},{"name":"portfolio_form_custom_fields","canBeUsed":true,"hidden":false},{"name":"live_chat","canBeUsed":true,"hidden":false},{"name":"auto_translation","canBeUsed":true,"hidden":false},{"name":"membership_tier","canBeUsed":true,"hidden":false},{"name":"redirect_options","canBeUsed":true,"hidden":false},{"name":"portfolio_region_options","canBeUsed":true,"hidden":false},{"name":"require_contact_info_view_portfolio","canBeUsed":true,"hidden":false},{"name":"ecommerce_product_add_on_categories","canBeUsed":true,"hidden":false}]},"showStatic":{"footerLogoSeoData":{"anchor_link":"https:\/\/www.strikingly.com\/?ref=logo\u0026permalink=vermilion-kangaroo-9jtvvh\u0026custom_domain=www.voicyn.mx\u0026utm_campaign=footer_pbs\u0026utm_content=https%3A%2F%2Fwww.voicyn.mx%2F\u0026utm_medium=user_page\u0026utm_source=7829410\u0026utm_term=pbs_b","anchor_text":"Free website builder"},"isEditMode":false},"ecommerceProductCollection":{"data":{"paginationMeta":{"currentPage":1,"previousPage":null,"nextPage":null,"perPage":20,"totalPages":1,"totalCount":5},"products":[{"id":11725490,"name":"VoiceOver 250 palabras","description":"","picture":[],"detailEnabled":false,"dimensions":null,"status":"visible","productType":"service","enableCustomSlug":false,"customSlug":null,"enabled":true,"sortWeight":{"all":900,"no":900},"ctaBtn":null,"shippingInfo":false,"estimatedDelivery":"","timedShelfDate":null,"posId":null,"isWeightToAll":true,"weightToAll":0,"startDate":null,"endDate":null,"categoryIds":[],"categories":[],"slugPath":"\/store\/products\/voiceover-250-palabras","realSales":0,"originalSales":0,"variations":[{"id":8933806,"name":"default","price":200000,"quantity":-1,"originalPrice":-1,"picture":null,"weight":0.0,"sortNumber":0,"cost":0}],"reviewsScore":0,"reviewsCount":0},{"id":11725419,"name":"VoiceOver 200 palabras","description":"","picture":[],"detailEnabled":false,"dimensions":null,"status":"visible","productType":"service","enableCustomSlug":false,"customSlug":null,"enabled":true,"sortWeight":{"all":800,"no":800},"ctaBtn":null,"shippingInfo":false,"estimatedDelivery":"","timedShelfDate":null,"posId":null,"isWeightToAll":true,"weightToAll":0,"startDate":null,"endDate":null,"categoryIds":[],"categories":[],"slugPath":"\/store\/products\/voiceover-200-palabras","realSales":0,"originalSales":0,"variations":[{"id":8933782,"name":"default","price":160000,"quantity":-1,"originalPrice":-1,"picture":null,"weight":0.0,"sortNumber":0,"cost":0}],"reviewsScore":0,"reviewsCount":0},{"id":11725415,"name":"VoiceOver 150 palabras","description":"","picture":[],"detailEnabled":false,"dimensions":null,"status":"visible","productType":"service","enableCustomSlug":false,"customSlug":null,"enabled":true,"sortWeight":{"all":700,"no":700},"ctaBtn":null,"shippingInfo":false,"estimatedDelivery":"","timedShelfDate":null,"posId":null,"isWeightToAll":true,"weightToAll":0,"startDate":null,"endDate":null,"categoryIds":[],"categories":[],"slugPath":"\/store\/products\/voiceover-150-palabras","realSales":0,"originalSales":0,"variations":[{"id":8933780,"name":"default","price":120000,"quantity":-1,"originalPrice":-1,"picture":null,"weight":0.0,"sortNumber":0,"cost":0}],"reviewsScore":0,"reviewsCount":0},{"id":11725411,"name":"VoiceOver 100 palabras","description":"","picture":[],"detailEnabled":false,"dimensions":null,"status":"visible","productType":"service","enableCustomSlug":false,"customSlug":null,"enabled":true,"sortWeight":{"all":600,"no":600},"ctaBtn":null,"shippingInfo":false,"estimatedDelivery":"","timedShelfDate":null,"posId":null,"isWeightToAll":true,"weightToAll":0,"startDate":null,"endDate":null,"categoryIds":[],"categories":[],"slugPath":"\/store\/products\/voiceover-100-palabras","realSales":0,"originalSales":0,"variations":[{"id":8933778,"name":"default","price":80000,"quantity":-1,"originalPrice":-1,"picture":null,"weight":0.0,"sortNumber":0,"cost":0}],"reviewsScore":0,"reviewsCount":0},{"id":11725410,"name":"VoiceOver 50 palabras","description":"","picture":[],"detailEnabled":false,"dimensions":null,"status":"visible","productType":"service","enableCustomSlug":false,"customSlug":null,"enabled":true,"sortWeight":{"all":500,"no":500},"ctaBtn":null,"shippingInfo":false,"estimatedDelivery":"","timedShelfDate":null,"posId":null,"isWeightToAll":true,"weightToAll":0,"startDate":null,"endDate":null,"categoryIds":[],"categories":[],"slugPath":"\/store\/products\/voiceover-50-palabras","realSales":0,"originalSales":0,"variations":[{"id":8933777,"name":"default","price":40000,"quantity":-1,"originalPrice":-1,"picture":null,"weight":0.0,"sortNumber":0,"cost":0}],"reviewsScore":0,"reviewsCount":0}]}},"ecommerceProductOrderList":{},"ecommerceCategoryCollection":null,"hasEcommerceProducts":true,"portfolioCategoryCollection":null,"hasPortfolioProducts":false,"blogCategoryCollection":{},"hasBlogs":true};$S.liveBlog=true;