sitio: la portada de la forja clavada arriba, y las cuatro secciones como pestañas que se vuelven el menú
El mismo lenguaje que gioser.net y tawasuyu.net. La portada es la forja de los pingüinos (among.webp, 179 KB) clavada arriba, con el nombre y el lema sobre vidrio y sin botones; el cuerpo sube por encima y el fondo vivo va adentro de él. La franja no es barra hasta que hace falta: el símbolo tocapu sube desde la portada con el primer scroll, y cuando las pestañas de las cuatro secciones (descargar, decisiones, componentes, código) llegan arriba, se encogen y se acomodan en ella. Elegir una muestra su sección; un ancla (#codigo) abre la suya; sin JS se ven las cuatro. Sale la perilla de tema: oscuro de fábrica, claro si el navegador lo pide (y ya no se lee el tema guardado, que lo pisaba). El idioma es un interruptor con la misma clave de siempre. El contenido de las cuatro secciones no cambia: el selector de variantes, los pesos y los botones de copiar siguen iguales. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Semantic delta
No definition changed: this change is text, documentation or data.
2 files · +189 −38
- web/takana-os.net/among.webp +— −—
- web/takana-os.net/index.html +189 −38
diff --git a/web/takana-os.net/among.webp b/web/takana-os.net/among.webp
new file mode 100644
index 00000000..4931f946
Binary files /dev/null and b/web/takana-os.net/among.webp differ
diff --git a/web/takana-os.net/index.html b/web/takana-os.net/index.html
index 08d72477..2f3a239d 100644
--- a/web/takana-os.net/index.html
+++ b/web/takana-os.net/index.html
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>takana — la forja determinista</title>
<meta name="description" content="Una distribución de Linux con dos pisos: un laboratorio hermético que compila todo desde fuente y direcciona por hash, y un Linux clásico y mutable encima.">
-<meta name="color-scheme" content="light dark">
+<meta name="color-scheme" content="dark light">
<link rel="icon" href="simbolo.svg" type="image/svg+xml">
<link rel="stylesheet" href="fuentes.css">
<meta property="og:title" content="takana — la forja determinista">
@@ -27,7 +27,7 @@
--sans:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
--mono:"IBM Plex Mono",ui-monospace,"DejaVu Sans Mono",monospace;
color-scheme:light}
-@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
+@media not all and (prefers-color-scheme:light){:root{
--chispa:#FFF6DE;
--fondo:#17130E;--papel:#1D1813;--papel2:#2A241B;--linea:#332B21;--linea2:#4A3F30;
--texto:#F2EBDD;--tenue:#B8AB95;--debil:#9C907B;
@@ -59,9 +59,9 @@
sobre la obsidiana; en claro eso lavaría todo a blanco, así que ahí se usa `multiply` con muy
poca fuerza y queda un tinte, no una mancha. */
:root{--mezcla:multiply;--fuerza:.16}
-@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--mezcla:screen;--fuerza:.52}}
+@media not all and (prefers-color-scheme:light){:root{--mezcla:screen;--fuerza:.52}}
:root[data-theme="dark"]{--mezcla:screen;--fuerza:.52}
-.aurora{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
+.aurora{position:sticky;top:0;height:100vh;margin-bottom:-100vh;z-index:0;pointer-events:none;overflow:hidden;
contain:strict}
.aurora i{position:absolute;display:block;top:50%;left:50%;
width:78vmax;height:78vmax;margin:-39vmax 0 0 -39vmax;border-radius:50%;
@@ -280,11 +280,83 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
.pie-rejilla p{font-size:.84rem;color:var(--debil);margin:0}
.pie-fin{margin-top:2rem;font-size:.8rem;color:var(--debil)}
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
+
+/* ── la franja, la portada y las pestañas (2026-10-13) ──────────────────────────────────────────
+ El mismo lenguaje que gioser.net y tawasuyu.net: la portada queda clavada arriba y el cuerpo sube
+ por encima; la franja no es barra hasta que hace falta —el símbolo sube desde la portada con el
+ primer scroll— y su menú son las cuatro pestañas de las secciones, que se encogen y se acomodan
+ en ella al llegar arriba (el guion les mueve `--p` de 0 a 1). Sin perilla de tema: oscuro de
+ fábrica, claro si el navegador lo pide. Clases con `t-` para no chocar con las de la página. */
+:root{--t-franja:64px;--t-vidrio:rgba(23,19,14,.74)}
+@media (prefers-color-scheme:light){:root{--t-vidrio:rgba(242,235,221,.82)}}
+.t-franja{position:fixed;top:0;left:0;right:0;z-index:60;height:var(--t-franja);display:flex;
+ align-items:center;gap:1rem;padding:0 clamp(1rem,4vw,2.5rem);color:var(--texto);pointer-events:none;
+ transition:color .35s}
+.t-franja.sobre-portada{color:#F2EBDD}
+.t-franja>*{pointer-events:auto}
+.t-marca{display:flex;align-items:center;gap:.6rem;font:900 .95rem/1 var(--display);letter-spacing:.06em;
+ text-transform:uppercase}
+.t-marca .simbolo{width:28px;transform-origin:0 0;will-change:transform}
+.t-marca-nombre{opacity:0;transition:opacity .3s}
+.t-franja.llego .t-marca-nombre{opacity:1}
+html:not(.js) .t-marca-nombre{opacity:1}
+html.js .t-tarjeta .titular .simbolo{visibility:hidden}
+.t-glifos{margin-left:auto;display:flex;align-items:center;gap:.5rem}
+.t-glifo{display:grid;place-items:center;width:34px;height:34px;border-radius:99px;border:1px solid currentColor;
+ background:none;color:inherit;cursor:pointer;opacity:.85;font:500 .76rem/1 var(--mono);letter-spacing:.08em;
+ transition:opacity .2s,color .2s}
+.t-glifo svg{width:17px;height:17px}
+.t-glifo:hover{opacity:1;color:var(--acento)}
+.t-glifo.idioma{width:auto;padding:0 .75rem}
+.t-portada-fondo{position:fixed;inset:0;z-index:0;overflow:hidden;background:#17130E}
+.t-portada-fondo img{display:block;width:100%;height:100%;object-fit:cover;object-position:62% 45%}
+.t-portada-fondo::after{content:"";position:absolute;inset:0;
+ background:linear-gradient(to bottom,rgba(10,8,6,.5),rgba(10,8,6,0) 20%),
+ linear-gradient(to top,rgba(10,8,6,.78),rgba(10,8,6,0) 45%)}
+.t-portada{position:relative;z-index:1;min-height:100svh;display:flex;align-items:flex-end;
+ padding:0 clamp(1rem,5vw,3rem) clamp(3rem,10vh,6.5rem)}
+.t-tarjeta{max-width:40rem;color:#F2EBDD;padding:clamp(1.1rem,3vw,1.8rem) clamp(1.2rem,3.5vw,2.2rem);
+ border-radius:22px;background:rgba(14,11,8,.5);border:1px solid rgba(255,255,255,.09);
+ backdrop-filter:blur(14px) saturate(1.25);-webkit-backdrop-filter:blur(14px) saturate(1.25);
+ box-shadow:0 20px 60px rgba(0,0,0,.35)}
+.t-tarjeta .antetitulo{color:#E3A63D}
+.t-tarjeta .lema{color:rgba(242,235,221,.9);margin:0}
+.t-cuerpo{position:relative;z-index:2;background:var(--fondo);box-shadow:0 -40px 80px rgba(0,0,0,.35)}
+.t-cuerpo>section,.t-cuerpo>footer{position:relative;z-index:1}
+.t-cuerpo>footer.pie{background:color-mix(in srgb,var(--papel) 85%,transparent)}
+
+.t-tabs{position:sticky;top:var(--t-tabs-top,0px);z-index:61;display:flex;justify-content:center;gap:.4rem;
+ max-width:840px;margin:0 auto;padding:2.6rem 1.5rem .9rem;pointer-events:none;--p:0}
+.t-tabs::before{content:"";position:absolute;left:50%;bottom:0;width:100vw;height:var(--t-franja);
+ transform:translateX(-50%);background:var(--t-vidrio);backdrop-filter:blur(14px) saturate(1.3);
+ -webkit-backdrop-filter:blur(14px) saturate(1.3);border-bottom:1px solid var(--linea);opacity:var(--p);z-index:-1}
+.t-tab{pointer-events:auto;position:relative;isolation:isolate;appearance:none;cursor:pointer;display:inline-flex;
+ align-items:center;gap:.45rem;white-space:nowrap;padding:.55rem .95rem;border-radius:99px;
+ border:1px solid color-mix(in srgb,var(--linea2) calc((1 - var(--p)) * 100%),transparent);
+ background:color-mix(in srgb,var(--papel) calc((1 - var(--p)) * 85%),transparent);
+ color:var(--tenue);font:600 .9rem/1 var(--sans);will-change:transform;transition:color .2s}
+.t-tab:hover{color:var(--texto)}
+.t-tab[aria-selected="true"]{color:var(--texto);
+ background:color-mix(in srgb,var(--acento) calc((1 - var(--p)) * 18%),transparent);
+ border-color:color-mix(in srgb,var(--acento) calc((1 - var(--p)) * 60%),transparent)}
+.t-tab svg{width:17px;height:17px;flex:none;color:var(--acento);opacity:calc(1 - var(--p) * 1.6)}
+.t-tab .rot{position:relative}
+.t-tab .rot::before{content:"";position:absolute;inset:-.42em -.85em;border-radius:99px;z-index:-1;
+ background:color-mix(in srgb,var(--acento) 22%,transparent);opacity:0}
+.t-tab[aria-selected="true"] .rot::before{opacity:var(--p)}
+.t-tab:focus-visible{outline:2px solid var(--acento);outline-offset:2px}
+html.js .t-panel:not(.activo){display:none}
+html.js .t-panel.activo{animation:t-entra .4s ease both}
+@keyframes t-entra{from{opacity:0;transform:translateY(10px)}}
+.t-panel.franja{border-top:0;padding-top:1.4rem}
+@media(max-width:720px){
+ .t-tabs{justify-content:flex-start;overflow-x:auto;scrollbar-width:none;gap:.3rem}
+ .t-tabs::-webkit-scrollbar{display:none}
+ .t-tab{padding:.5rem .7rem;font-size:.82rem}
+ .t-franja.con-menu .t-marca-nombre{opacity:0}}
</style>
</head>
<body>
-<!-- El fondo vivo. `aria-hidden` porque no dice nada: es color. -->
-<div class="aurora" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></div>
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<symbol id="tocapu" viewBox="0 0 748 748">
@@ -314,22 +386,17 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
</symbol>
</svg>
-<header class="barra"><div class="envoltura">
- <a class="marca" href="/"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg>takana</a>
- <nav class="enlaces">
- <a href="#descargar"><span data-l="es">Descargar</span><span data-l="en">Download</span></a>
- <a href="#decisiones"><span data-l="es">Las decisiones</span><span data-l="en">The decisions</span></a>
- <a href="#componentes"><span data-l="es">Los componentes</span><span data-l="en">Components</span></a>
- <a href="#codigo"><span data-l="es">El código</span><span data-l="en">The code</span></a>
- </nav>
- <div class="perillas">
- <button class="perilla" data-poner-lang="es">ES</button>
- <button class="perilla" data-poner-lang="en">EN</button>
- <button class="perilla" id="tema" title="tema">◐</button>
+<header class="t-franja sobre-portada" id="t-franja">
+ <a class="t-marca" href="#" id="t-marca" aria-label="takana"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg><span class="t-marca-nombre">takana</span></a>
+ <div class="t-glifos" id="t-glifos">
+ <a class="t-glifo" href="https://git.gioser.net/sergio/takana" title="git.gioser.net/sergio/takana" aria-label="repositorio / repository"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18 3 12l6-6M15 6l6 6-6 6"/></svg></a>
+ <button class="t-glifo idioma" type="button" id="t-idioma" aria-label="English / español"><span data-l="es" lang="en">EN</span><span data-l="en" lang="es">ES</span></button>
</div>
-</div></header>
+</header>
-<section class="portada"><div class="fragua" aria-hidden="true"></div><div class="envoltura">
+<div class="t-portada-fondo" aria-hidden="true"><img src="among.webp" alt="" fetchpriority="high"></div>
+
+<section class="t-portada"><div class="t-tarjeta">
<p class="antetitulo"><span data-l="es">takana · el martillo</span><span data-l="en">takana · the hammer</span></p>
<div class="titular">
<svg class="simbolo" viewBox="0 0 748 748" aria-hidden="true"><use href="#tocapu"/></svg>
@@ -339,14 +406,14 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
<span data-l="es">Un Linux mutable que puedes romper y recuperar, manteniendo su pureza hasta el último bit.</span>
<span data-l="en">A mutable Linux you can break and recover, its purity intact down to the last bit.</span>
</p>
- <div class="botones">
- <a class="boton lleno" href="#descargar"><span data-l="es">Descargar</span><span data-l="en">Download</span></a>
- <a class="boton" href="#codigo"><span data-l="es">El repositorio</span><span data-l="en">The repository</span></a>
- <a class="boton" href="https://tawasuyu.net">tawasuyu.net ↗</a>
- </div>
</div></section>
-<section class="franja" id="descargar"><div class="envoltura">
+<div class="t-cuerpo">
+<!-- El fondo vivo. `aria-hidden` porque no dice nada: es color. -->
+<div class="aurora" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></div>
+<div class="t-tabs" id="t-tabs" role="tablist" aria-label="secciones / sections"><button class="t-tab" role="tab" type="button" id="tab-descargar" data-tab="descargar" aria-controls="descargar" aria-selected="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4v11M7 11l5 5 5-5M5 20h14"/></svg><span class="rot"><span data-l="es">Descargar</span><span data-l="en">Download</span></span></button><button class="t-tab" role="tab" type="button" id="tab-decisiones" data-tab="decisiones" aria-controls="decisiones" aria-selected="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v18M5 7h14"/><path d="M8 7 5 13h6zM16 7l-3 6h6z"/></svg><span class="rot"><span data-l="es">Las decisiones</span><span data-l="en">The decisions</span></span></button><button class="t-tab" role="tab" type="button" id="tab-componentes" data-tab="componentes" aria-controls="componentes" aria-selected="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 3 8 4.5v9L12 21l-8-4.5v-9z"/><path d="m4 7.5 8 4.5 8-4.5M12 12v9"/></svg><span class="rot"><span data-l="es">Los componentes</span><span data-l="en">Components</span></span></button><button class="t-tab" role="tab" type="button" id="tab-codigo" data-tab="codigo" aria-controls="codigo" aria-selected="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18 3 12l6-6M15 6l6 6-6 6"/></svg><span class="rot"><span data-l="es">El código</span><span data-l="en">The code</span></span></button></div>
+
+<section class="franja t-panel activo" id="descargar" role="tabpanel" aria-labelledby="tab-descargar"><div class="envoltura">
<p class="sello"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg><span data-l="es">01 · descargar</span><span data-l="en">01 · download</span></p>
<h2><span data-l="es">Descargar</span><span data-l="en">Download</span></h2>
@@ -397,7 +464,7 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
<noscript><p class="nota"><span data-l="es">Las descargas se arman con JavaScript. Sin él: takana-os.net/descargas/</span><span data-l="en">Downloads are assembled with JavaScript. Without it: takana-os.net/descargas/</span></p></noscript>
</div></section>
-<section class="franja" id="decisiones"><div class="envoltura">
+<section class="franja t-panel" id="decisiones" role="tabpanel" aria-labelledby="tab-decisiones"><div class="envoltura">
<p class="sello"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg><span data-l="es">02 · las decisiones</span><span data-l="en">02 · the decisions</span></p>
<h2><span data-l="es">Trece decisiones, y contra qué se tomaron</span><span data-l="en">Thirteen decisions, and what they were taken against</span></h2>
<p>
@@ -618,7 +685,7 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
</div>
</div></section>
-<section class="franja" id="componentes"><div class="envoltura">
+<section class="franja t-panel" id="componentes" role="tabpanel" aria-labelledby="tab-componentes"><div class="envoltura">
<p class="sello"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg><span data-l="es">03 · los componentes</span><span data-l="en">03 · the components</span></p>
<h2><span data-l="es">Qué lleva dentro</span><span data-l="en">What is inside</span></h2>
@@ -692,7 +759,7 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
</p>
</div></section>
-<section class="franja" id="codigo"><div class="envoltura">
+<section class="franja t-panel" id="codigo" role="tabpanel" aria-labelledby="tab-codigo"><div class="envoltura">
<p class="sello"><svg class="simbolo" viewBox="0 0 748 748"><use href="#tocapu"/></svg><span data-l="es">04 · el código</span><span data-l="en">04 · the code</span></p>
<h2><span data-l="es">Dónde vive y cómo se llama</span><span data-l="en">Where it lives and how it is called</span></h2>
@@ -762,6 +829,7 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
<span data-l="en">takana · MIT licence · this page is served from the repository itself (<code>web/takana-os.net/</code>) and asks nothing of third parties: the typefaces — Chivo and IBM Plex, both SIL OFL — travel with it.</span>
</p>
</div></footer>
+</div>
<script>
(function(){
@@ -774,12 +842,13 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
r.setAttribute('lang', l);
}
try{ var g=localStorage.getItem('takana-lang'); if(g) r.dataset.lang=g;
- var t=localStorage.getItem('takana-tema'); if(t) r.dataset.theme=t; }catch(e){}
+ }catch(e){}
if(!r.dataset.lang) r.dataset.lang = (navigator.language||'es').slice(0,2)==='es' ? 'es' : 'en';
pintar();
- document.querySelectorAll('[data-poner-lang]').forEach(function(b){
+ var bIdioma=document.getElementById('t-idioma');
+ if (bIdioma) [bIdioma].forEach(function(b){
b.addEventListener('click', function(){
- r.dataset.lang=b.dataset.ponerLang; pintar();
+ r.dataset.lang = r.dataset.lang==='es' ? 'en' : 'es'; pintar();
if(SEL) pinta(vAhora); // la coma decimal del peso cambia con el idioma
try{ localStorage.setItem('takana-lang', r.dataset.lang); }catch(e){}
});
@@ -871,12 +940,6 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
c.appendChild(b);
});
- document.getElementById('tema').addEventListener('click', function(){
- var oscuro = r.dataset.theme ? r.dataset.theme==='dark'
- : matchMedia('(prefers-color-scheme:dark)').matches;
- r.dataset.theme = oscuro ? 'light' : 'dark';
- try{ localStorage.setItem('takana-tema', r.dataset.theme); }catch(e){}
- });
})();
/* ── el fondo vivo: elegir destinos, no pintar cuadros ─────────────────────────────────────────
@@ -939,5 +1002,93 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
});
})();
</script>
+<script>
+/* ── la franja y las pestañas (2026-10-13) ──────────────────────────────────────────────────────
+ El símbolo sube desde la portada con el primer scroll y se planta en la franja; cuando las
+ pestañas de las secciones llegan arriba, se encogen y se acomodan en ella: el menú son ellas.
+ Elegir una muestra su sección; sin JS se ven las cuatro, una abajo de otra. */
+(function(){
+ var r=document.documentElement, quieto=matchMedia('(prefers-reduced-motion: reduce)').matches;
+ r.classList.add('js');
+ var franja=document.getElementById('t-franja'), marca=document.querySelector('#t-marca .simbolo'),
+ grande=document.querySelector('.t-tarjeta .titular .simbolo'), glifos=document.getElementById('t-glifos'),
+ cuerpo=document.querySelector('.t-cuerpo'), barra=document.getElementById('t-tabs'),
+ tabs=[].slice.call(document.querySelectorAll('.t-tab')), tarjeta=document.querySelector('.t-tarjeta');
+ if(!franja||!barra||!cuerpo) return;
+ var suave=function(t){return t*t*(3-2*t)}, RAMPA=90, geo=null, menu=null, p=0;
+
+ function medir(){
+ var s=scrollY, alto=franja.offsetHeight;
+ if(marca&&grande){ marca.style.transform='none';
+ var h=grande.getBoundingClientRect(), b=marca.getBoundingClientRect();
+ geo={hx:h.left,hy:h.top+s,hw:h.width,bx:b.left,by:b.top,bw:b.width}; }
+ barra.style.setProperty('--p',0); tabs.forEach(function(t){t.style.transform='none'});
+ var top=alto-barra.offsetHeight; barra.style.setProperty('--t-tabs-top',top+'px');
+ // las pestañas son lo primero del cuerpo (el fondo vivo no ocupa lugar); un sticky reporta su
+ // posición pegada, así que se mide desde el cuerpo
+ var docTop=s+cuerpo.getBoundingClientRect().top, br=barra.getBoundingClientRect();
+ var rot=tabs.map(function(t){ var l=t.querySelector('.rot').getBoundingClientRect(), b=t.getBoundingClientRect();
+ return {cx:l.left+l.width/2,w:l.width,cy:l.top+l.height/2-br.top,ox:l.left+l.width/2-b.left,oy:l.top+l.height/2-b.top}; });
+ var izq=(marca?marca.getBoundingClientRect().right:0)+(innerWidth<720?14:110),
+ der=(glifos?glifos.getBoundingClientRect().left:innerWidth)-14, gap=innerWidth<720?12:22,
+ suma=rot.reduce(function(a,l){return a+l.w},0),
+ k=Math.max(.55,Math.min(.92,(der-izq-gap*(rot.length-1))/suma)), total=suma*k+gap*(rot.length-1),
+ x0=innerWidth/2-total/2;
+ if(x0<izq) x0=izq; if(x0+total>der) x0=Math.max(izq,der-total);
+ var x=x0; rot.forEach(function(l){ l.dx=x+l.w*k/2-l.cx; x+=l.w*k+gap; });
+ menu={alto:alto,top:top,pegado:docTop-top,rot:rot,k:k};
+ tabs.forEach(function(t,i){ t.style.transformOrigin=rot[i].ox+'px '+rot[i].oy+'px'; });
+ }
+ function volar(s){ if(!geo) return;
+ var t=Math.min(1,Math.max(0,s/Math.max(1,geo.hy-geo.by))), e=suave(t),
+ x=geo.hx+(geo.bx-geo.hx)*e, y=Math.max(geo.by,geo.hy-s), k=geo.hw/geo.bw+(1-geo.hw/geo.bw)*e;
+ marca.style.transform='translate('+(x-geo.bx).toFixed(1)+'px,'+(y-geo.by).toFixed(1)+'px) scale('+k.toFixed(3)+')';
+ franja.classList.toggle('llego',t>.98); }
+ function encoger(s){ if(!menu) return;
+ var t=Math.min(1,Math.max(0,(s-(menu.pegado-RAMPA))/RAMPA)); p=suave(t);
+ barra.style.setProperty('--p',p.toFixed(3));
+ var falta=Math.max(0,menu.pegado-s);
+ tabs.forEach(function(tab,i){ var l=menu.rot[i], dy=menu.alto/2-(menu.top+l.cy+falta), k=1-(1-menu.k)*p;
+ tab.style.transform = p===0 ? 'none' : 'translate('+(l.dx*p).toFixed(1)+'px,'+(dy*p).toFixed(1)+'px) scale('+k.toFixed(3)+')'; });
+ franja.classList.toggle('con-menu',p>.5); }
+ var tick=false;
+ function pintar(){ tick=false; var s=scrollY, alto=franja.offsetHeight; volar(s); encoger(s);
+ if(tarjeta){ var tp=tarjeta.getBoundingClientRect().top; tarjeta.style.opacity=Math.min(1,Math.max(0,(tp-alto)/(alto*1.5))).toFixed(3); }
+ franja.classList.toggle('sobre-portada', cuerpo.getBoundingClientRect().top>alto); }
+ addEventListener('scroll',function(){ if(!tick){tick=true;requestAnimationFrame(pintar)} },{passive:true});
+ addEventListener('resize',function(){medir();pintar()},{passive:true});
+ medir(); pintar();
+ if(document.fonts&&document.fonts.ready) document.fonts.ready.then(function(){medir();pintar()});
+ document.getElementById('t-marca').addEventListener('click',function(e){ e.preventDefault(); scrollTo({top:0,behavior:quieto?'auto':'smooth'}); });
+
+ function elegir(id, foco){
+ // sin un id que sea de una pestaña no se toca nada (al cargar sin ancla, «Descargar» queda)
+ if(!tabs.some(function(t){return t.dataset.tab===id})) return false;
+ var hay=false;
+ tabs.forEach(function(t){ var on=t.dataset.tab===id; if(on) hay=true;
+ t.setAttribute('aria-selected',String(on)); t.tabIndex=on?0:-1;
+ var panel=document.getElementById(t.dataset.tab); if(panel) panel.classList.toggle('activo',on);
+ if(on&&foco) t.focus(); });
+ if(hay) try{ history.replaceState(null,'','#'+id); }catch(e){}
+ return hay;
+ }
+ tabs.forEach(function(t,i){
+ t.tabIndex = t.getAttribute('aria-selected')==='true' ? 0 : -1;
+ t.addEventListener('click',function(){ var comoMenu=p>.5; elegir(t.dataset.tab);
+ if(comoMenu&&menu) scrollTo({top:Math.round(menu.pegado),behavior:quieto?'auto':'smooth'}); });
+ t.addEventListener('keydown',function(e){ var n=tabs.length,
+ j=e.key==='ArrowRight'?(i+1)%n:e.key==='ArrowLeft'?(i-1+n)%n:e.key==='Home'?0:e.key==='End'?n-1:-1;
+ if(j>=0){ e.preventDefault(); elegir(tabs[j].dataset.tab,true); } });
+ });
+ // un enlace con ancla a una sección (#codigo, #descargar…) abre esa pestaña
+ var pedido=decodeURIComponent((location.hash||'').slice(1));
+ if(elegir(pedido)&&menu) scrollTo({top:Math.round(menu.pegado)});
+ addEventListener('hashchange',function(){ var id=decodeURIComponent((location.hash||'').slice(1));
+ if(elegir(id)&&menu) scrollTo({top:Math.round(menu.pegado),behavior:quieto?'auto':'smooth'}); });
+ document.addEventListener('click',function(e){ var a=e.target.closest('a[href^="#"]'); if(!a) return;
+ var id=a.getAttribute('href').slice(1); if(tabs.some(function(t){return t.dataset.tab===id})){
+ e.preventDefault(); elegir(id); if(menu) scrollTo({top:Math.round(menu.pegado),behavior:quieto?'auto':'smooth'}); } });
+})();
+</script>
</body>
</html>