diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index fe3a1b5..8a133c7 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -49,7 +49,12 @@ jobs: --exclude 'BRAND-IMAGE-PROMPTS.md' \ --exclude 'package.json' \ --exclude 'package-lock.json' \ - --exclude 'index.js' + --exclude 'index.js' \ + --exclude 'LANZAMIENTO-VEREDICTO.md' \ + --exclude 'LICENSE' \ + --exclude 'og-test-*' \ + --exclude 'og-zoom-*' \ + --exclude 'wrangler.toml' echo "Published files:"; find _site -maxdepth 1 | sort - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 diff --git a/assets/shared.css b/assets/shared.css index 2112ef0..24cfc02 100644 --- a/assets/shared.css +++ b/assets/shared.css @@ -117,3 +117,158 @@ nav .bar,.nav .bar{position:relative} RECORTABA el GIF: medido en /inferbench/, 22 px arriba y abajo con la demo a 800x500 en una caja de 870. Afecta a las tres páginas de producto que enseñan un GIF. */ figure img[width][height]{height:auto} + +/* ============================================================ + SEO / conversión — bloques compartidos por todas las páginas + (TL;DR, clúster de enlaces, compartir, CTA fijo en móvil). + Añadido en la pasada de los 26 puntos de SEO. + ============================================================ */ + +/* ── TL;DR / Key takeaways ─────────────────────────────────── + Va SIEMPRE justo después del hero: primero la intención de + búsqueda (el h1 + el subtítulo), después el resumen. */ +.tldr{border:1px solid var(--line2,#3A2C22);border-left:3px solid var(--ember,#FF6A00); + background:linear-gradient(180deg,rgba(26,19,16,.72),rgba(14,11,10,.55)); + border-radius:14px;padding:22px 24px;max-width:860px;margin:0 auto; + box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 1px 2px rgba(0,0,0,.4)} +.tldr h2{font-size:13px;letter-spacing:1.6px;text-transform:uppercase; + color:var(--amber,#FFB02E);font-weight:700;margin-bottom:14px} +.tldr ul{list-style:none;display:grid;gap:10px} +.tldr li{position:relative;padding-left:26px;font-size:16px;line-height:1.62; + color:var(--bone,#EFE7DC)} +.tldr li::before{content:"";position:absolute;left:6px;top:.62em;width:7px;height:7px; + border-radius:2px;transform:rotate(45deg); + background:linear-gradient(135deg,var(--ember,#FF6A00),var(--amber,#FFB02E))} +.tldr li b,.tldr li strong{color:#fff;font-weight:650} +@media(max-width:600px){.tldr{padding:18px 18px;border-radius:12px}.tldr li{font-size:15px}} + +/* ── Clúster de enlaces internos ───────────────────────────── + Cada página enlaza a sus hermanas: reparte autoridad y da a + Google la estructura del portfolio. */ +.related{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:26px} +.relcard{display:block;border:1px solid var(--line2,#3A2C22);border-radius:12px; + padding:15px 17px;background:rgba(26,19,16,.5);transition:.16s;color:inherit;text-decoration:none} +.relcard:hover{border-color:var(--ember,#FF6A00);transform:translateY(-2px); + background:rgba(26,19,16,.78)} +.relcard .rt{display:block;font-weight:650;font-size:15.5px;color:var(--bone,#EFE7DC);margin-bottom:5px} +.relcard .rd{display:block;font-size:13.5px;line-height:1.5;color:var(--dim,#A0917F)} +.relcard:hover .rt{color:var(--amber,#FFB02E)} + +/* ── Botón de compartir ────────────────────────────────────── + Usa navigator.share en móvil y copia al portapapeles en + escritorio. shared.js le pone el comportamiento. */ +.fv-share{display:inline-flex;align-items:center;gap:9px;margin-top:8px} +.fv-share .sharebtn{display:inline-flex;align-items:center;gap:8px;font-family:inherit; + font-size:14px;font-weight:600;padding:9px 15px;border-radius:11px;cursor:pointer; + border:1px solid var(--line2,#3A2C22);background:rgba(26,19,16,.55); + color:var(--bone,#EFE7DC);transition:.16s} +.fv-share .sharebtn:hover{border-color:var(--ember,#FF6A00);color:var(--amber,#FFB02E)} +.fv-share .sharebtn svg{width:16px;height:16px;flex:none} +.fv-share .sharemsg{font-size:13px;color:var(--amber,#FFB02E);opacity:0;transition:opacity .18s} +.fv-share .sharemsg.on{opacity:1} + +/* ── CTA fijo en móvil ─────────────────────────────────────── + Barra inferior que sólo existe por debajo de 760px. El + padding del body evita que tape el pie. */ +.stickycta{display:none} +@media(max-width:760px){ + .stickycta{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:90; + align-items:center;gap:12px;padding:10px 14px calc(10px + env(safe-area-inset-bottom,0px)); + background:rgba(14,11,10,.93);backdrop-filter:blur(12px); + border-top:1px solid var(--line2,#3A2C22); + box-shadow:0 -8px 28px rgba(0,0,0,.5)} + .stickycta .sct{flex:1;min-width:0;font-size:13px;line-height:1.35;color:var(--dim,#A0917F)} + .stickycta .sct b{display:block;font-size:14.5px;color:var(--bone,#EFE7DC);font-weight:650; + white-space:nowrap;overflow:hidden;text-overflow:ellipsis} + .stickycta .btn{flex:none;padding:11px 17px;font-size:14.5px} + body{padding-bottom:78px} + /* El CTA fijo no debe animarse: es un elemento de interfaz permanente. */ + .stickycta .btn-fire{animation:none} +} +@media(max-width:380px){ + .stickycta{gap:9px;padding-left:11px;padding-right:11px} + .stickycta .sct{font-size:12px} + .stickycta .btn{padding:10px 13px;font-size:13.5px} +} + +/* ── Respaldos de cero especificidad ───────────────────────────────────── + Los bloques nuevos (TL;DR, FAQ, clúster) se insertan en 18 páginas que NO + comparten la misma hoja: `.faq` sólo estaba definido en index.css, + trace/base.css, veredicto/base.css y regenta/index.css, y `.eye`/`.cta-row` + sólo en core.css/index.css. Aquí van los respaldos envueltos en `:where()` + para que su especificidad sea 0 y la hoja propia de cada página SIEMPRE + gane, aunque shared.css se cargue después. */ + +:where(.faq){max-width:720px;margin:0 auto;display:flex;flex-direction:column;gap:10px} +:where(.faq) details{background:var(--card,var(--panel,#1A1310));border:1px solid var(--line,#2C211B);border-radius:12px;padding:2px 18px;transition:border-color .16s ease} +:where(.faq) details[open]{border-color:var(--line2,#3A2C22)} +:where(.faq) summary{cursor:pointer;list-style:none;padding:15px 0;font-weight:600;font-size:15px;color:var(--bone,#EFE7DC);display:flex;justify-content:space-between;align-items:center;gap:14px} +:where(.faq) summary::-webkit-details-marker{display:none} +:where(.faq) summary::after{content:"+";color:var(--ember,#FF6A00);font-size:22px;font-weight:300;line-height:1;transition:transform .2s ease} +:where(.faq) details[open] summary::after{transform:rotate(45deg)} +:where(.faq) details p{color:var(--ash,#A89A8E);font-size:14px;line-height:1.6;margin:0;padding:0 0 16px} +:where(.eye){font-size:13px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:var(--amber,#FFB02E);display:block} +:where(.cta-row){display:flex;gap:14px;justify-content:center;flex-wrap:wrap} + +/* El bloque nuevo trae su propio `.wrap`; en la home y en /contacto el
+ ya es `.wrap`, así que el anidado duplicaría el padding lateral. */ +.wrap .wrap{max-width:none;padding:0} + +/* Detalles del TL;DR */ +.tldr .cta-row{margin-top:20px;justify-content:flex-start} +.tldr code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.9em; + background:rgba(255,106,0,.10);border:1px solid var(--line,#2C211B);border-radius:6px;padding:1px 6px;color:var(--amber,#FFB02E)} + +/* ── Tablas de datos insertadas por scripts/seo-tables.mjs ─────────────── + Clases propias (.tablewrap/.seotable) para no chocar con las tablas que + cada página ya tenía. Scroll lateral propio: la página nunca debe + desplazarse en horizontal. */ +/* `contain:inline-size` hace que el ancho del contenedor NO dependa de su + contenido. Sin esto, el `min-width:520px` de la tabla se propagaba hacia + arriba como ancho mínimo: en /contacto/ (cuyo es flex) estiraba el +
a 570px con el viewport a 375 y la página se desplazaba en + horizontal. Medido con Chrome headless en la pasada de los 26 puntos. */ +.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:34px; + contain:inline-size;max-width:100%; + border:1px solid var(--line,#2C211B);border-radius:14px;background:rgba(22,17,14,.5)} +.tablewrap::-webkit-scrollbar{height:6px} +.tablewrap::-webkit-scrollbar-thumb{background:var(--line2,#3A2C22);border-radius:3px} +.seotable{width:100%;border-collapse:collapse;font-size:14.5px;min-width:520px} +.seotable th,.seotable td{text-align:left;padding:13px 18px; + border-bottom:1px solid var(--line,#2C211B);vertical-align:top;line-height:1.55} +.seotable thead th{font-size:12px;letter-spacing:1.4px;text-transform:uppercase; + color:var(--amber,#FFB02E);font-weight:700;background:rgba(255,106,0,.06);white-space:nowrap} +.seotable tbody th{font-weight:650;color:var(--bone,#EFE7DC);white-space:nowrap} +.seotable tbody td{color:var(--ash,#A89A8E)} +.seotable tbody tr:last-child th,.seotable tbody tr:last-child td{border-bottom:0} +.seotable tbody tr:hover{background:rgba(255,106,0,.035)} +.seotable a{color:var(--amber,#FFB02E);text-decoration:none;font-weight:650} +.seotable a:hover{text-decoration:underline} +.seotable b{color:var(--bone,#EFE7DC)} +.seotable code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.92em; + background:rgba(255,106,0,.10);border:1px solid var(--line,#2C211B);border-radius:6px;padding:1px 6px;color:var(--amber,#FFB02E)} +@media(max-width:600px){.seotable{font-size:13.5px}.seotable th,.seotable td{padding:11px 14px}} + +/* Un
hijo directo de un en flex (caso de /contacto/) hereda + `min-width:auto` como ítem flex y NO encoge por debajo del ancho mínimo de + su contenido: la tabla de datos (min-width 520px) estiraba el main a 569px + a 375px de ancho y la página se desplazaba en horizontal. Medido en la + pasada de los 26 puntos. `min-width:0` es inocuo en los bodies no-flex. */ +body > main{min-width:0} + +/* ── Secciones insertadas por los scripts de SEO ───────────────────────── + Van marcadas con `.seosec` porque las 18 páginas NO comparten hoja: la + home y /contacto/ no cargan `core.css`, así que allí `.center` no + centraba y `h2` heredaba el estilo de etiqueta de `index.css` (13px, + mayúsculas, letter-spacing 4px). Con una definición propia, estos + bloques se ven igual en todo el sitio. */ +.seosec{padding:72px 0} +.seosec .center{text-align:center;max-width:680px;margin-left:auto;margin-right:auto} +.seosec .center .eye{display:block;font-size:13px;font-weight:600;letter-spacing:3px; + text-transform:uppercase;color:var(--amber,#FFB02E);margin-bottom:10px} +.seosec h2{font-size:clamp(28px,4vw,38px);font-weight:800;letter-spacing:-.8px; + text-transform:none;line-height:1.15;color:var(--bone,#EFE7DC)} +/* El h2 del TL;DR es el rótulo pequeño del propio recuadro, no un titular. */ +.seosec .tldr h2{font-size:13px;font-weight:700;letter-spacing:1.6px; + text-transform:uppercase;color:var(--amber,#FFB02E)} +@media(max-width:600px){.seosec{padding:52px 0}} diff --git a/assets/shared.js b/assets/shared.js index 9c6a168..d265efe 100644 --- a/assets/shared.js +++ b/assets/shared.js @@ -414,3 +414,74 @@ } rafId=requestAnimationFrame(tick); // store the id: a hide/show before the first tick must not fork a second chain })(); + +/* ============================================================ + Botón de compartir (punto 22 del checklist SEO). + Progresivo: navigator.share donde exista (móvil y Safari), + copia al portapapeles como respaldo. Sin dependencias y sin + ninguna red social embebida — no cargamos scripts de terceros + porque la CSP del sitio es `script-src 'self'`. + ============================================================ */ +(function(){ + var boxes=document.querySelectorAll('.fv-share'); + if(!boxes.length) return; + var isEN=function(){ return document.documentElement.lang==='en'; }; + [].forEach.call(boxes,function(box){ + var btn=box.querySelector('.sharebtn'); + var msg=box.querySelector('.sharemsg'); + if(!btn) return; + btn.addEventListener('click',function(){ + var url=(document.querySelector('link[rel=canonical]')||{}).href||location.href; + var title=document.title; + var say=function(t){ if(!msg) return; msg.textContent=t; msg.classList.add('on'); + clearTimeout(msg._t); msg._t=setTimeout(function(){ msg.classList.remove('on'); },2600); }; + if(navigator.share){ + navigator.share({title:title,url:url}).catch(function(){ /* el usuario canceló */ }); + return; + } + var done=function(){ say(isEN()?'Link copied':'Enlace copiado'); }; + var fail=function(){ say(isEN()?'Copy it from the address bar':'Cópialo de la barra de direcciones'); }; + /* Respaldo con textarea + execCommand. Sigue haciendo falta: la API + moderna `clipboard.writeText` rechaza con NotAllowedError en más + situaciones de las que parece (permiso denegado, iframes sin + allow="clipboard-write", contextos automatizados). Medido: en ese + mismo caso execCommand('copy') SÍ copia, así que se intenta después + del rechazo, no sólo cuando la API no existe. */ + var legacy=function(){ + try{ + var ta=document.createElement('textarea'); + ta.value=url; ta.setAttribute('readonly',''); ta.className='vh'; + document.body.appendChild(ta); + ta.select(); ta.setSelectionRange(0,ta.value.length); + var ok=document.execCommand('copy'); + document.body.removeChild(ta); + ok?done():fail(); + }catch(e){ fail(); } + }; + if(navigator.clipboard&&navigator.clipboard.writeText){ + navigator.clipboard.writeText(url).then(done,legacy); + }else{ + legacy(); + } + }); + }); +})(); + +/* ============================================================ + CTA fijo en móvil (punto 21). + La barra ya viene en el HTML de cada página (para que exista + sin JS); aquí sólo la ocultamos mientras el CTA principal del + hero está a la vista, para no duplicar el mismo botón en + pantalla, y la devolvemos al hacer scroll. + ============================================================ */ +(function(){ + var bar=document.querySelector('.stickycta'); + if(!bar) return; + var heroCta=document.querySelector('.hero .btn-fire'); + if(!heroCta||!('IntersectionObserver' in window)) return; + var io=new IntersectionObserver(function(entries){ + bar.style.transform=entries[0].isIntersecting?'translateY(110%)':'translateY(0)'; + },{threshold:0}); + bar.style.transition='transform .22s ease'; + io.observe(heroCta); +})(); diff --git a/claudescope/index.html b/claudescope/index.html index 2db9d3d..157bd9b 100644 --- a/claudescope/index.html +++ b/claudescope/index.html @@ -36,6 +36,47 @@ } + + @@ -120,6 +161,24 @@

+
+
+

En 30 segundos

+
    +
  • ClaudeScope da búsqueda full-text sobre todas las sesiones de Claude Code que has corrido.
  • +
  • Añade el panel de uso que la suscripción no te enseña: tokens, coste y lo que te ahorró la caché.
  • +
  • 100% local: lee los ficheros de sesión de tu disco. No sube nada y no pide API key.
  • +
  • Un solo comando y gratis: npx claudescope-cli. Open source.
  • +
+ +
+
+
Demo @@ -242,8 +301,106 @@

+
+
+ FAQ +

Preguntas frecuentes

+
+
+
+ ¿ClaudeScope sube mis sesiones a algún sitio? +

No. Lee los ficheros de sesión que Claude Code ya guarda en tu disco y monta el índice y el panel en tu propia máquina. No hay servidor, no hay cuenta y no hay API key.

+
+
+ ¿Hay que instalar algo? +

No hace falta instalación permanente: con npx claudescope-cli se ejecuta directamente. Solo necesitas Node.js.

+
+
+ ¿Qué puedo buscar exactamente? +

El texto completo de las conversaciones: tus mensajes, las respuestas y las llamadas a herramientas. Sirve justo para lo que uno hace a mano y mal: recordar en qué sesión resolviste un problema concreto.

+
+
+ ¿Cuánto cuesta? +

Nada. Es gratis y open source, sin tier de pago ni límite de uso. El código está en GitHub.

+
+
+
+

+ + + +
+
+
+ Ficha +

ClaudeScope de un vistazo

+
+
+ + + + + + + + + + + + + + + +
Precio, licencia, requisitos y tratamiento de datos de ClaudeScope.
DatoValor
PrecioGratis, sin tier de pago
LicenciaMIT (open source)
Cómo se ejecutanpx claudescope-cli
RequisitosNode.js
PlataformasWindows · macOS · Linux
Dónde correEn tu máquina, sobre los ficheros de sesión de tu disco
Cuenta o API keyNo hace falta ninguna
TelemetríaNinguna: no sube nada
+
+
+
+ + +
+ +

+ + +
+
+ ClaudeScope + Gratis y open source +
+ Empezar +
+
MIT © 2026 Jonathan Martín · GitHub ↗ diff --git a/contacto/index.html b/contacto/index.html index 39bb9d1..b8cd4f8 100644 --- a/contacto/index.html +++ b/contacto/index.html @@ -24,6 +24,55 @@ + + @@ -70,6 +119,24 @@

+
+
+

En 30 segundos

+
    +
  • Desarrollo a medida dirigiendo flotas de agentes de IA: del concepto al producto funcionando.
  • +
  • Precio por proyecto, con alcance cerrado antes de empezar. Nunca por horas.
  • +
  • El código entregado es tuyo, documentado y traspasado. Sin dependencia de mí ni de ninguna plataforma.
  • +
  • Hablas directamente conmigo. Remoto desde España (CET), con clientes en cualquier huso horario.
  • +
+ +
+
+ +

Qué puedo construir

@@ -93,22 +160,22 @@

Cómo trabajo

1 -

Hablamos

+

Hablamos

Me cuentas el problema. Sin compromiso y sin intermediarios — me hablas a mí.

2 -

Propuesta clara

+

Propuesta clara

Alcance, plazos y precio cerrado, acordados antes de empezar a trabajar.

3 -

Construyo con flotas de IA

+

Construyo con flotas de IA

Dirijo agentes autónomos para ir de la idea al producto en tiempo récord, sin pausa.

4 -

Entrega y soporte

+

Entrega y soporte

Tu código, documentado y tuyo. Te acompaño también después del lanzamiento.

@@ -120,19 +187,19 @@

Por qué trabajar conmigo

Un estudio que entrega como un equipo, llevado por una persona a la que puedes llegar.

-

Velocidad real

+

Velocidad real

Flotas de agentes trabajando en paralelo y sin pausa — lo que antes era cosa de un equipo entero sale en días.

-

Local-first y privado

+

Local-first y privado

Tu código y tus datos se quedan donde deben. La inferencia puede correr incluso en modelos locales, a coste $0.

-

Producto, no horas

+

Producto, no horas

Recibes algo que funciona, con alcance y precio cerrados — no una factura por horas.

-

Hablas conmigo

+

Hablas conmigo

Sin gestores de cuenta ni capa comercial. Quien lo construye es quien te responde.

@@ -186,8 +253,78 @@

Preguntas frecuentes

+ + + +
+
+
+ Condiciones +

Cómo es trabajar conmigo

+
+
+ + + + + + + + + + + + + + + +
Condiciones de un encargo de desarrollo a medida con Fervon.
ConceptoCómo funciona
PrecioPor proyecto, cerrado antes de empezar. Nunca por horas.
AlcanceAcordado por escrito antes de que arranque nada
Propiedad del códigoTuya. Documentado y traspasado, sin dependencia de mí ni de ninguna plataforma.
Con quién hablasConmigo, directamente. No hay intermediarios ni comerciales.
Dónde estoyRemoto desde España (CET), con clientes en cualquier huso horario
Forma de trabajoAsíncrono por defecto; llamadas cuando ayudan
StackTypeScript/Node · React · Python · SQLite/Postgres · LLM (Claude + llama.cpp)
IdiomasEspañol e inglés
+
+
+
+ + +
+ +
+ + +
+
+ Cuéntame tu proyecto + Respuesta directa, sin intermediarios +
+ Escribir +
+
+ + +
+
+ Fervon + Software a medida con agentes +
+ Hablemos +
+