Vásquez Pérez Abogados
Academia Legal
Bienvenido de vuelta
Accede a tu perfil de Academia Legal.
¿Sin cuenta? Regístrate gratis
Academia Legal
0% leído
Procedimiento sancionatorio contractual Colombia
Academia Legal
Derecho de la Infraestructura

13 claves del procedimiento sancionatorio contractual

15 de enero de 2025
13
Claves
8 min
Lectura
2025
Publicado
Juan Simón Vásquez Pérez
Juan Simón Vásquez Pérez
Socio · Vásquez Pérez Abogados
Análisis · 8 min
¿No eres abogado?
Tenemos una versión más clara para ti.
Escuchar
Voz femenina · Accesibilidad

Las audiencias de declaratoria de incumplimiento y el debido proceso sancionatorio contractual representan retos jurídicos frecuentes en la ejecución de contratos estatales. Aquí están las 13 claves que todo contratista o entidad debe conocer para navegar este escenario con claridad y estrategia.

① Inicio del proceso — Claves 1 a 3
② Audiencias — Claves 4 a 7
③ Decisión — Claves 8 a 11
④ Recursos — Claves 12 y 13
1

Debido proceso matizado

El debido proceso en sede administrativa contractual no es idéntico al penal, pero exige un núcleo esencial: comunicación previa de los cargos, oportunidad real de defensa y decisión motivada. El Consejo de Estado ha consolidado la tesis del "debido proceso matizado": garantías plenas en sus elementos esenciales, pero adaptadas a la naturaleza administrativa del trámite.

2

El supervisor no es parte

El supervisor o interventor puede emitir concepto técnico, pero no ostenta la calidad de parte en la audiencia. Su informe puede controvertirse. El contratista tiene derecho pleno a objetar sus apreciaciones. La entidad, y no el supervisor, es quien toma la decisión final.

3

Carácter oral del procedimiento

La audiencia es eminentemente oral. Los argumentos de defensa, las pruebas y las decisiones deben constar en el acta de la diligencia. La entidad no puede reemplazar la audiencia con un acto administrativo escrito que prescinda de este trámite: eso vicia de nulidad la actuación.

4

Audiencia concentrada

La ley favorece el trámite en una sola sesión. El contratista debe presentar sus descargos en esa oportunidad. La fragmentación injustificada puede afectar la validez del procedimiento. Si se suspende, debe existir motivo válido que quede registrado en el acta.

5

La citación define el objeto

Los hechos señalados en el oficio de citación delimitan el objeto del procedimiento. La entidad no puede sancionar por conductas distintas a las comunicadas previamente. Ampliar el objeto durante la audiencia sin nueva comunicación viola el principio de congruencia y el derecho de defensa.

6

Principio de tipicidad

Solo puede sancionarse la conducta expresamente prevista en el contrato, el pliego o la ley como incumplimiento sancionable. Las conductas atípicas no pueden fundamentar sanciones. La tipicidad en materia contractual estatal, aunque más flexible que en derecho penal, sigue siendo un límite real al poder sancionatorio de la entidad.

7

Trascendencia del incumplimiento

El Consejo de Estado exige que el incumplimiento afecte real y materialmente la ejecución del contrato o su objeto. Los incumplimientos formales o irrelevantes no justifican sanciones. La entidad debe acreditar que la conducta tuvo impacto concreto y no fue meramente formal.

8

Prueba flexible pero controlada

Cualquier medio probatorio idóneo es admisible, pero la entidad no puede fundar su decisión exclusivamente en el informe del supervisor sin sustento adicional. El contratista puede aportar pruebas documentales, testimoniales y periciales. La valoración debe ser razonada y constar en la motivación del acto.

9

Naturaleza administrativa, no jurisdiccional

La decisión es un acto administrativo susceptible de recurso de reposición ante la misma entidad y de control judicial ante la jurisdicción contencioso-administrativa. La audiencia no es la última instancia: el contratista tiene vías adicionales de defensa luego de la decisión.

10

Posibilidad de corrección

Si durante la audiencia el contratista demuestra que ya corrigió el incumplimiento o presenta garantías suficientes de subsanación, la entidad puede suspender el trámite y otorgar un plazo de cumplimiento. Esta es una oportunidad estratégica que no debe desaprovecharse.

11

Ausencia de términos legales estrictos

No existe un término legal expreso para que la entidad inicie el trámite. Sin embargo, la doctrina del acto propio y la buena fe limitan la posibilidad de sancionar tardíamente cuando la entidad toleró el incumplimiento por largo tiempo sin actuar. Esta defensa debe plantearse con argumentación sólida.

12

Proporcionalidad de multas

Las multas deben guardar proporción con la gravedad del incumplimiento y no pueden exceder los topes contractuales. La desproporción es causal autónoma de nulidad del acto sancionatorio. Un análisis de proporcionalidad bien fundamentado puede reducir o anular la multa impuesta.

13

Caducidad de la acción sancionatoria

Las sanciones contractuales no son imprescriptibles. Están sujetas a los términos de caducidad de las acciones contractuales bajo el derecho administrativo colombiano. Vencido el término, la facultad sancionatoria se extingue y cualquier acto dictado sería nulo.

Conclusión

El procedimiento sancionatorio contractual es un escenario de alta complejidad jurídica para contratistas y entidades. Conocer sus reglas, límites y garantías es indispensable para una defensa efectiva o para el ejercicio legítimo de la potestad sancionatoria. Ante una audiencia de este tipo, la asesoría jurídica especializada no es opcional: es determinante.

Comparte si te fue útil
Descarga el PDF completo — disponible para miembros registrados
Comentarios

Regístrate para dejar un comentario y unirte a la conversación.

¿Tiene una pregunta legal?

Nuestro equipo responde con claridad y estrategia real.

Consultar ahora
'; w.document.write(html); w.document.close(); } // ── Visit counter (localStorage simulation) ──────────────── // For production: replace with a real endpoint like POST /api/track-visit function trackVisit(slug) { // CountAPI: real global counter, no signup required // Increments once per session to avoid refresh inflation var sessKey = 'vp_hit_' + slug; var endpoint = sessionStorage.getItem(sessKey) ? 'https://api.countapi.xyz/get/vasquezperez-academia/' + slug : 'https://api.countapi.xyz/hit/vasquezperez-academia/' + slug; if(!sessionStorage.getItem(sessKey)){ try { sessionStorage.setItem(sessKey,'1'); } catch(e){} } fetch(endpoint) .then(function(r){ return r.json(); }) .then(function(d){ if(d && typeof d.value === 'number'){ var vc = document.getElementById('visitCounter'); var vn = document.getElementById('visitCount'); if(vc && vn){ vn.textContent = d.value >= 1000 ? (d.value/1000).toFixed(1).replace('.0','')+'k' : d.value.toString(); vc.style.display = 'inline-flex'; } } }) .catch(function(){ // CountAPI unavailable — hide counter rather than show fake number var vc = document.getElementById('visitCounter'); if(vc) vc.style.display = 'none'; }); } // ══════════════════════════════════════════════════════════════════════ // SHARED ARTICLE ENHANCEMENTS // ══════════════════════════════════════════════════════════════════════ // ── SESSION / USER STATE ─────────────────────────────────────────────── var vpSession = (function() { try { return JSON.parse(localStorage.getItem('vp_user') || 'null'); } catch(e) { return null; } })(); function saveSession(user) { vpSession = user; try { localStorage.setItem('vp_user', JSON.stringify(user)); } catch(e) {} } function clearSession() { vpSession = null; try { localStorage.removeItem('vp_user'); } catch(e) {} } function isLoggedIn() { return !!vpSession; } function isAdmin() { return vpSession && vpSession.role === 'admin'; } // ── ACCORDION POINTS ─────────────────────────────────────────────────── // ── FEMALE VOICE AUDIO ───────────────────────────────────────────────── var _isPlaying = false; var _utterance = null; function _getFemalVoice(lang) { var voices = (window.speechSynthesis && window.speechSynthesis.getVoices()) || []; var lc = (lang === 'en') ? 'en' : 'es'; var scored = voices.map(function(v) { var s = 0, n = v.name.toLowerCase(), vl = (v.lang || '').toLowerCase(); if (vl.indexOf(lc) === 0) s += 20; var fem = ['lucia','paulina','monica','clara','paloma','sofia','elena','maria','laura','sara','karen','victoria','female','mujer','google español']; if (fem.some(function(f){ return n.indexOf(f) >= 0; })) s += 30; var mal = ['jorge','carlos','diego','antonio','juan','francisco','male','hombre']; if (mal.some(function(m){ return n.indexOf(m) >= 0; })) s -= 15; if (!v.localService) s += 5; return { v: v, s: s }; }); scored.sort(function(a,b){ return b.s - a.s; }); return scored.length ? scored[0].v : null; } function _updateAudioUI(playing) { var btn = document.getElementById('audioPlayBtn') || document.getElementById('audioCtrlBtn'); var note = document.getElementById('audioNoteEl'); var wave = document.getElementById('waveformEl'); var icon = document.getElementById('audioIconSvg') || document.getElementById('audioPlayIcon'); if (btn) btn.classList.toggle('playing', playing); if (wave) wave.style.display = playing ? 'flex' : 'none'; if (icon) icon.style.display = playing ? 'none' : ''; if (note && !playing) note.textContent = 'Voz femenina · Accesibilidad'; } function toggleAudio() { if (!('speechSynthesis' in window)) { artToast('Tu navegador no soporta lectura en voz.', 'blue'); return; } if (_isPlaying) { window.speechSynthesis.cancel(); _isPlaying = false; _updateAudioUI(false); return; } // Get only the active content div text var activeBlock = null; ['content-es-tech','content-es-simple','content-en-tech','content-en-simple'].forEach(function(id) { var el = document.getElementById(id); if (el && el.style.display !== 'none') activeBlock = el; }); // Fallback to art-body if (!activeBlock) activeBlock = document.getElementById('art-reading-body'); if (!activeBlock) return; // Get plain text — strip HTML, limit to 4500 chars var raw = (activeBlock.innerText || activeBlock.textContent || '').substring(0, 4800).trim(); if (!raw || raw.length < 30) return; var lang = (typeof currentLang !== 'undefined') ? currentLang : 'es'; _utterance = new SpeechSynthesisUtterance(raw); _utterance.lang = (lang === 'en') ? 'en-US' : 'es-CO'; _utterance.rate = 0.87; _utterance.pitch = 1.07; function doSpeak() { var voice = _getFemalVoice(lang); if (voice) { _utterance.voice = voice; var n = document.getElementById('audioNoteEl'); if (n) n.textContent = '🎙 ' + voice.name; } _utterance.onend = _utterance.onerror = function() { _isPlaying = false; _updateAudioUI(false); }; window.speechSynthesis.speak(_utterance); _isPlaying = true; _updateAudioUI(true); } var vl = window.speechSynthesis.getVoices(); if (vl && vl.length > 0) { doSpeak(); } else { window.speechSynthesis.onvoiceschanged = function() { window.speechSynthesis.onvoiceschanged = null; doSpeak(); }; setTimeout(doSpeak, 300); } } // ── PDF DOWNLOAD (gated) ─────────────────────────────────────────────── function dlPDF() { if (!isLoggedIn()) { openUserModal('login'); artToast('Inicia sesión para descargar el PDF.', 'blue'); return; } var titleEl = document.getElementById('hero-title-es') || document.querySelector('.art-hero-title'); var title = titleEl ? titleEl.textContent.trim() : document.title; var activeBlock = null; ['content-es-tech','content-es-simple','content-en-tech','content-en-simple'].forEach(function(id) { var el = document.getElementById(id); if (el && el.style.display !== 'none') activeBlock = el; }); var body = activeBlock ? activeBlock.innerHTML : ''; var w = window.open('','_blank','width=820,height=960'); if (!w) { artToast('Permite las ventanas emergentes para descargar.', 'blue'); return; } w.document.write('' + title + '' + '' + '' + '' + '
Vásquez Pérez Abogados · Academia Legal
' + '

' + title + '

' + '
vasquezperez.com/academialegal · © 2026 · Documento informativo
' + body + '' + 'window.onload=function(){window.print();}'); w.document.close(); } // ── USER MODAL (Login / Register) ───────────────────────────────────── var _umTab = 'login'; var _umRole = ''; function openUserModal(tab) { _umTab = tab || 'login'; var m = document.getElementById('userModal'); if (!m) return; m.style.display = 'flex'; document.body.style.overflow = 'hidden'; setTimeout(function() { m.classList.add('vis'); }, 10); switchUMTab(_umTab); setTimeout(function() { var e = document.getElementById('umEmail'); if(e) e.focus(); }, 380); } function closeUserModal() { var m = document.getElementById('userModal'); if (!m) return; m.classList.remove('vis'); setTimeout(function() { m.style.display = 'none'; document.body.style.overflow = ''; }, 300); } function switchUMTab(tab) { _umTab = tab; document.querySelectorAll('.um-tab').forEach(function(b) { b.classList.toggle('on', b.dataset.tab === tab); }); var loginFields = document.getElementById('umLoginFields'); var regFields = document.getElementById('umRegFields'); var umTitle = document.getElementById('umTitle'); var umSub = document.getElementById('umSub'); if (loginFields) loginFields.style.display = (tab === 'login') ? '' : 'none'; if (regFields) regFields.style.display = (tab === 'register') ? '' : 'none'; if (umTitle) umTitle.textContent = (tab === 'login') ? 'Acceder' : 'Crear cuenta'; if (umSub) umSub.textContent = (tab === 'login') ? 'Ingresa con tus credenciales.' : 'Regístrate para reaccionar, comentar y descargar.'; } function setRole(role) { _umRole = role; document.querySelectorAll('.um-role-btn').forEach(function(b) { b.classList.toggle('on', b.dataset.role === role); }); } function doUserAction() { var email = (document.getElementById('umEmail') || {value:''}).value.trim().toLowerCase(); var pass = (document.getElementById('umPass') || {value:''}).value; var errEl = document.getElementById('umErr'); var btn = document.getElementById('umBtn'); var spin = document.getElementById('umSpin'); var btnTxt = document.getElementById('umBtnTxt'); if (errEl) errEl.style.display = 'none'; if (!email || !pass) { if (errEl) { errEl.textContent = 'Completa todos los campos.'; errEl.style.display = 'block'; } return; } if (_umTab === 'register') { var name = (document.getElementById('umName') || {value:''}).value.trim(); var consent = document.getElementById('umConsent'); if (!name) { if(errEl){errEl.textContent='Escribe tu nombre completo.';errEl.style.display='block';} return; } if (!_umRole) { if(errEl){errEl.textContent='Indica si eres abogado o no.';errEl.style.display='block';} return; } if (!consent || !consent.checked) { if(errEl){errEl.textContent='Debes autorizar el tratamiento de datos para continuar.';errEl.style.display='block';} return; } } if (btn) btn.disabled = true; if (btnTxt) btnTxt.style.display = 'none'; if (spin) spin.style.display = 'block'; setTimeout(function() { var ADMIN_EMAIL = 'admin@vasquezperez.com'; var ADMIN_PASS = 'vpAdmin2026!'; var user; if (_umTab === 'login') { if (email === ADMIN_EMAIL && pass === ADMIN_PASS) { user = { email: email, name: 'Juan Simón Vásquez Pérez', role: 'admin', readerPref: 'tech' }; } else if (email.includes('@') && pass.length >= 6) { // Simulate existing user - in production: POST /api/auth/login var stored = null; try { stored = JSON.parse(localStorage.getItem('vp_users_' + email)); } catch(e) {} if (stored && stored.pass === pass) { user = stored; } else { if (errEl) { errEl.textContent = 'Credenciales incorrectas.'; errEl.style.display = 'block'; } if (btn) btn.disabled = false; if (btnTxt) btnTxt.style.display = ''; if (spin) spin.style.display = 'none'; return; } } else { if (errEl) { errEl.textContent = 'Credenciales incorrectas.'; errEl.style.display = 'block'; } if (btn) btn.disabled = false; if (btnTxt) btnTxt.style.display = ''; if (spin) spin.style.display = 'none'; return; } } else { // Register var name = (document.getElementById('umName') || {value:''}).value.trim(); user = { email: email, name: name, role: 'user', readerPref: (_umRole === 'lawyer') ? 'tech' : 'simple', profession: _umRole }; try { localStorage.setItem('vp_users_' + email, JSON.stringify(Object.assign({}, user, {pass: pass}))); } catch(e) {} // In production: POST /api/auth/register with tratamiento de datos flag } saveSession(user); closeUserModal(); applySession(user); artToast('Bienvenido, ' + user.name.split(' ')[0] + '!', 'green'); // Apply reader preference based on profile if (user.readerPref && typeof setReader === 'function') { setTimeout(function() { setReader(user.readerPref, document.querySelector('[data-mode="' + user.readerPref + '"]')); }, 300); } }, 700); } function applySession(user) { if (!user) return; // Update nav access button var accessBtn = document.getElementById('navAccessBtn') || document.getElementById('artNavAccess'); if (accessBtn) { var initials = user.name.split(' ').map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase(); accessBtn.textContent = initials; accessBtn.style.background = (user.role === 'admin') ? 'var(--blue)' : 'rgba(255,255,255,.15)'; accessBtn.style.borderRadius = '100px'; accessBtn.style.width = '34px'; accessBtn.style.height = '34px'; accessBtn.style.padding = '0'; accessBtn.style.fontWeight = '800'; accessBtn.style.fontSize = '11px'; accessBtn.onclick = function() { if (user.role === 'admin') { openUserModal('admin'); } else { if(confirm('¿Cerrar sesión?')) { clearSession(); location.reload(); } } }; } // Unlock gated content document.querySelectorAll('.gate-badge').forEach(function(g) { var btn = g.querySelector('.gate-btn'); if (btn) { btn.textContent = '✓ Disponible'; btn.style.background = '#059669'; btn.onclick = dlPDF; } }); // Show comments var cg = document.getElementById('commentGated'); var ci = document.getElementById('commentInput'); if (cg) cg.style.display = 'none'; if (ci) ci.style.display = ''; } // ── REACTIONS ────────────────────────────────────────────────────────── function doReaction(type) { if (!isLoggedIn()) { openUserModal('login'); artToast('Inicia sesión para reaccionar.', 'blue'); return; } var slug = (window.location.pathname.split('/').filter(Boolean).pop() || 'articulo'); var key = 'vp_react_' + slug + '_' + type; var btn = document.querySelector('.reaction-btn[data-type="' + type + '"]'); var cnt = btn ? btn.querySelector('.rcount') : null; var already = false; try { already = localStorage.getItem(key) === '1'; } catch(e) {} if (already) { try { localStorage.removeItem(key); } catch(e) {} if (btn) btn.classList.remove('active'); if (cnt) cnt.textContent = Math.max(0, parseInt(cnt.textContent||'0') - 1); } else { try { localStorage.setItem(key, '1'); } catch(e) {} if (btn) btn.classList.add('active'); if (cnt) cnt.textContent = parseInt(cnt.textContent||'0') + 1; artToast(type === 'like' ? '¡Gracias por tu reacción!' : 'Comentario marcado.', 'green'); } } function doComment() { if (!isLoggedIn()) { openUserModal('login'); return; } var input = document.getElementById('commentText'); var text = input ? input.value.trim() : ''; if (!text) return; var list = document.getElementById('commentList'); if (list) { var initials = vpSession.name.split(' ').map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase(); var now = new Date().toLocaleDateString('es-CO', {day:'2-digit',month:'short',year:'numeric'}); var el = document.createElement('div'); el.className = 'comment-item'; el.innerHTML = '
' + initials + '
' + vpSession.name.split(' ')[0] + '
' + now + '
' + text.replace(//g,'>') + '
'; list.appendChild(el); } if (input) input.value = ''; artToast('Comentario publicado.', 'green'); } // ── TOAST ────────────────────────────────────────────────────────────── function artToast(msg, type) { var t = document.createElement('div'); t.className = 'art-toast ' + (type || 'blue'); t.textContent = msg; document.body.appendChild(t); setTimeout(function() { t.classList.add('show'); }, 20); setTimeout(function() { t.classList.remove('show'); setTimeout(function(){t.remove();},400); }, 3500); } // ── COUNTAPI VISIT COUNTER ───────────────────────────────────────────── function initVisitCounter(slug) { var vc = document.getElementById('visitCounter'); var vcn = document.getElementById('visitCount'); if (!vc || !vcn) return; var sessKey = 'vp_hit_' + slug; var endpoint = sessionStorage.getItem(sessKey) ? 'https://api.countapi.xyz/get/vasquezperez-academia/' + slug : 'https://api.countapi.xyz/hit/vasquezperez-academia/' + slug; if (!sessionStorage.getItem(sessKey)) { try { sessionStorage.setItem(sessKey, '1'); } catch(e){} } fetch(endpoint) .then(function(r) { return r.json(); }) .then(function(d) { if (d && typeof d.value === 'number') { vcn.textContent = d.value >= 1000 ? (d.value/1000).toFixed(1).replace('.0','')+'k' : String(d.value); vc.style.display = 'inline-flex'; } }) .catch(function() { /* silent */ }); } // ── LOAD COMMENTS FROM LOCAL STORAGE (demo) ──────────────────────────── function loadDemoComments(slug) { // In production: GET /api/comments/{slug} // Demo: show 1 sample comment var list = document.getElementById('commentList'); if (!list) return; var sample = '
MC
María C.
Abr 2026
Excelente análisis. Muy útil para entender los tiempos en la transferencia de acciones.
'; list.innerHTML = sample; } /* ════ VP PREMIUM AUTH SYSTEM ════════════════════════════════════════ */ var _vps = (function(){ try{ return JSON.parse(localStorage.getItem('vp_user')||'null'); }catch(e){ return null; } })(); var _vpTab = 'login'; var _vpRole = ''; function _isLoggedIn(){ return !!_vps; } function _isAdmin(){ return _vps && _vps.role === 'admin'; } /* ── Open / Close ──────────────────────────────────────────────────── */ function openVPModal(tab){ _vpTab = tab||'login'; var m = document.getElementById('vpModal'); if(!m) return; m.style.display = 'flex'; document.body.style.overflow = 'hidden'; requestAnimationFrame(function(){ m.classList.add('vis'); }); _vpSwitchTab(_vpTab); setTimeout(function(){ var e=document.getElementById('vpEmail'); if(e) e.focus(); }, 420); } function closeVPModal(){ var m = document.getElementById('vpModal'); if(!m) return; m.classList.remove('vis'); setTimeout(function(){ m.style.display='none'; document.body.style.overflow=''; }, 340); } /* ── Tabs ──────────────────────────────────────────────────────────── */ function _vpSwitchTab(tab){ _vpTab = tab; document.querySelectorAll('.vp-tab').forEach(function(b){ b.classList.toggle('on', b.dataset.tab===tab); }); var lf=document.getElementById('vpLogin'); var rf=document.getElementById('vpReg'); var hl=document.getElementById('vpHL'); var sl=document.getElementById('vpSL'); var ch=document.getElementById('vpChips'); if(lf) lf.style.display = tab==='login' ? '' : 'none'; if(rf) rf.style.display = tab==='register' ? '' : 'none'; if(hl) hl.textContent = tab==='login' ? 'Bienvenido de vuelta' : 'Crea tu cuenta'; if(sl) sl.textContent = tab==='login' ? 'Accede a tu perfil de Academia Legal.' : 'Regístrate para acceder a todos los beneficios.'; if(ch) ch.style.display = tab==='register' ? '' : 'none'; var ft=document.getElementById('vpFoot'); if(ft) ft.innerHTML = tab==='login' ? '\u00bfSin cuenta? Regístrate gratis' : '\u00bfYa tienes cuenta? Ingresar'; } /* ── Role ──────────────────────────────────────────────────────────── */ function _vpPickRole(r){ _vpRole = r; document.querySelectorAll('.vp-role').forEach(function(b){ b.classList.toggle('on', b.dataset.role===r); }); } /* ── Submit ────────────────────────────────────────────────────────── */ function vpSubmit(){ var email = (document.getElementById('vpEmail')||{value:''}).value.trim().toLowerCase(); var pass = (document.getElementById('vpPass') ||{value:''}).value; var errEl = document.getElementById('vpErr'); var btn = document.getElementById('vpBtn'); var spin = document.getElementById('vpSpin'); var btxt = document.getElementById('vpBtnTxt'); if(errEl){ errEl.style.display='none'; errEl.classList.remove('show'); } function showErr(msg){ if(errEl){ errEl.textContent=msg; errEl.style.display='block'; errEl.classList.add('show'); } } if(!email||!pass){ showErr('Completa todos los campos.'); return; } if(pass.length<6){ showErr('La contraseña debe tener al menos 6 caracteres.'); return; } if(_vpTab==='register'){ var name = (document.getElementById('vpName')||{value:''}).value.trim(); var ck = document.getElementById('vpCk'); if(!name){ showErr('Escribe tu nombre completo.'); return; } if(!_vpRole){ showErr('Selecciona tu perfil para continuar.'); return; } if(!ck||!ck.checked){ showErr('Debes autorizar el tratamiento de datos personales para registrarte.'); return; } } if(btn) btn.disabled=true; if(btxt) btxt.style.display='none'; if(spin) spin.style.display='block'; setTimeout(function(){ var user; if(_vpTab==='login'){ if(email==='admin@vasquezperez.com' && pass==='vpAdmin2026!'){ user={email:email,name:'Juan Simón Vásquez Pérez',role:'admin',pref:'tech',ini:'JS'}; } else { var st=null; try{ st=JSON.parse(localStorage.getItem('vp_u_'+email)); }catch(e){} if(st && st.pw===pass){ user={email:email,name:st.name,role:'user',pref:st.pref,ini:st.ini,prof:st.prof}; } else { showErr('Correo o contraseña incorrectos.'); if(btn) btn.disabled=false; if(btxt) btxt.style.display=''; if(spin) spin.style.display='none'; var pe=document.getElementById('vpPass'); if(pe){ pe.classList.add('shake'); setTimeout(function(){ pe.classList.remove('shake'); },600); } return; } } } else { var name=(document.getElementById('vpName')||{value:''}).value.trim(); var ini=name.split(' ').map(function(w){ return w[0]||''; }).join('').substring(0,2).toUpperCase(); user={email:email,name:name,role:'user',pref:(_vpRole==='lawyer'?'tech':'simple'),ini:ini,prof:_vpRole}; try{ localStorage.setItem('vp_u_'+email, JSON.stringify({name:name,pw:pass,pref:user.pref,ini:ini,prof:_vpRole})); }catch(e){} } _vps=user; try{ localStorage.setItem('vp_user',JSON.stringify(user)); }catch(e){} closeVPModal(); _vpApply(user); vpToast(_vpTab==='register' ? 'Bienvenido, '+user.name.split(' ')[0]+'!' : 'Sesión iniciada.', 'green'); if(user.pref && typeof setReader==='function'){ setTimeout(function(){ setReader(user.pref, document.querySelector('[data-mode="'+user.pref+'"]')); },320); } },700); } /* ── Apply session visually ────────────────────────────────────────── */ function _vpApply(user){ if(!user) return; var acc=document.getElementById('vpAccess'); if(acc){ var color=user.role==='admin'?'#153ABF':'#059669'; var sess=document.createElement('div'); sess.className='vp-session'; sess.id='vpSession'; sess.innerHTML=( '
'+user.ini+'
'+ ''+user.name.split(' ')[0]+''+ ''+ '
'+ '
'+ '
'+user.name+'
'+ '
'+(user.role==='admin'?'Administrador':(user.pref==='tech'?'Abogado':'Usuario'))+'
'+ '
'+ ''+ '
'+ ''+ '
' ); sess.style.display='flex'; sess.addEventListener('click',function(){ sess.classList.toggle('open'); }); document.addEventListener('click',function(e){ if(!sess.contains(e.target)) sess.classList.remove('open'); }); acc.parentNode.replaceChild(sess, acc); } /* Unlock gated content */ document.querySelectorAll('.gate-unlock').forEach(function(b){ b.textContent='↓ Descargar PDF'; b.style.background='#059669'; b.onclick=function(){ downloadPDF(); }; }); var cg=document.getElementById('cmtGated'); if(cg) cg.style.display='none'; var ci=document.getElementById('cmtInput'); if(ci) ci.style.display=''; } /* ── Logout ────────────────────────────────────────────────────────── */ function vpLogout(){ _vps=null; try{ localStorage.removeItem('vp_user'); }catch(e){} vpToast('Sesión cerrada.','blue'); setTimeout(function(){ location.reload(); },700); } /* ── Reactions ─────────────────────────────────────────────────────── */ function vpReact(type){ if(!_isLoggedIn()){ openVPModal('login'); vpToast('Inicia sesión para reaccionar.','blue'); return; } var slug=(window.location.pathname.split('/').filter(Boolean).pop()||'art'); var key='vp_rx_'+slug+'_'+type; var btn=document.querySelector('.rxn-btn[data-type="'+type+'"]'); var cnt=btn?btn.querySelector('.rxn-count'):null; var had=false; try{ had=localStorage.getItem(key)==='1'; }catch(e){} if(had){ try{ localStorage.removeItem(key); }catch(e){} if(btn) btn.classList.remove('on'); if(cnt) cnt.textContent=Math.max(0,parseInt(cnt.textContent||'0')-1); } else { try{ localStorage.setItem(key,'1'); }catch(e){} if(btn) btn.classList.add('on'); if(cnt) cnt.textContent=parseInt(cnt.textContent||'0')+1; vpToast('¡Gracias!','green'); } } /* ── Comment ───────────────────────────────────────────────────────── */ function vpComment(){ if(!_isLoggedIn()){ openVPModal('login'); return; } var inp=document.getElementById('cmtText'); var txt=inp?inp.value.trim():''; if(!txt) return; var list=document.getElementById('cmtList'); if(list){ var ini=_vps.name.split(' ').map(function(w){ return w[0]||''; }).join('').substring(0,2).toUpperCase(); var now=new Date().toLocaleDateString('es-CO',{day:'2-digit',month:'short',year:'numeric'}); var el=document.createElement('div'); el.className='cmt'; el.innerHTML=( '
'+ '
'+ini+'
'+ '
'+_vps.name.split(' ')[0]+'
'+ '
'+now+'
'+ '
'+ '
'+txt.replace(//g,'>')+'
' ); list.appendChild(el); } if(inp) inp.value=''; vpToast('Comentario publicado.','green'); } /* ── PDF Download (gated) ─────────────────────────────────────────── */ function downloadPDF(){ if(!_isLoggedIn()){ openVPModal('login'); vpToast('Inicia sesión para descargar.','blue'); return; } var titleEl=document.getElementById('hero-title-es')||document.querySelector('.art-hero-title'); var title=titleEl?titleEl.textContent.trim():document.title; var activeBlock=['content-es-tech','content-es-simple','content-en-tech','content-en-simple'].reduce(function(a,id){ var el=document.getElementById(id); return (el&&el.style.display!=='none')?el:a; },null)||document.getElementById('art-reading-body'); var body=activeBlock?activeBlock.innerHTML:''; var w=window.open('','_blank','width=820,height=960'); if(!w){ vpToast('Permite ventanas emergentes para descargar.','blue'); return; } w.document.write( ''+title+''+ ''+ ''+ ''+ '
Vásquez Pérez Abogados · Academia Legal
'+ '

'+title+'

'+ '
vasquezperez.com/academialegal · 2026 · Documento informativo
'+ body+ ''+ 'window.onload=function(){window.print();}'+ '' ); w.document.close(); } /* ── Female voice audio ───────────────────────────────────────────── */ var _playing=false; function _femVoice(lang){ var voices=(window.speechSynthesis&&window.speechSynthesis.getVoices())||[]; var lc=lang==='en'?'en':'es'; var fem=['lucia','paulina','monica','clara','paloma','sofia','elena','maria','laura','karen','victoria','female','mujer','google esp']; var mal=['jorge','carlos','diego','antonio','juan','francisco','male','hombre']; var sc=voices.map(function(v){ var s=0,n=v.name.toLowerCase(),vl=(v.lang||'').toLowerCase(); if(vl.indexOf(lc)===0) s+=20; if(fem.some(function(f){ return n.indexOf(f)>=0; })) s+=30; if(mal.some(function(m){ return n.indexOf(m)>=0; })) s-=15; if(!v.localService) s+=5; return {v:v,s:s}; }); sc.sort(function(a,b){ return b.s-a.s; }); return sc.length?sc[0].v:null; } function toggleAudio(){ if(!('speechSynthesis' in window)){ vpToast('Tu navegador no soporta lectura en voz.','blue'); return; } if(_playing){ window.speechSynthesis.cancel(); _playing=false; _updAudioUI(false); return; } var blocks=['content-es-tech','content-es-simple','content-en-tech','content-en-simple']; var block=blocks.reduce(function(a,id){ var el=document.getElementById(id); return(el&&el.style.display!=='none')?el:a; },null); if(!block) block=document.getElementById('art-reading-body'); if(!block) return; var txt=(block.innerText||block.textContent||'').substring(0,4800).trim(); if(!txt||txt.length<20) return; var lang=typeof currentLang!=='undefined'?currentLang:'es'; var u=new SpeechSynthesisUtterance(txt); u.lang=lang==='en'?'en-US':'es-CO'; u.rate=0.87; u.pitch=1.06; function go(){ var v=_femVoice(lang); if(v){ u.voice=v; var n=document.getElementById('audioNoteEl'); if(n) n.textContent='Voz: '+v.name; } u.onend=u.onerror=function(){ _playing=false; _updAudioUI(false); }; window.speechSynthesis.speak(u); _playing=true; _updAudioUI(true); } var vl=window.speechSynthesis.getVoices(); if(vl&&vl.length>0){ go(); } else { window.speechSynthesis.onvoiceschanged=function(){ window.speechSynthesis.onvoiceschanged=null; go(); }; setTimeout(go,300); } } function _updAudioUI(p){ var btn=document.getElementById('audioCtrlBtn'); var wave=document.getElementById('waveformEl'); var icon=document.getElementById('audioIconSvg'); var note=document.getElementById('audioNoteEl'); if(btn) btn.style.color=p?'var(--blue)':''; if(wave) wave.style.display=p?'flex':'none'; if(icon) icon.style.display=p?'none':''; if(note&&!p) note.textContent='Voz femenina · Accesibilidad'; } /* ── CountAPI ─────────────────────────────────────────────────────── */ function initVC(slug){ var vc=document.getElementById('visitCounter'); var vcn=document.getElementById('visitCount'); if(!vc||!vcn) return; var key='vp_hit_'+slug; var ep=sessionStorage.getItem(key) ?'https://api.countapi.xyz/get/vasquezperez-academia/'+slug :'https://api.countapi.xyz/hit/vasquezperez-academia/'+slug; if(!sessionStorage.getItem(key)){ try{ sessionStorage.setItem(key,'1'); }catch(e){} } fetch(ep).then(function(r){ return r.json(); }).then(function(d){ if(d&&typeof d.value==='number'){ vcn.textContent=d.value>=1000?(d.value/1000).toFixed(1).replace('.0','')+'k':String(d.value); vc.style.display='inline-flex'; } }).catch(function(){}); } /* ── Toast ────────────────────────────────────────────────────────── */ function vpToast(msg,type){ var t=document.createElement('div'); t.className='vp-toast '+(type||'blue'); t.innerHTML=''+msg+''; document.body.appendChild(t); setTimeout(function(){ t.classList.add('show'); },20); setTimeout(function(){ t.classList.remove('show'); setTimeout(function(){ t.remove(); },420); },3800); } /* ── Dividend calculator ──────────────────────────────────────────── */ function calcDiv(){ var ins=document.getElementById('calcIns'); var div=document.getElementById('calcDiv'); var res=document.getElementById('calcResult'); if(!ins||!div||!res) return; var id=ins.value?new Date(ins.value):null; var dd=div.value?new Date(div.value):null; if(!id||!dd){ res.className='acc-result'; res.textContent='Ingresa ambas fechas para calcular.'; return; } var fmt=function(d){ return d.toLocaleDateString('es-CO',{day:'numeric',month:'long',year:'numeric'}); }; if(id<=dd){ res.className='acc-result ok'; res.innerHTML='Tienes derecho a ese dividendo. Estabas inscrito el '+fmt(id)+', antes de que el dividendo fuera exigible el '+fmt(dd)+'.'; } else { var diff=Math.round((id-dd)/(86400000)); res.className='acc-result warn'; res.innerHTML='No tienes derecho a ese dividendo. Te inscribiste el '+fmt(id)+', pero el dividendo ya era exigible desde el '+fmt(dd)+' — '+diff+' día(s) antes. Solo tienes derecho a dividendos exigibles después del '+fmt(id)+'.'; } } /* ── Accordion ────────────────────────────────────────────────────── */ function initAccordion(){ document.querySelectorAll('.art-point').forEach(function(pt){ if(pt.dataset.ready==='1') return; pt.dataset.ready='1'; var pn=pt.querySelector('.point-num'); var pc=pt.querySelector('.point-content'); if(!pn||!pc) return; var h4=pc.querySelector('h4'); var p=pc.querySelector('p'); var title=h4?h4.textContent.trim():''; var body=p?p.outerHTML:''; pt.innerHTML=( '
'+ '
'+pn.textContent.trim()+'
'+ '
'+title+'
'+ '
'+ '
'+ (body?'
'+body+'
':'') ); if(body){ pt.addEventListener('click',function(){ var open=pt.classList.contains('open'); var par=pt.parentNode; if(par) par.querySelectorAll('.art-point.open').forEach(function(o){ if(o!==pt) o.classList.remove('open'); }); pt.classList.toggle('open',!open); }); } }); var first=document.querySelector('#content-es-tech .art-point')||document.querySelector('.art-point'); if(first&&first.querySelector&&first.querySelector('.ap-body')) first.classList.add('open'); } /* ── Keyboard ─────────────────────────────────────────────────────── */ document.addEventListener('keydown',function(e){ if(e.key==='Escape') closeVPModal(); }); /* ── Init ─────────────────────────────────────────────────────────── */ document.addEventListener('DOMContentLoaded',function(){ initAccordion(); if(_vps) _vpApply(_vps); if(_vps&&_vps.pref&&typeof setReader==='function'){ setReader(_vps.pref, document.querySelector('[data-mode="'+_vps.pref+'"]')); } }); /* ═══ VP ACADEMIA — PREMIUM ARTICLE INTERACTIONS ═══════════════════ */ (function(){ /* ── 1. Reading progress bar ──────────────────────────────────────── */ var _rpBar = document.createElement('div'); _rpBar.className = 'vp-read-bar'; document.body.appendChild(_rpBar); window.addEventListener('scroll', function(){ var h = document.documentElement.scrollHeight - window.innerHeight; if(h > 0) _rpBar.style.width = Math.min(100, (window.scrollY/h)*100) + '%'; }, {passive:true}); /* ── 2. Accordion premium ──────────────────────────────────────────── */ function initAccordion(){ document.querySelectorAll('.art-point').forEach(function(pt){ if(pt.dataset.vpAc) return; pt.dataset.vpAc = '1'; /* reconstruct into ap-header / ap-body */ var pnEl = pt.querySelector('.point-num, .pn'); var pcEl = pt.querySelector('.point-content, .pc'); if(!pnEl || !pcEl) return; var num = pnEl.textContent.trim() || '•'; var h4 = pcEl.querySelector('h4'); var pEl = pcEl.querySelector('p'); var title = h4 ? h4.textContent.trim() : ''; var body = pEl ? pEl.outerHTML : ''; pt.innerHTML = ( '
' + '
' + num + '
' + '
' + title + '
' + '
' + '' + '' + '' + '
' + '
' + (body ? '
' + body + '
' : '') ); pt.addEventListener('click', function(){ var isOpen = pt.classList.contains('open'); /* close siblings */ var par = pt.parentNode; if(par) par.querySelectorAll('.art-point.open').forEach(function(o){ if(o !== pt) o.classList.remove('open'); }); pt.classList.toggle('open', !isOpen); }); }); /* open first by default */ var first = document.querySelector('#content-es-tech .art-point') || document.querySelector('.art-body .art-point'); if(first && !first.classList.contains('open')) first.classList.add('open'); } window.initAccordion = initAccordion; /* ── 3. Reveal on scroll ───────────────────────────────────────────── */ (function(){ var targets = '.art-point, .art-cta-block, .art-related, ' + '.rxn-bar, .cmts, .tl-wrap, .acc-calc, ' + '.art-lead, .vp-callout, .art-conclusion-block'; function addReveal(){ document.querySelectorAll(targets).forEach(function(el){ if(!el.classList.contains('vp-reveal')){ el.classList.add('vp-reveal'); } }); } addReveal(); if(!('IntersectionObserver' in window)){ document.querySelectorAll('.vp-reveal').forEach(function(el){ el.classList.add('vp-vis'); }); return; } var io = new IntersectionObserver(function(entries){ entries.forEach(function(e){ if(e.isIntersecting){ e.target.classList.add('vp-vis'); io.unobserve(e.target); } }); }, {threshold: 0.07, rootMargin: '0px 0px -32px 0px'}); document.querySelectorAll('.vp-reveal').forEach(function(el){ io.observe(el); }); })(); /* ── 4. Hero stat counter animation ───────────────────────────────── */ (function(){ if(!('IntersectionObserver' in window)) return; var io = new IntersectionObserver(function(entries){ entries.forEach(function(e){ if(!e.isIntersecting) return; var el = e.target; var end = parseInt(el.dataset.target || '0', 10); var sfx = el.dataset.suffix || ''; var dur = 1100; var t0 = Date.now(); io.unobserve(el); (function tick(){ var p = Math.min(1, (Date.now()-t0)/dur); var ease = 1 - Math.pow(1-p, 3); el.textContent = Math.round(ease * end) + (p >= 1 ? sfx : ''); if(p < 1) requestAnimationFrame(tick); })(); }); }, {threshold: 0.5}); document.querySelectorAll('.hero-stat-num[data-target]').forEach(function(el){ io.observe(el); }); })(); /* ── 5. artCtrl elevation on scroll ───────────────────────────────── */ (function(){ var ctrl = document.getElementById('artCtrl'); if(!ctrl) return; window.addEventListener('scroll', function(){ ctrl.classList.toggle('elevated', window.scrollY > 80); }, {passive: true}); })(); /* ── 6. Visit counter ──────────────────────────────────────────────── */ function initVC(slug){ var vc = document.getElementById('visitCounter'); var vcn = document.getElementById('visitCount'); if(!vc || !vcn) return; var key = 'vp_hit_' + slug; var ep = sessionStorage.getItem(key) ? 'https://api.countapi.xyz/get/vasquezperez-academia/' + slug : 'https://api.countapi.xyz/hit/vasquezperez-academia/' + slug; try{ sessionStorage.setItem(key,'1'); }catch(e){} fetch(ep) .then(function(r){ return r.json(); }) .then(function(d){ if(d && typeof d.value === 'number'){ vcn.textContent = d.value >= 1000 ? (d.value/1000).toFixed(1).replace('.0','') + 'k' : String(d.value); vc.style.display = 'inline-flex'; } }).catch(function(){}); } window.initVC = initVC; })(); // ── INIT ────────────────────────────────── function openUserModal(t){ if(typeof openVPModal==='function') openVPModal(t); } function artToast(m,t){ if(typeof vpToast==='function') vpToast(m,t); } document.addEventListener('DOMContentLoaded',function(){ if(typeof initAccordion==='function') initAccordion(); if(typeof initVC==='function') initVC('sancionatorio'); if(typeof _vps!=='undefined'&&_vps){ if(typeof _vpApply==='function') _vpApply(_vps); if(_vps.pref&&typeof setReader==='function'){ setReader(_vps.pref,document.querySelector('[data-mode="'+_vps.pref+'"]')); } } }); function isLoggedIn(){ return typeof _isLoggedIn==='function'&&_isLoggedIn(); } /* ── Navegación por fases — art-sancionatorio ── */ function vpScrollToPoint(n){ var pts = document.querySelectorAll('.art-point'); var target = pts[n-1]; if(!target) return; target.scrollIntoView({behavior:'smooth', block:'center'}); setTimeout(function(){ target.click(); }, 400); }