/* ═══════════════════════════════════════════════════════════════════════════
   SpartanDev — hoja de estilo del sitio entero
   Dirección: «expediente técnico». 28-sep-2026.

   El sitio se presenta como lo presenta su propia herramienta de auditoría:
   una afirmación, la prueba que la sostiene y la fecha en que se verificó.
   No es una landing con capturas; es un dossier con pruebas adjuntas.

   🔴 POR QUÉ SE REHIZO. El diseño anterior cumplía nueve de los nueve rasgos
   con los que se delata una página generada: una sola palabra del titular en
   otro color, etiquetas en versalitas con tracking, monoespaciada decorativa
   (15 usos), numerado 01/02/03 sobre contenido que NO es una secuencia, puntos
   medios como separador, catorce flechas «↗» pegadas al texto, negro teñido
   (#0e1114) en lugar de negro, y tarjetas con el mismo radio y la misma sombra.
   Ninguno de esos nueve vuelve a aparecer aquí. Si añades uno, lo estás
   devolviendo al punto de partida.

   🔑 LA PALETA SALE DE LA MARCA, medida con `palettegen` sobre `img/marca.webp`:
   negro #090609, carmesí #972324, plata #c1bfc1. La paleta anterior era
   turquesa y no aparecía en la identidad por ningún lado — ese era el motivo de
   fondo por el que se leía como plantilla.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  color-scheme:dark;

  /* El negro de la marca es negro DE VERDAD, no un gris muy oscuro. Da la
     casualidad de que eso esquiva el rasgo del «negro teñido» sin esfuerzo:
     aquí es fidelidad a la identidad, no una decisión estética. */
  --tinta:#0a0b0d;
  --plano:#181c1e;   /* superficie apenas elevada: monturas y desplegables */
  /* Un segundo negro, más claro, para los bloques de lectura. Es el recurso
     que usa YouTube: la caja de descripción y los comentarios no van sobre el
     fondo, van sobre un gris apenas levantado, y unas líneas finas separan y
     sangran el contenido. Neutro tirando a frío (210°) — NUNCA morado. */
  --plano2:#191a1c;
  --trama:#23262a;   /* filetes */
  --trama-viva:#383c42;

  /* El texto NO es blanco: es el plateado del casco. Un gris claro cálido
     sobre negro se lee como tinta sobre plancha, no como el tema oscuro de
     cualquier SaaS, que siempre tira de blanco roto. Medido: 11,03:1, AAA. */
  --plata:#c1bfc1;
  --grafito:#8a8b8e;   /* secundario — 5,92:1, AA */

  /* 🔴 EL CARMESÍ ES DE LA MARCA, NO DE LOS ESTADOS. Vive en el logo y en los
     avisos de las páginas legales, donde el rojo sí significa «ojo». No se usa
     como texto: sobre el negro da 2,48:1 y no pasa ni para texto grande.
     Hasta el 29-sep-2026 también teñía los sellos de estado, y se retiró por
     feedback externo: un «En producción» en rojo se lee como alerta. */
  --carmesi:#972324;
  --carmesi-vivo:#b02b2c;   /* filete de los avisos legales: 4,10:1 */

  /* Colores de ESTADO. Tienen que decir el estado sin leer la etiqueta, así
     que siguen la convención universal: verde es que funciona, ámbar es que
     espera. El ámbar es el mismo de la era 10 de BuzzBrew: ya era de la casa. */
  --vivo:#2e6b50;        /* macizo, texto claro encima 5,41:1 AA */
  --pendiente:#d6b78e;   /* perfilado, como texto 9,69:1 AA */
  --sobre-sello:#edeeec;

  /* Zilla Slab (OFL) para titulares: el logotipo ya lleva remates tipo slab, y
     es el registro de la documentación técnica y los sellos. Deliberadamente
     NO es la serif de alto contraste que sale por defecto en todo lo generado
     — por eso Zodiak se queda fuera del sitio nuevo. */
  --slab:ZillaSlab,'Bookman Old Style',Georgia,serif;
  --sans:Satoshi,'Segoe UI',system-ui,sans-serif;
  --mono:'Cascadia Code',Consolas,ui-monospace,monospace;

  --medida:38rem;     /* menos de 80 caracteres por línea */
  --canal:clamp(16px,4vw,40px);
}

/* Alias de transición: `legal.css` y la página del juego todavía nombran los
   tokens viejos. Apuntarlos aquí hace que hereden la paleta nueva sin tocar
   esos ficheros el mismo día. Se retiran cuando se rehagan esas páginas. */
:root{
  --bg:var(--tinta); --panel:var(--plano); --line:var(--trama);
  --text:var(--plata); --muted:var(--grafito); --font:var(--sans);
  --display:var(--slab); --cyan:var(--plata); --amber:var(--plata);
}

@font-face{font-family:Satoshi;src:url('/fonts/satoshi-400.woff2') format('woff2');font-weight:400;font-display:swap}
@font-face{font-family:Satoshi;src:url('/fonts/satoshi-500.woff2') format('woff2');font-weight:500;font-display:swap}
@font-face{font-family:Satoshi;src:url('/fonts/satoshi-700.woff2') format('woff2');font-weight:700;font-display:swap}
@font-face{font-family:ZillaSlab;src:url('/fonts/zillaslab-400.woff2') format('woff2');font-weight:400;font-display:swap}
@font-face{font-family:ZillaSlab;src:url('/fonts/zillaslab-600.woff2') format('woff2');font-weight:600;font-display:swap}
@font-face{font-family:ZillaSlab;src:url('/fonts/zillaslab-700.woff2') format('woff2');font-weight:700;font-display:swap}

/* ── Base ─────────────────────────────────────────────────────────────────── */
*{box-sizing:border-box}
/* Desplazamiento suave para los enlaces a una sección (#contacto). Quien pide
   menos movimiento lo tiene directo: el bloque de reduced-motion lo anula. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--tinta);color:var(--plata);
  font:400 1rem/1.7 var(--sans);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
img{max-width:100%;height:auto;display:block}
a{color:inherit;-webkit-tap-highlight-color:transparent}
button{-webkit-tap-highlight-color:transparent}

/* Foco visible y del mismo grosor en todo el sitio. Es plata y no carmesí
   porque el carmesí no llega al 3:1 que necesita un indicador. */
:where(a,button,summary,[tabindex]):focus-visible{
  outline:2px solid var(--plata);outline-offset:3px;border-radius:2px;
}

.wrap{width:min(1180px,100% - var(--canal)*2);margin-inline:auto}

.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--canal);top:12px;z-index:100;background:var(--plano);
  border:1px solid var(--trama-viva);padding:10px 16px;text-decoration:none}

/* ── Escala tipográfica ───────────────────────────────────────────────────── */
h1,h2,h3,h4{font-family:var(--slab);font-weight:600;line-height:1.15;margin:0;
  letter-spacing:-.005em}
h1{font-size:clamp(2.1rem,4.4vw,3.4rem)}
h2{font-size:clamp(1.6rem,3vw,2.3rem)}
h3{font-size:clamp(1.25rem,2.1vw,1.6rem)}
h4{font-size:1rem;font-weight:600}
p{margin:0 0 1.1rem;max-width:var(--medida)}

/* El dato real —fechas, recuentos, nombres de fichero— va en monoespaciada.
   Nada MÁS va en monoespaciada: usarla de adorno para etiquetas era uno de los
   rasgos que se está corrigiendo. Si el texto no es un dato, no lleva `.dato`. */
.dato{font:400 .8rem/1.5 var(--mono);color:var(--grafito);font-variant-numeric:tabular-nums}

/* ── Cabecera ─────────────────────────────────────────────────────────────── */
/* Rejilla con anchos reservados: al cambiar de idioma las opciones no se mueven,
   porque cada enlace reserva también el ancho de su etiqueta en el otro idioma
   con `::after`. Se resolvió así en su día y sigue siendo la forma correcta. */
header{
  display:grid;grid-template-columns:auto 1fr auto var(--boton-ancho,6.5rem);
  align-items:center;gap:0 24px;padding:22px 0;
  border-bottom:1px solid var(--trama);
}
.brand{display:flex;align-items:center;gap:11px;text-decoration:none;font-family:var(--slab);
  font-weight:700;font-size:1.05rem;letter-spacing:.02em}
.brand img{width:34px;height:34px}
header nav{display:flex;justify-self:end;width:var(--nav-ancho,13.5rem);
  justify-content:space-between;gap:16px}
header nav a{display:inline-grid;justify-items:center;text-decoration:none;
  color:var(--grafito);font-size:.9rem;padding-bottom:2px;
  border-bottom:1px solid transparent}
header nav a::after{content:attr(data-otro);height:0;overflow:hidden;
  visibility:hidden;pointer-events:none;font-weight:600}
header nav a:hover,header nav a[aria-current]{color:var(--plata);border-bottom-color:var(--plata)}

.lang-switch{display:flex;align-items:center;gap:7px;justify-self:end;
  color:var(--grafito);text-decoration:none;font:400 .8rem var(--mono)}
.lang-switch:hover{color:var(--plata)}
.lang-switch svg{width:14px;height:14px}

/* El botón principal es un rectángulo macizo de plata con tinta encima: es el
   único elemento «lleno» de la cabecera, así que no necesita ni color de acento
   ni flecha pegada al texto para destacar. */
.button{display:inline-flex;align-items:center;justify-content:center;
  background:var(--plata);color:var(--tinta);text-decoration:none;
  font-family:var(--slab);font-weight:600;font-size:.92rem;
  padding:11px 20px;border:1px solid var(--plata);
  transition:background-color .15s,color .15s}
.button:hover{background:transparent;color:var(--plata)}

/* ── Héroe ────────────────────────────────────────────────────────────────── */
/* El reparto es el de siempre: texto a la izquierda, marca a la derecha. Lo que
   cambia es el registro — sin palabra coloreada en el titular, sin flechas
   pegadas y sin versalitas. */
.hero{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(28px,5vw,64px);align-items:center;
  padding:clamp(40px,7vw,78px) 0 clamp(30px,5vw,52px);
  border-bottom:1px solid var(--trama)}

/* 🔑 El rótulo va en caja baja, sin tracking y sin monoespaciada. Ésas tres
   cosas juntas —VERSALITAS + letter-spacing + mono— eran lo que lo hacía leerse
   como plantilla, no el hecho de existir. La pieza se queda; el disfraz no. */
.eyebrow{color:var(--grafito);font-size:.88rem;margin:0 0 18px}

.hero h1{font-size:clamp(2.1rem,4.2vw,3.35rem);line-height:1.1}
.actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px 20px;margin-top:2rem}

/* La marca se monta igual que las pruebas: filete fino y plano por debajo. Así
   la portada y las piezas hablan el mismo idioma. */
.hero-art{display:flex;flex-direction:column;gap:14px}
.identity{border:1px solid var(--trama-viva);background:var(--plano);padding:10px}
.identity img{width:100%}

/* La fila de campos: tres áreas de trabajo. Sin numerar — no son una secuencia,
   y el «01 02 03» fingía un orden que no existe. Va bajo el titular, donde
   estaba la entradilla.
   🔑 Sin cajas, a cualquier ancho: una línea de texto con puntos entre áreas.
   Las cajas apiladas ocupaban ~130 px en un teléfono. Cada área va entera
   (nowrap) y el punto queda al final del renglón, nunca al principio. Va en la
   letra del texto y no en monoespaciada: la de Android es más ancha que la de
   Windows y partía la línea en tres; la Satoshi viaja con la web y mide igual
   en todas partes. */
.disciplines{margin:1.4rem 0 0;line-height:1.8;color:var(--grafito)}
.disciplines span,.disciplines li{white-space:nowrap;font:400 clamp(.86rem,1.2vw,.95rem) var(--sans)}
.disciplines span:not(:last-child)::after,
.disciplines li:not(:last-child)::after{content:' ·';margin-right:.45em;color:var(--trama-viva)}

/* El encabezado de sección lleva el rótulo y el titular a la izquierda y la
   entradilla a la derecha, como estaba. */
.section-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  gap:clamp(18px,4vw,52px);align-items:end;
  padding-top:clamp(46px,7vw,82px);margin-bottom:clamp(24px,3.5vw,38px)}
.section-head h2{max-width:20ch}
.section-head>p{margin:0;color:var(--grafito);font-size:.95rem}
/* Subtítulo bajo el título de sección: una línea breve en gris, en la misma
   columna. No es un rótulo encima ni una entradilla al lado. */
.section-sub{margin:.55rem 0 0;color:var(--grafito);font-size:clamp(1rem,1.5vw,1.12rem)}

@media(max-width:860px){
  .hero{grid-template-columns:1fr;gap:34px;padding-top:clamp(28px,6vw,48px)}
  /* En estrecho la marca va primero: es lo que identifica la página de un
     vistazo, y el titular se lee igual de bien justo debajo. */
  .hero-art{order:-1}
  .section-head{grid-template-columns:1fr;align-items:start;gap:14px}
  .section-head h2{max-width:none}
}

/* ── Los proyectos ────────────────────────────────────────────────────────── */
/* La disposición es la de siempre: rejilla de dos por fila, captura arriba y
   cuerpo debajo. Lo que cambia son los materiales.

   🔴 Tres cosas de la versión anterior NO vuelven, y las tres estaban en la
   lista de rasgos: el `border-radius:12px` en todo por igual, la
   `box-shadow:0 8px 24px #0003` bajo cada imagen y los degradados de adorno
   (`linear-gradient(145deg,#202c32,#1b2229)` y sus cuatro variantes). Juntas
   eran el «kit de tarjetas SaaS». La tarjeta se queda; el acabado no. */
.project-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(18px,2.5vw,30px);align-items:start}
/* Columna flexible: la tarjeta ocupa todo el alto de su fila y el cuerpo se
   reparte lo que sobra. Sin esto, estirarla dejaba el contenido arriba y un
   hueco muerto debajo. */
.project{position:relative;display:flex;flex-direction:column;
  border:1px solid var(--trama);background:var(--plano);
  transition:border-color .16s}
/* Cada tarjeta lleva el matiz de su tipo también en el cuerpo, no solo en el
   escenario de la captura. Se elige con `:has()` porque la clase de tipo está
   en la imagen, no en el artículo — así no hay que duplicarla en el HTML. */
.project:has(.project-image.terminal){background:#171b1f}
.project:has(.project-image.catalog){background:#151921}
.project:has(.project-image.tools){background:#171c1f}
.project:has(.project-image.game){background:#1d1a19}
.project:has(.project-image.panel){background:#181d1e}
.project:has(.project-image.hardware){background:#1a1c1f}
.project:hover,.project:focus-within{border-color:var(--plata)}

/* La captura mantiene su proporción fija para que la rejilla no baile, y se
   apoya en el plano en vez de en un degradado. */
/* El escenario interior: un degradado muy suave sobre el que se apoya la
   captura, para que no quede pegada al fondo de la tarjeta. Es el efecto de la
   versión anterior, pero A CANTO VIVO — la redondez es lo que no vuelve.
   
   📌 Los cuatro matices no son adorno: cada uno corresponde a un tipo de
   captura y revive las clases .terminal, .catalog, .tools y .game, que se
   habían quedado inertes. Son casi imperceptibles a propósito —los
   degradados llamativos de la versión anterior eran parte del problema. */
.project-image{display:flex;align-items:center;justify-content:center;
  position:relative;aspect-ratio:1.78;overflow:hidden;padding:20px;
  text-decoration:none;border-bottom:1px solid var(--trama);
  background:linear-gradient(150deg,#222b30,#0e1214)}
.project-image.terminal{background:linear-gradient(150deg,#27303b,#101419)}
.project-image.catalog{background:linear-gradient(150deg,#28354d,#111620)}
.project-image.tools{background:linear-gradient(150deg,#29363d,#11171a)}
.project-image.panel{background:linear-gradient(150deg,#222d30,#0e1314)}
/* SmartAccess: plata, sin matiz. Antes tiraba a granate (#2e2427) y era la
   única tarjeta cálida aparte del juego. */
.project-image.hardware{background:linear-gradient(150deg,#2d3034,#111315)}
.project-image img{width:100%;height:100%;object-fit:contain;transition:transform .3s}
.project-image:hover img,.project-image:focus-visible img{transform:scale(1.025)}

/* BuzzBrew es un móvil en vertical: se sale del encuadre y se inclina, que es
   como estaba y es lo que lo distingue del resto de la rejilla. */
.project-image.game{justify-content:flex-end;padding:0 28px;gap:20px;
  background:linear-gradient(150deg,#403834,#1b1816)}
.project-image.game img{height:92%;width:auto;border-radius:10px;transform:rotate(7deg)}
.project-image.game:hover img,.project-image.game:focus-visible img{transform:rotate(4deg)}

/* Botón a la página del proyecto, superpuesto en la esquina de la imagen.
   Va por encima del enlace de la galería (`z-index`) para que el clic caiga
   aquí y no abra el visor. Siempre visible: es una segunda vía, no un truco
   que haya que descubrir apuntando. */
/* Los dos botones van juntos en la esquina: la página del proyecto y la ficha
   de Google Play. Uno debajo del otro, en el hueco libre a la izquierda del
   móvil: en fila, el segundo pisaba la esquina de la captura. */
.project-links{position:absolute;z-index:3;top:18px;left:18px;
  display:flex;flex-direction:column;align-items:flex-start;gap:8px;pointer-events:none}
/* En un teléfono no queda hueco libre: salen de la imagen y van en fila justo
   debajo, antes del cuerpo de la tarjeta. */
@media(max-width:600px){
  .project-links{position:static;flex-direction:row;flex-wrap:wrap;
    padding:16px clamp(20px,2.2vw,28px) 0}
}
.project-page{pointer-events:auto;
  background:var(--tinta);border:1px solid var(--trama-viva);
  padding:8px 14px;font-family:var(--slab);font-weight:600;font-size:.82rem;
  color:var(--plata);text-decoration:none;
  transition:background-color .15s,color .15s,border-color .15s}
.project-page:hover{background:var(--plata);color:var(--tinta);border-color:var(--plata)}
/* El rótulo de la tarjeta del juego: se quedó sin estilo al rehacer la hoja y
   salía pegado al nombre. Va en slab, con el subtítulo en caja baja. */
.game-label{order:1;font-family:var(--slab);font-weight:700;
  font-size:clamp(1.35rem,2.2vw,2rem);line-height:1.1;color:var(--plata)}
.game-label small{display:block;margin-top:14px;font:400 .78rem/1.7 var(--sans);
  color:var(--grafito)}

/* El rótulo de abrir la galería queda SIEMPRE sobre la imagen, que era el
   defecto que había en BuzzBrew. Sin flecha: el texto ya dice qué hace. */
.image-action{position:absolute;z-index:2;right:12px;bottom:12px;
  background:var(--tinta);border:1px solid var(--trama-viva);
  padding:6px 11px;font-size:.76rem;color:var(--plata);
  opacity:0;transition:opacity .16s}
.project-image:hover .image-action,
.project-image:focus-visible .image-action{opacity:1}

.project-body{display:flex;flex-direction:column;flex:1;
  padding:clamp(20px,2.2vw,28px)}
.project-meta{display:flex;justify-content:space-between;align-items:center;
  gap:12px;flex-wrap:wrap;margin-bottom:16px}
.project-meta>span:first-child{font-size:.82rem;color:var(--grafito)}

/* 🔑 EL ESTADO. Tres grupos, y cada uno con su COLOR, no solo con su relleno:
     vivo         .status          verde, macizo
     pendiente    .status.pending  ámbar, perfilado
     desarrollo   .status.dev      plata, perfilado
   🔴 Antes eran todos carmesí y solo cambiaba macizo/perfilado. Feedback
   externo (29-sep-2026): el rojo se lee como «detenido», y la diferencia de
   relleno sola NO se percibía — hacía falta leer la etiqueta. Ahora el color
   lo dice solo. Un mismo proyecto lleva el mismo estado en todas las páginas. */
.status{font-family:var(--slab);font-weight:600;font-size:.74rem;
  letter-spacing:.03em;padding:4px 10px;white-space:nowrap;
  background:var(--vivo);color:var(--sobre-sello);border:1px solid var(--vivo)}
.status.pending{background:transparent;color:var(--pendiente);border-color:var(--pendiente)}
.status.dev{background:transparent;color:var(--grafito);border-color:var(--trama-viva)}

.project h3{font-size:clamp(1.3rem,1.8vw,1.5rem);margin:0 0 10px}
/* Un solo párrafo por tarjeta: qué hace el sistema y por qué funciona. Antes
   eran tres piezas —frase en dos golpes, descripción y recuadro de resultado—
   y las tres decían casi lo mismo con distinto tono.
   🔑 El alto mínimo reserva tantas líneas como ocupa el párrafo más largo a
   cada ancho, para que las dos tarjetas de una fila sigan midiendo igual
   cerradas. Si cambia un texto, hay que volver a medirlo. */
.description{font-size:.9rem;line-height:1.7;color:var(--grafito);margin:0 0 20px;min-height:6.8em}
@media(max-width:1159px){.description{min-height:8.5em}}
@media(max-width:1024px){.description{min-height:10.2em}}

.tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:22px}
.tags span{font:400 .74rem var(--mono);color:var(--grafito);
  border:1px solid var(--trama);padding:4px 8px}

details{margin-top:auto;border-top:1px solid var(--trama)}
summary{cursor:pointer;display:flex;justify-content:space-between;gap:12px;
  padding-top:16px;font-family:var(--slab);font-weight:600;font-size:.86rem;list-style:none}
summary::-webkit-details-marker{display:none}
/* Un `summary` se pulsa, no se lee para copiar. Sin esto, Android pinta su
   resaltado de toque y de paso selecciona el texto, y queda una banda de color
   cruzando la ficha. */
summary{-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none}
/* 🔑 EL «+», como en instituteofhealth.com: una caja cuadrada FIJA y, dentro,
   una cruz que gira 45° y pasa a «×». Gira la cruz, no la caja.
   La cruz se dibuja con dos barras y no con el carácter «+»: un «+» de texto
   gira alrededor del centro de su caja tipográfica, que no es el centro del
   trazo, y el giro bailaba. */
summary{align-items:center}
summary .mas{flex:none;display:grid;place-items:center;width:26px;height:26px;
  background:var(--trama);transition:background-color .2s}
summary:hover .mas{background:var(--trama-viva)}
summary .mas i{position:relative;width:10px;height:10px;
  transition:transform .38s cubic-bezier(.2,.7,.2,1)}
summary .mas i::before,summary .mas i::after{content:'';position:absolute;inset:0;
  margin:auto;background:var(--plata)}
summary .mas i::before{width:10px;height:1.5px}
summary .mas i::after{width:1.5px;height:10px}
details[open] summary .mas i{transform:rotate(45deg)}

/* El panel se despliega en altura en vez de aparecer de golpe. Usa
   ::details-content e interpolate-size, que son recientes: el navegador que no
   los entienda descarta estas dos reglas y abre al instante, como antes. Por
   eso van sueltas — agrupadas con otra, invalidarían a la otra también. */
details{interpolate-size:allow-keywords}
details::details-content{height:0;overflow:clip;
  transition:height .38s cubic-bezier(.2,.7,.2,1),content-visibility .38s allow-discrete}
details[open]::details-content{height:auto}
/* Y el contenido entra con fundido y subiendo, como en la referencia. Esto sí
   funciona en todos los navegadores: es una animación al aparecer. */
details[open] .case-content{animation:desplegar .45s cubic-bezier(.2,.7,.2,1) both}
@keyframes desplegar{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
/* flow-root: el margen inferior del último párrafo se queda DENTRO. Sin esto se
   escapaba por fuera (colapso de márgenes) y js/tarjetas.js, que mide esta caja
   para saber la altura final, se quedaba 7 px corto. La altura visible es la misma. */
.case-content{display:flow-root;padding-top:12px;color:var(--grafito);font-size:.86rem}
.case-content h4{margin:18px 0 4px;font-size:.86rem;color:var(--plata)}
.case-content p{margin:7px 0}
.case-content .evidence{margin-top:18px;padding:11px;background:var(--tinta);
  border-left:2px solid var(--trama);font:400 .75rem/1.6 var(--mono)}
.case-content a{display:inline-block;margin-top:12px}

/* ── Otros trabajos ───────────────────────────────────────────────────────── */
/* Dos columnas: el cuerpo y el estado. La primera columna de 40px era la del
   número de orden, que se ha retirado — una lista de proyectos no es una
   secuencia y el numerado fingía un orden que no existe. */


.approach{padding-top:20px}
.more-work{padding-top:15px}
/* Cada trabajo va sobre el gris levantado y con un filete a la izquierda que
   lo sangra, como una respuesta en un hilo. Así se distinguen de los seis
   proyectos principales sin necesidad de otra tarjeta. */
.work-row{display:grid;grid-template-columns:1fr auto;gap:25px;
  background:var(--plano2);border-left:2px solid var(--trama-viva);
  padding:22px clamp(18px,2.4vw,28px);margin-bottom:10px;
  transition:border-color .16s}
.work-row:last-child{margin-bottom:0}
.work-row:hover{border-left-color:var(--plata)}
.work-row h3{font-size:1.3rem;margin:0 0 10px}
.work-row p{font-size:.9rem;color:var(--grafito);max-width:700px;margin:0 0 16px}
.work-row small{color:var(--grafito);font-size:.76rem;line-height:1.7}
/* Los otros trabajos usan el mismo sello que los proyectos: un solo sistema
   de estados en todo el sitio. Arriba, sin estirarse al alto de la fila. */
.work-row>.status{align-self:start}

/* ── El hilo común ────────────────────────────────────────────────────────── */
.principles{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,3vw,30px)}
.principles article{display:flex;flex-direction:column;border-top:1px solid var(--trama-viva);padding-top:22px}
.principles h3{margin:0 0 14px;font-size:1.25rem;max-width:18ch;line-height:1.25}
.principles p{font-size:.88rem;color:var(--grafito);margin-bottom:.9rem}
.principles a{font-size:.85rem;color:var(--plata);text-decoration:none;
  border-bottom:1px solid var(--trama-viva);
  margin-top:auto;align-self:flex-start}
.principles a:hover{border-bottom-color:var(--plata)}

/* 🔑 LOS TRES CASOS DE ALTURA de una fila de dos tarjetas:
     · las dos cerradas  -> iguales por contenido (resultado y frase reservan
                            dos líneas), sin estirar nada;
     · una abierta       -> cada una mide lo suyo: la cerrada NO crece. Por eso
                            la rejilla va con align-items:start;
     · las dos abiertas  -> se igualan a la más alta. Lo hace js/tarjetas.js,
                            NO un align-self:stretch: estirar no se anima, y la
                            segunda tarjeta saltaba 318 px en un fotograma.
   Mientras una pareja está igualada lleva la clase .igualada, y el desplegable
   pierde su margin-top:auto: así el espacio sobrante va al FINAL de la tarjeta y
   «La decisión detrás del proyecto» sigue a la misma altura en las dos. */
.project.igualada details{margin-top:0}

@media(min-width:901px){
  /* El hilo común: los tres títulos reservan dos líneas, como la frase y el
     resultado de las tarjetas. Si uno cabía en una («The hard cases count.»),
     su párrafo y su enlace subían y la fila quedaba escalonada. El enlace,
     además, va al fondo: aunque un párrafo crezca, los tres siguen alineados. */
  .principles h3{min-height:2.5em}
}

@media(max-width:900px){
  .project-grid,.principles{grid-template-columns:1fr}
  .description{min-height:0}
}
@media(max-width:620px){
  .work-row{grid-template-columns:1fr;gap:12px}
  .work-row>.status{justify-self:start}
}

/* ── Quién está detrás ────────────────────────────────────────────────────── */
/* Mismo recurso que arriba: bloque de lectura sobre el gris levantado, con
   el filete de sangrado. Dos columnas — identidad a la izquierda, texto a la
   derecha. */
.about{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);
  gap:clamp(20px,4vw,48px);background:var(--plano2);
  border-left:2px solid var(--trama-viva);
  padding:clamp(24px,3.5vw,42px) clamp(20px,3vw,38px);
  margin-top:clamp(46px,7vw,80px)}
.about p{color:var(--grafito);font-size:.95rem}
.about-location{margin-top:.7rem;font:400 .82rem var(--mono);color:var(--grafito)}
/* Va DESPUÉS de la regla base: antes estaba en el bloque de 900px de más arriba
   y la base, al venir detrás, la pisaba — en móvil seguían las dos columnas. */
@media(max-width:900px){.about{grid-template-columns:1fr;gap:18px}}

/* ── Contacto ─────────────────────────────────────────────────────────────── */
/* Dos columnas: el titular a la izquierda y el correo a la derecha, alineados
   por la base. Antes iba todo apilado a la izquierda y sobraba media página. */
.cta{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(20px,4vw,56px);align-items:end;
  padding:clamp(38px,5vw,60px) 0;border-top:1px solid var(--trama);
  margin-top:clamp(46px,7vw,80px)}
.cta h2{max-width:16ch;margin:0}
.cta p{color:var(--grafito);margin:0 0 .9rem}
.cta .actions{margin-top:1.8rem}
/* El correo es la acción por la que existe la sección, así que se comporta
   como un botón en vez de como un enlace suelto. */
.cta>a[href^="mailto"]{display:inline-flex;align-items:center;
  font-family:var(--slab);font-weight:600;font-size:clamp(.95rem,1.4vw,1.08rem);
  text-decoration:none;padding:14px 24px;border:1px solid var(--trama-viva);
  white-space:nowrap;transition:border-color .15s,background-color .15s,color .15s}
.cta>a[href^="mailto"]:hover{background:var(--plata);color:var(--tinta);border-color:var(--plata)}

@media(max-width:760px){
  .cta{grid-template-columns:1fr;align-items:start;gap:26px}
  .cta>a[href^="mailto"]{justify-content:center}
}
.contact-link{display:inline-flex;align-items:center;padding:12px 20px;
  border:1px solid var(--trama-viva);text-decoration:none;font-size:.92rem;
  transition:border-color .15s}
.contact-link:hover{border-color:var(--plata)}
/* En la cabecera el botón llena la columna reservada (para que nada se mueva al
   cambiar de idioma), así que el texto va centrado. La reserva de 6,5rem es la
   que pide «Contacto», la etiqueta más larga: 60 px de texto + 40 de relleno +
   2 de borde. Con 8,2rem sobraban 56 px vacíos a la derecha del texto. */
header .contact-link{justify-content:center}
.contact-link.primary{background:var(--plata);color:var(--tinta);border-color:var(--plata);
  font-family:var(--slab);font-weight:600}
.contact-link.primary:hover{background:transparent;color:var(--plata)}

/* ── Pie ──────────────────────────────────────────────────────────────────── */
footer{border-top:1px solid var(--trama);padding:28px 0 46px;
  display:flex;flex-wrap:wrap;gap:12px 28px;justify-content:space-between;
  align-items:center;font-size:.85rem;color:var(--grafito)}
footer a{color:var(--grafito);text-decoration:none}
footer a:hover{color:var(--plata)}
.text-link{text-decoration:none;border-bottom:1px solid var(--trama-viva);padding-bottom:2px;transition:border-color .15s}
.text-link:hover{border-bottom-color:var(--plata)}

/* ── Respeta a quien pide menos movimiento ────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;scroll-behavior:auto !important}
}

/* ── Visor de galería ─────────────────────────────────────────────────────── */
/* El desenfoque vive FUERA de `.pswp` a propósito: `.pswp` lleva
   `will-change:opacity`, que crea una raíz de composición y anula cualquier
   `backdrop-filter` declarado dentro. Costó encontrarlo; no lo muevas.
   El z-index queda justo por debajo del de PhotoSwipe (100000). */
body.gallery-open::before{
  content:'';position:fixed;inset:0;z-index:99999;pointer-events:none;
  backdrop-filter:blur(22px) saturate(.75) brightness(.45);
  -webkit-backdrop-filter:blur(22px) saturate(.75) brightness(.45);
  animation:desenfocar .22s ease both;
}
@keyframes desenfocar{from{opacity:0}to{opacity:1}}

/* Si el navegador no sabe desenfocar, el fondo se oscurece más para que el
   texto de detrás no compita con la imagen. */
.pswp{--pswp-bg:#0a0b0df2;--pswp-icon-color:#c1bfc1;--pswp-icon-color-secondary:#090609;
  font-family:var(--sans)}
@supports (backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px)){
  .pswp{--pswp-bg:#0a0b0d59}
}

/* `:not(--arrow)` importa: sin él, esta regla estrechaba también las flechas a
   40px cuando su icono mide 60, así que media punta quedaba FUERA del área
   clicable y había que apuntar al pixel. */
.pswp .pswp__button:not(.pswp__button--arrow){width:40px}

/* Flechas: hitbox redondo y lo bastante grande para el dedo (72px; el mínimo
   recomendado para tocar son 44). El icono se centra dentro, así que todo lo
   que se ve responde al clic. */
.pswp .pswp__button--arrow{
  width:72px;height:72px;margin-top:-36px;border-radius:50%;
  background:transparent;transition:background-color .18s ease;
}
.pswp .pswp__button--arrow .pswp__icn{
  width:56px;height:56px;top:50%;left:50%;margin:-28px 0 0 -28px;
}
.pswp .pswp__button--arrow:hover,
.pswp .pswp__button--arrow:focus-visible{background:#2421248c}

.pswp__button--arrow--prev{left:22px}
.pswp__button--arrow--next{right:22px}
.pswp__counter{font:400 12px var(--mono);margin-inline:12px;white-space:nowrap;flex-shrink:0}

/* Ojo con la especificidad: PhotoSwipe lo enseña con
   `.pswp--zoom-allowed .pswp__button--zoom{display:block}`, que son DOS clases.
   Una sola no basta para taparlo — hace falta empatar y ganar por orden. */
.pswp .pswp__button--zoom{display:none}
.pswp__button--thumb-toggle{font:28px var(--sans);color:#c1bfc1}

/* El pie del visor es la ficha de la prueba: proyecto, título y nota. */
.pswp__dynamic-caption{color:var(--plata)}
.pswp__dynamic-caption--aside{max-width:330px;padding:22px 24px}
.pswp__dynamic-caption--below{max-width:850px;padding:20px 0}
.pswp__dynamic-caption--mobile{padding:16px 20px;background:var(--plano)}
.caption-project{font:400 .78rem var(--mono);color:var(--grafito)}
.pswp__dynamic-caption h2{font-family:var(--slab);font-size:clamp(1.2rem,2vw,1.7rem);
  font-weight:600;line-height:1.25;margin:9px 0}
.pswp__dynamic-caption p{font-size:13px;line-height:1.6;color:var(--grafito);margin:0 0 12px}

/* La tira de miniaturas no está fija: aparece al acercar el ratón al borde
   inferior, o con el botón. Fija robaba sitio justo a lo que se ha venido a
   ver, y en móvil tapaba la descripción. */
.pswp__thumbs{position:absolute;bottom:12px;left:50%;transform:translate(-50%,14px);
  display:flex;gap:8px;max-width:calc(100% - 32px);padding:8px;overflow-x:auto;
  background:var(--plano);border:1px solid var(--trama-viva);scrollbar-width:thin;
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .18s ease,transform .18s ease,visibility .18s}
.pswp.thumbs-visible .pswp__thumbs{opacity:1;visibility:visible;pointer-events:auto;
  transform:translate(-50%,0)}
.pswp__thumbs button{flex:0 0 64px;height:44px;padding:3px;border:1px solid transparent;
  background:var(--tinta);border-radius:5px;opacity:.55}
/* Plata y no carmesí: el carmesí sobre el fondo del visor se queda en 2,5:1 y
   un borde que señala «ésta es la que estás viendo» tiene que verse. */
.pswp__thumbs button[aria-pressed=true]{border-color:var(--plata);opacity:1}
.pswp__thumbs button:hover{opacity:1}
.pswp__thumbs img{width:100%;height:100%;object-fit:contain}

.pswp .pswp__dynamic-caption--mobile{bottom:12px;max-height:32dvh;overflow-y:auto;
  transition:bottom .2s ease}
.pswp.thumbs-visible .pswp__dynamic-caption--mobile{bottom:88px}

@media(max-width:720px){
  .pswp__dynamic-caption h2{font-size:1.2rem}
  .pswp__dynamic-caption p{font-size:12px}
  .pswp__thumbs button{flex-basis:48px;height:36px}
  .pswp__button--arrow--prev{left:2px}
  .pswp__button--arrow--next{right:2px}
  .pswp .pswp__button--arrow{width:56px;height:56px;margin-top:-28px}
  .pswp .pswp__button--arrow .pswp__icn{width:46px;height:46px;margin:-23px 0 0 -23px}
}

/* ── Página del juego ─────────────────────────────────────────────────────── */
/* BuzzBrew tiene piezas que la portada no usa. Ojo con dos nombres: el hero del
   juego es `.game-hero` y no `.hero`, y el enlace de cierre es `.next-link` y
   no `.cta`. En la portada esas dos clases ya significan otra cosa. */
.game-head{display:flex;align-items:center;gap:clamp(.9rem,3vw,1.5rem);margin-top:1.2rem}
.game-head h1{margin:0}
.game-icon{width:clamp(64px,9vw,92px);height:auto;border:1px solid var(--trama-viva)}
.hero-sub{margin:1.4rem 0 0;max-width:44rem;color:var(--grafito);
  font-size:clamp(1rem,1.8vw,1.1rem);line-height:1.75}
.hero-sub strong{color:var(--plata);font-weight:500}
/* El héroe del juego reparte: identidad a la izquierda, ficha a la derecha.
   Antes iba todo apilado y sobraba media página. */
.game-hero{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr);
  gap:clamp(22px,4vw,52px);align-items:center;padding:52px 0 18px}

/* La ficha usa el gris levantado y el filete de sangrado, como los bloques de
   la portada: un mismo sitio, un mismo recurso. */
.game-ficha{background:var(--plano2);border-left:2px solid var(--trama-viva);
  padding:clamp(18px,2.4vw,24px);display:flex;flex-direction:column;
  align-items:flex-start;gap:14px}
.game-ficha p{margin:0;color:var(--grafito);font-size:.9rem;line-height:1.7}
/* Descargar y Compartir, en fila. Compartir va en perfil: es la acción
   secundaria, y dos rectángulos macizos competirían entre sí. */
.ficha-acciones{display:flex;flex-wrap:wrap;gap:10px}
.button.secundario{background:transparent;color:var(--plata);border-color:var(--trama-viva);cursor:pointer}
.button.secundario:hover{border-color:var(--plata)}
/* `hidden` pierde contra el display de .button: hay que reforzarlo. */
.button[hidden]{display:none}

/* Texto y escalera de eras, hombro con hombro. */
.game-cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  gap:clamp(24px,4vw,56px);align-items:start;margin-top:1.4rem}
.game-cols .prose{margin-top:0}
/* El gato y la planta del propio juego, junto al texto. Son suyos y le dan a
   la página el tono que tiene el producto: es un juego, no un informe.
   Se apoyan en la base y se recortan en pantalla estrecha, donde el texto
   manda. */
.deco{display:flex;align-items:flex-end;justify-content:center;gap:clamp(12px,3vw,34px);
  padding-top:10px}
/* 🔑 EL TOPE DE 148 px NO ES ESTÉTICO. Los sprites miden 299 px de alto; a 190
   px CSS, una pantalla 2x los dibuja a 380 px reales y los AMPLÍA un 27 %. Eso
   es lo que hacía que la ranura se viera dentada en la web y limpia en el
   editor. Por debajo de 299/2 = 149 px el navegador ya no inventa píxeles. */
.deco img{width:auto;height:clamp(110px,12vw,148px);filter:drop-shadow(0 10px 22px #0006)}
.deco img:first-child{height:clamp(96px,10.4vw,128px)}
/* El gato se espeja para que mire hacia la planta y no hacia fuera de la
   pagina. Va por CSS y no duplicando el fichero: son cero bytes mas. */
.deco img:last-child{transform:scaleX(-1)}

/* La abeja acompaña a la primera era: se posa junto al «01», encima de la
   línea, como quien arranca el recorrido. */
.deco-abeja{position:absolute;top:-17px;left:1.9rem;width:auto;height:38px}

/* La ficha de cifras sale de la columna: a todo el ancho son dos columnas de
   tres, que es como se lee de un vistazo. */
.spec{margin-top:clamp(30px,4vw,46px)}

/* La escalera de eras: dos columnas a todo el ancho. Es una progresión, y en
   dos columnas se abarca de un vistazo.

   🔑 El color avanza del plateado del casco al ámbar de la era 10. La
   interpolación NO es lineal (curva t^1.9): con diez pasos lineales el cambio
   se reparte tan fino que no se lee como progresión, solo como diez grises
   distintos. Así las primeras se quedan en plata y el dorado llega de verdad
   al final. Los diez pasan AAA sobre el fondo — comprobado, no supuesto.
   El mismo color tiñe el hito de cada era y el tramo de línea que sale de él,
   así que la línea entera va del plata al ámbar. */
.ascent li:nth-child(1){--c:#c1bfc1}
.ascent li:nth-child(2){--c:#c1bfc0}
.ascent li:nth-child(3){--c:#c2bfbe}
.ascent li:nth-child(4){--c:#c4bebb}
.ascent li:nth-child(5){--c:#c5bdb6}
.ascent li:nth-child(6){--c:#c8bcb0}
.ascent li:nth-child(7){--c:#cbbba9}
.ascent li:nth-child(8){--c:#cebaa1}
.ascent li:nth-child(9){--c:#d2b998}
.ascent li:nth-child(10){--c:#d6b78e}
/* El número acompaña, apagado, para que el protagonista sea el nombre. */
.ascent li:nth-child(10) .n{color:#8a7a63}

/* Separacion entre las secciones de la pagina del juego. El selector solo
   casa alli: en la portada las secciones cuelgan de <main> directamente, no
   de un .wrap intermedio. */
main > .wrap > section{margin-top:clamp(38px,5vw,60px)}

@media(max-width:860px){
  .game-hero{grid-template-columns:1fr;gap:26px;padding-top:34px}
  .game-cols{grid-template-columns:1fr;gap:26px}
}


.prose{max-width:var(--medida);color:var(--grafito);margin-top:1.4rem}
.prose p{margin:0 0 1rem;font-size:.95rem;line-height:1.8}
.prose p:last-child{margin-bottom:0}
.prose strong{color:var(--plata);font-weight:500}
.prose ul{margin:0 0 1rem;padding-left:1.1rem;font-size:.92rem;line-height:1.9}
.prose a{color:var(--plata)}

/* Las eras van numeradas porque en el juego también: la interfaz muestra
   «Era 3 / 10». El número no es adorno, es el mismo que ve quien juega — que es
   justo la prueba que hay que pasar antes de numerar nada. */
/* 🔑 LÍNEA DE TIEMPO: diez columnas iguales. Cada era es número, hito y
   nombre, y el tramo de línea que va de su hito al siguiente es su ::before.
   El último no lleva tramo: la línea termina en la era 10, y ese hito va
   relleno. Los hitos son cuadrados, como todo lo demás del sitio. */
.ascent{--hito:11px;--fila-n:1.5rem;
  list-style:none;margin:2.8rem 0 0;padding:0;display:grid;
  grid-template-columns:repeat(10,minmax(0,1fr))}
.ascent li{position:relative;padding:0 14px 0 0}
.ascent li::before{content:'';position:absolute;left:0;right:0;
  top:calc(var(--fila-n) + 14px + var(--hito)/2);height:1px;
  background:color-mix(in srgb,var(--c) 45%,transparent)}
.ascent li::after{content:'';position:absolute;left:0;top:calc(var(--fila-n) + 14px);
  width:var(--hito);height:var(--hito);box-sizing:border-box;
  background:var(--tinta);border:1px solid var(--c)}
.ascent li:last-child::before{display:none}
.ascent li:last-child::after{background:var(--c)}
.ascent .n{display:block;height:var(--fila-n);line-height:var(--fila-n);
  font:400 .78rem/var(--fila-n) var(--mono);color:var(--grafito);font-variant-numeric:tabular-nums}
.ascent .era{display:block;margin-top:calc(14px + var(--hito) + 14px);
  font-size:.9rem;line-height:1.45;color:var(--c)}

/* En estrecho, diez columnas no caben: la línea se pone en vertical, con el
   hito a la izquierda y número y nombre en la misma fila. */
@media(max-width:900px){
  .ascent{grid-template-columns:1fr;margin-top:2rem}
  .ascent li{display:grid;grid-template-columns:2rem 1fr;gap:.55rem;align-items:baseline;
    padding:11px 0 11px calc(var(--hito) + 18px)}
  .ascent li::before{left:calc(var(--hito)/2);right:auto;top:50%;bottom:-50%;
    width:1px;height:auto}
  .ascent li::after{top:50%;transform:translateY(-50%)}
  .ascent .n{height:auto}
  .ascent .era{margin-top:0;font-size:.95rem}
  .deco-abeja{top:50%;left:auto;right:0;transform:translateY(-50%)}
}

.spec{list-style:none;margin:2.6rem 0 0;padding:0;display:grid;
  grid-template-columns:1fr 1fr;gap:0 3.5rem}
.spec li{display:flex;flex-direction:column;align-items:flex-start;gap:.15rem;
  padding:14px 0;border-bottom:1px solid var(--trama)}
.spec .k{color:var(--grafito);font-size:.88rem}
.spec .v{font:400 .92rem var(--mono);font-variant-numeric:tabular-nums}
.spec .v em{font-style:normal;color:var(--plata);font-weight:600}
/* El matiz de la cifra va debajo, no colgando de un punto medio. */
.spec .v small{display:block;margin-top:3px;font:400 .8rem/1.5 var(--sans);color:var(--grafito)}

/* Tira de capturas del juego. Son verticales (460x1022), así que en escritorio
   caben las cuatro de frente. Montura igual que la de las pruebas. */
.shots{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:2rem}
.shots figure{margin:0;scroll-snap-align:start}
.shots img{width:100%;border-radius:10px;border:1px solid var(--trama-viva);transition:transform .25s,border-color .25s}
.shots figure:hover img{transform:translateY(-5px);border-color:var(--plata)}
.shots figcaption{margin-top:11px;font-size:.8rem;color:var(--grafito)}
.shots figcaption b{color:var(--plata);font-weight:500;display:block;margin-bottom:3px}

.next-link{display:inline-flex;align-items:center;gap:13px;margin-top:2.2rem;
  border:1px solid var(--trama-viva);padding:13px 19px;font-size:.9rem;
  font-family:var(--slab);font-weight:600;text-decoration:none;
  transition:border-color .15s}
.next-link:hover{border-color:var(--plata)}
.next-link svg{width:.9rem;height:.9rem;flex:none}

/* Bloque de lectura de la página del juego: el mismo recurso que «Otros
   trabajos» y «La persona detrás» —gris levantado y filete de sangrado—, para
   que las dos páginas se lean como un mismo sitio. */
.bloque{background:var(--plano2);border-left:2px solid var(--trama-viva);
  padding:clamp(22px,3vw,32px) clamp(20px,3vw,30px);
  margin-top:clamp(28px,4vw,42px)}
.bloque h2{margin-top:0}
.bloque .prose{margin-top:1.1rem}
.bloque .next-link{margin-top:1.8rem}


@media(max-width:720px){
  .game-hero{padding:34px 0 10px}
  .spec{grid-template-columns:1fr;gap:0}
  /* Cuatro capturas verticales no caben de frente: pasan a tira desplazable. */
  .shots{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;gap:14px;
    margin-inline:calc(var(--canal)*-1);padding-inline:var(--canal)}
  .shots figure{flex:0 0 62%}
}

/* ── Pantalla estrecha ────────────────────────────────────────────────────── */
/* La rejilla de cuatro columnas de la cabecera no cabe por debajo de ~820px:
   la marca y la navegación se montaban una encima de otra y empujaban el ancho
   de la página entera, que es lo que provocaba el desplazamiento lateral.
   Aquí pasa a dos filas — identidad y acciones arriba, navegación debajo. */
@media(max-width:820px){
  /* Flex con wrap, como en la versión que estaba en producción. La rejilla con
     columna reservada para el botón partía «Let's talk» en dos líneas: en un
     teléfono estrecho esa columna no da de sí. */
  header{display:flex;flex-wrap:wrap;align-items:center;gap:14px;padding:16px 0}
  .brand{margin-right:auto}
  header nav{order:3;width:100%;justify-content:space-between;
    margin:2px 0 0;padding-top:12px;border-top:1px solid var(--trama)}
  .lang-switch,header>.button{justify-self:auto}
  header>.button{white-space:nowrap}
}

@media(max-width:620px){
  .project-meta{flex-wrap:wrap;gap:8px}
  .cta h2,.section-head h2{max-width:none}
  .actions{flex-direction:column;align-items:stretch}
  /* El botón ocupa el ancho, pero el enlace de texto no: estirado, su subrayado
     cruzaba la pantalla entera y quedaba pegado al filete del héroe — se leía
     como una línea doble. */
  .actions .text-link{align-self:flex-start}
  .contact-link{justify-content:center}
  footer{flex-direction:column;align-items:flex-start;gap:10px}
}

/* Red de seguridad: ninguna pieza puede ensanchar la página. Si algo se sale,
   se ve aquí antes que en un móvil de verdad. */
html,body{overflow-x:clip}
