:root {
  --portada-text-x: 40px;   /* ← ajuste en x del texto bio de la portada (encima de dónde ya lo coloca js/portada.js siguiendo a la ventana) */
  --portada-text-y: 0px;   /* ← ajuste en y del texto bio de la portada */
  --portada-text-scale: 0.85; /* ← escala del texto bio de la portada (1 = original) */
  --portada-text-width: 100px; /* ← ancho del bloque de texto bio de la portada (reemplaza el ancho que calcula js/portada.js) */
  --scramble-radius: 90px; /* ← distancia a la que el texto empieza a revolverse al cruzar con SOUND ON/OFF (js/soundScramble.js) */

  /* ← Posición horizontal de los controles y la mini portada, medida desde
     el centro de la pantalla: más = a la derecha, negativo = a la izquierda. */
  --reproductor-x: 39px;

  /* ← Paleta general. El fondo se define en canales para poder usarlo con
     transparencia en los controles fijos (menú wafle, sonido). */
  --page-bg-rgb: 10 10 10; /* ← fondo de toda la página */
  --page-bg: rgb(var(--page-bg-rgb));
  --ink: #bcbab5; /* #e8e6e0 al 80% sobre el fondo negro; para volver, usa #e8e6e0 */
  --ink-soft: #8f8b84;
  --rule: rgb(232 230 224 / 0.25);
  --accent: #e5391c;
  --slot-bg: #1a1918; /* ← fondo del área audiovisual mientras carga o si aún no hay contenido */

  --gutter: 20px; /* ← margen lateral de toda la página */
  --grotesk: "Hanken Grotesk", "Helvetica Neue", Arial, sans-serif;

  --memoria-ratio: 9 / 16; /* ← proporción del área audiovisual vertical */
  --memoria-max-h: 88svh;  /* ← alto máximo del área audiovisual */
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html {
  touch-action: pan-y;
  /* Evita el gesto nativo de "ir atrás" al deslizar desde el borde izquierdo
     (Chrome/Android). */
  overscroll-behavior-x: none;
  /* Oculta la barra de scroll de la página (el scroll en sí sigue
     funcionando igual, con el dedo, la rueda o el teclado). */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* Edge/IE viejos */
}

html::-webkit-scrollbar {
  display: none; /* Chrome/Safari/Android */
}

body {
  min-height: 100vh;
  background: var(--page-bg);
  color: var(--ink);
  overflow-x: hidden;
  touch-action: pan-y;
  overscroll-behavior-x: none;
}

.portada {
  position: relative;
  width: 100%;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
}

/* La foto vive en su propia capa, con una altura fija al viewport más grande
   posible (100lvh, con la barra del navegador ya colapsada) en vez de 100dvh.
   Si usara 100dvh aquí, cada vez que la barra del navegador aparece/desaparece
   durante el scroll, "background-size: cover" recalcularía el recorte de la
   imagen y se sentiría como un salto/zoom brusco — con una altura fija eso no
   pasa nunca, ".portada" (con overflow:hidden) solo recorta lo que sobra. El
   escalado gradual al hacer scroll (ver js/portada.js) se anima aquí, aislado
   del resto de la composición (ventana, texto, velo). */
.portada-photo {
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  background-image: url("./assets/imagenes/web/retrato_1.jpg") /* copia ligera de retrato_1.png (herramientas/optimizar-videos.swift) */;
  background-size: cover;
  background-position: center;
  /* Crece desde su borde inferior: así el desvanecido de la máscara se queda
     anclado al final de la portada durante el zoom. Desde el centro, el
     degradado se salía por abajo y dejaba un corte visible contra el fondo. */
  transform-origin: center bottom;
  will-change: transform;
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%);
}

/* Una sola capa de blur para toda la portada (sin costuras posibles, ya que
   solo hay un cálculo de backdrop-filter). El hueco de la ventana se recorta
   con clip-path (polygon con un "corte" hacia el hueco) en vez de mask SVG:
   mask + backdrop-filter combinados es poco fiable en Safari/Chrome móvil,
   clip-path con polygon() tiene soporte mucho más sólido. La misma máscara de
   fade (mask-image) de ".portada-photo" se repite aquí para que el velo se
   desvanezca en el mismo punto y al mismo ritmo que la foto — si solo se
   desvaneciera la foto, el color del velo se quedaría como un corte sólido. */
.portada-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  backdrop-filter: blur(11px) saturate(1.4) brightness(0.9);
  -webkit-backdrop-filter: blur(11px) saturate(1.6) brightness(0.9);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%);
  background-image: linear-gradient(
    180deg,
    rgba(255, 70, 40, 0.55) 0%,
    rgba(247, 81, 52, 0.4) 38%,
    rgba(23, 16, 15, 0.8) 92%
  );
  pointer-events: none;
}

.portada-veil-grain {
  position: absolute;
  inset: 0;
  opacity: 0.6;
  mix-blend-mode: overlay;
  background-repeat: repeat;
  background-size: 150px 150px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Cierre real hacia el color de la página: el velo combina backdrop-filter con
   máscara y no llega a desaparecer del todo, así que sin esta capa queda un
   corte visible donde termina la portada. Va sobre el velo y bajo texto/ventana. */
.portada::after {
  content: "";
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  height: 30%;
  background: linear-gradient(to bottom, rgb(var(--page-bg-rgb) / 0) 0%, var(--page-bg) 70%);
  pointer-events: none;
}

.portada-window {
  position: absolute;
  z-index: 3;
  box-sizing: border-box;
  border: 0.5px solid rgba(0, 0, 0, 0.85);
  cursor: grab;
  touch-action: none;
}

.portada-window.is-dragging {
  cursor: grabbing;
}

/* Glitch de la ventana (js/glitch.js): solo se ve durante cada golpe del audio. */
.portada-glitch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
}

.portada-glitch.is-activo {
  opacity: 1;
}

/* "left"/"top"/"maxHeight" los sigue calculando js/portada.js en cada frame
   (siguen a la ventana arrastrable) — el "transform" de acá es un ajuste
   ENCIMA de eso, no reemplaza ese cálculo: --portada-text-x/y corren el
   bloque sin afectar lo que ya calculó JS (por eso "translate", no
   "left/top"), y --portada-text-scale lo escala desde su propia esquina
   superior izquierda (transform-origin). "width" SÍ se reemplaza: JS pone
   un ancho inline en cada frame (el disponible junto a la ventana), y
   "!important" es la única forma de que --portada-text-width le gane a
   eso — sin él, el ancho calculado por JS seguiría ganando siempre. */
.portada-text {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 1em; /* ← "un renglón" de separación entre cada grupo (nombre / profesión / ubicación / párrafo) */
  font-family: "Space Mono", monospace;
  font-weight: 400;
  font-size: clamp(10px, 2.6vw, 13px);
  line-height: 1.25;
  color: #000000;
  /* "!important": por las dudas de que algo más específico (o el motor del
     navegador en algún dispositivo) intente justificarlo — mismo criterio
     que "width"/"max-height" más abajo, que ya necesitan "!important" para
     ganarle al estilo inline que pone js/portada.js en cada frame. */
  text-align: left !important;
  pointer-events: none;
  /* "overflow:visible" + "max-height:none": con --portada-text-width fijo
     (angosto), el párrafo necesita más renglones de los que cabían con el
     ancho que calculaba JS — ese cálculo también le ponía un alto máximo
     (el de la ventana arrastrable) pensado PARA ese ancho dinámico, ya no
     para uno fijo. Con "overflow:hidden" de antes, lo que no cabía en ese
     alto se recortaba (el texto se veía "cortado", sin llegar al final).
     "!important" en max-height por lo mismo que en width: JS pone un
     "max-height" inline en cada frame y le gana a una regla normal. */
  overflow: visible;
  max-height: none !important;
  /* Con --portada-text-width angosto, varias palabras en español no entran
     completas en una sola línea — sin esto, el navegador las corta a la
     mitad para que quepan (se veía "Tecn-ólogo", "int-egra"). Mejor que se
     desborden un poco el ancho de la columna a que partan una palabra. */
  overflow-wrap: normal;
  word-break: normal;
  width: var(--portada-text-width, 200px) !important;
  transform: translate(var(--portada-text-x, 0px), var(--portada-text-y, 0px)) scale(var(--portada-text-scale, 1));
  transform-origin: left top;
}

/* Cada grupo (nombre / profesión / ubicación / párrafo) es su propio bloque
   — el espaciado GRANDE entre grupos lo da el "gap" de ".portada-text"
   (arriba); este es el espaciado CHICO entre renglones que van juntos
   dentro del mismo grupo (como Valencia/CDMX). */
.bio-group {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}

.bio-location {
  flex-direction: row;
  align-items: flex-start;
  gap: 0.5em;
  /* Un renglón MÁS que la separación normal entre grupos (el "gap" de
     ".portada-text" ya pone uno; este suma otro, solo después de ubicación,
     antes del párrafo). */
  margin-bottom: 1em;
}

.bio-location-icon {
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  margin-top: 0.2em; /* alinea ópticamente con la primera línea (Valencia), no con el bloque completo */
}

.bio-location-cities {
  display: flex;
  flex-direction: column;
  gap: 0.2em;
}

/* Agrupa ecualizador y switch en la esquina inferior derecha. Fijo (no
   ".portada"): se queda visible en toda la página al hacer scroll. Deja pasar
   los toques y solo los recibe el switch. */
.portada-sound {
  position: fixed;
  z-index: 100;
  right: 24px;
  bottom: 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 14px;
  pointer-events: none;
}

/* Entre el switch de idioma y el menú wafle, centrado en la pantalla. Fijo
   como ellos, con su mismo color, y visible solo con el sonido encendido. */
.reproductor {
  position: fixed;
  z-index: 210; /* sobre el panel del menú, igual que el wafle */
  top: 9px;
  left: calc(50% + var(--reproductor-x));
  height: 44px;
  display: flex;
  align-items: center;
  color: #161513;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -6px);
  transition: color 0.35s ease, opacity 0.5s ease, transform 0.5s ease, visibility 0s linear 0.5s;
}

body:has(.portada-switch.is-on) .reproductor {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}

/* Marco provisional: se sustituye por la imagen del audio. Mide lo mismo que
   la retícula de puntos del wafle (3 × 4px + 2 × 5px). */
.reproductor-portada {
  width: 22px;
  height: 22px;
  margin-left: 8px;
  border: 1px solid currentColor;
  overflow: hidden;
}

/* Con la portada del track (campo "portada" en tracks.js): video o imagen
   que llena el recuadro, sin el marco. */
.reproductor-portada.con-imagen {
  border: 0;
}

.reproductor-portada video,
.reproductor-portada img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.reproductor-boton {
  display: grid;
  place-items: center;
  width: 36px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.15s ease;
}

.reproductor-boton:active {
  transform: scale(0.82);
}

.reproductor-boton:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 2px;
}

.reproductor-boton svg {
  display: block;
  width: 20px;
  height: 20px;
  fill: currentColor;
}

/* Degradado bajo la barra superior: al quedar fijos, el idioma y el
   reproductor necesitan que el contenido se desvanezca al pasar por debajo. */
body::before {
  content: "";
  position: fixed;
  z-index: 140;
  top: 0;
  left: 0;
  right: 0;
  height: 84px;
  background: linear-gradient(var(--barra-bg, var(--page-bg)) 62%, transparent);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}

body.sobre-contenido::before,
body.about-page::before,
body.proyecto-page::before {
  opacity: 1;
}

body.about-page {
  --barra-bg: var(--about-bg);
}

.portada-sound.en-pausa .portada-sound-icon path {
  animation-play-state: paused;
}

/* Con el análisis de audio activo, las barras las mueve js/sonido.js. */
.portada-sound.con-analisis .portada-sound-icon path {
  animation: none;
}

.portada-sound-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

body.about-page .portada-sound-label {
  color: var(--about-ink-soft); /* el gris general es para fondo oscuro */
}

/* Letras generadas por SplitText (js/soundScramble.js) sobre el texto bio:
   se revuelven al cruzar con
   SOUND ON/OFF durante el scroll. */
.scramble-char {
  will-change: transform;
}

/* Mismo estilo que ".portada-text". El cambio entre
   "SOUND ON"/"SOUND OFF" se anima con un fade (ver js/portada.js: se baja la
   opacidad, se cambia el texto y se vuelve a subir). */
.portada-sound-label {
  font-family: "Space Mono", monospace;
  font-weight: 700;
  font-size: clamp(10px, 2.6vw, 13px);
  color: var(--ink-soft);
  opacity: 1;
  transition: opacity 0.3s ease;
  user-select: none;
}

/* Ícono de ecualizador (barras que laten), animación adaptada de
   https://codepen.io/SGII2/pen/GRxLWBM. Del ancho del círculo del switch (30px
   × su escala 0.9 = 27px) y solo visible mientras el switch está en naranja
   (encendido) — por ahora es solo decorativo, luego reaccionará a la música
   real y el switch la activará. */
.portada-sound-icon {
  width: 27px;
  height: 27px;
  color: #ff7a29;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

.portada-sound:has(.portada-switch.is-on) .portada-sound-icon {
  opacity: 1;
}

/* Cada barra sigue una franja de frecuencias del track (js/sonido.js), con
   transform: scaleY. Mientras Web Audio no ha arrancado (necesita un toque),
   se usa este pulso genérico de CSS. */
.portada-sound-icon path {
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  transform-box: fill-box;
  transform-origin: center;
  animation: portada-bar-pulse 400ms ease-in-out alternate infinite;
}

.portada-sound-icon path:nth-child(1) {
  animation-delay: 0ms;
}

.portada-sound-icon path:nth-child(2) {
  animation-delay: 133ms;
}

.portada-sound-icon path:nth-child(3) {
  animation-delay: 237ms;
}

.portada-sound-icon path:nth-child(4) {
  animation-delay: 87ms;
}

@keyframes portada-bar-pulse {
  from {
    transform: scaleY(1);
  }
  to {
    transform: scaleY(0.2);
  }
}

/* Switch (aún sin acción real, ver js/portada.js). El efecto "gooey" (botón y
   barra se funden al moverse) usa el filtro SVG #gooey definido en el
   <svg class="filters"> del <body>. Color según el lado: amarillo a la
   izquierda (apagado), naranja a la derecha (encendido). */
.portada-switch {
  position: relative;
  cursor: pointer;
  pointer-events: auto;
  filter: url(#gooey);
  -webkit-filter: url(#gooey);
  transform: scale(0.9);
  transform-origin: right center;
}

.portada-switch-bg,
.portada-switch-btn {
  background: #ffcf33;
  transition: 300ms all ease;
}

.portada-switch-bg {
  width: 60px;
  height: 7px;
}

.portada-switch-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: inline-block;
  position: absolute;
  left: 0px;
  top: -12px;
  transform: translate3d(0, 0, 0);
}

.portada-switch.is-on .portada-switch-btn,
.portada-switch.is-on .portada-switch-bg {
  background: #ff7a29;
}

.portada-switch.is-on .portada-switch-btn {
  animation: portada-switch-on 250ms linear forwards;
}

.portada-switch.is-off .portada-switch-btn {
  animation: portada-switch-off 250ms linear forwards;
}

@keyframes portada-switch-on {
  0% {
    transform: scale3d(1, 1, 1) translate3d(0px, 0, 0);
    transform-origin: left center;
  }
  40% {
    transform: scale3d(1.4, 0.7, 0) translate3d(20px, 0, 0);
    transform-origin: right center;
  }
  70% {
    transform: scale3d(0.9, 1.15, 1) translate3d(33px, 0, 0);
  }
  100% {
    transform: scale3d(1, 1, 1) translate3d(30px, 0, 0);
  }
}

@keyframes portada-switch-off {
  0% {
    transform: scale3d(1, 1, 1) translate3d(30px, 0, 0);
    transform-origin: right center;
  }
  40% {
    transform: scale3d(1.4, 0.7, 0) translate3d(10px, 0, 0);
    transform-origin: right center;
  }
  70% {
    transform: scale3d(0.9, 1.15, 1) translate3d(-3px, 0, 0);
  }
  100% {
    transform: scale3d(1, 1, 1) translate3d(0px, 0, 0);
  }
}

.portada-text .bio-line {
  opacity: 0;
  transform: translateY(-14px);
}

.portada-text .bio-name {
  font-weight: 700; /* "negrilla": el resto del texto es 400, el nombre resalta en 700 */
}

/* ═══════════════════════════════════════════════════════════════════════
   ABOUT (about.html) — fondo claro propio. Nombre, foto y un acordeón:
   cada sección se despliega al tocarla (js/about.js). ═══ */

/* Inicio ↔ About en la misma página (js/vistas.js): la vista que no se ve
   queda fuera, y la que llega aparece con un fundido corto. */
.vista-oculta {
  display: none !important;
}

.vista-entra {
  animation: vista-entra 350ms ease both; /* ← igual que DURACION_ENTRADA en js/vistas.js */
}

@keyframes vista-entra {
  from {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .vista-entra {
    animation: none;
  }
}

body.about-page {
  --about-bg: #d9d5c9;
  --about-ink: #1c1a17;
  --about-ink-soft: #6b6659;
  --about-rule: rgb(28 26 23 / 0.22);
  background: var(--about-bg);
  min-height: 100vh;
  min-height: 100dvh;
}

.about {
  padding: 90px var(--gutter) 24vh;
  color: var(--about-ink);
  font-family: var(--grotesk);
}

/* Nombre a la izquierda y foto a la derecha, con el ancho que tenía antes. */
.about-cabecera {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 160px; /* ← 160px: ancho de la foto */
  gap: 20px;
  align-items: start;
  margin-bottom: 28px;
}

.about-nombre {
  font-size: clamp(30px, 9vw, 72px); /* ← tamaño del nombre */
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: 0.025em;
  align-self: end; /* abajo, a la altura de la base de la foto */
  text-align: left; /* ← pegado a la foto */
  margin-bottom: 0.233em; /* baja la caja lo que mide el espacio bajo la base de las letras */
}

.about-foto {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 50% 24%; /* ← qué parte de la foto se ve: el 2º valor sube (menos) o baja (más) el encuadre */
}

/* ─── Acordeón ──────────────────────────────────────────────────────────── */
.about-acordeon {
  border-bottom: 1px solid var(--about-rule);
}

.about-seccion {
  border-top: 1px solid var(--about-rule);
}

.about-encabezado {
  font: inherit;
}

.about-fila {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 16px 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 21px; /* ← tamaño de los nombres de sección */
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.025em;
  text-align: left;
  cursor: pointer;
}

.about-fila:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 2px;
}

.about-flecha {
  flex: none;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  transition: transform 0.6s cubic-bezier(0.76, 0, 0.24, 1);
}

.about-seccion.is-open .about-flecha {
  transform: rotate(180deg);
}

.about-panel {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition:
    grid-template-rows 0.6s cubic-bezier(0.76, 0, 0.24, 1),
    visibility 0s linear 0.6s;
}

.about-seccion.is-open .about-panel {
  grid-template-rows: 1fr;
  visibility: visible;
  transition: grid-template-rows 0.6s cubic-bezier(0.76, 0, 0.24, 1), visibility 0s;
}

.about-recorte {
  min-height: 0;
  overflow: hidden;
}

.about-cuerpo {
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding: 6px 0 34px;
}

/* ─── Contenido de cada sección ─────────────────────────────────────────── */
.about-bio {
  max-width: 56ch;
  font-size: 15px; /* ← tamaño de los párrafos de "Sobre mí" */
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
}

.about-entry,
.about-skill {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-width: 56ch;
}

.about-entry-title,
.about-skill-title {
  font-size: 15px; /* ← tamaño de los títulos de cada entrada */
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.015em;
}

.about-entry-place,
.about-entry-date {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--about-ink-soft);
}

.about-entry-desc,
.about-skill-desc {
  margin-top: 5px;
  font-size: 14px; /* ← tamaño de las descripciones */
  font-weight: 500;
  line-height: 1.4;
}

.about-skill-desc {
  margin-top: 2px;
}

.about-pendiente {
  font-size: 14px;
  font-weight: 600;
  color: var(--about-ink-soft);
}

.about-pie {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  margin-top: 40px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--about-ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .about-flecha,
  .about-panel,
  .about-seccion.is-open .about-panel {
    transition: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   MENÚ WAFLE (js/menu.js) — 9 puntos fijos arriba a la derecha. Tres
   anillos de retraso (centro, lados, esquinas) hacen que cada animación
   salga del centro hacia afuera. Al abrir, los 4 lados desaparecen y las
   esquinas + centro quedan formando una X. ═══ */

.waffle {
  position: fixed;
  z-index: 210;
  top: 9px;
  right: 9px; /* 44px de área táctil: los puntos quedan justo sobre --gutter */
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: #161513; /* sobre el naranja de la portada y el fondo claro de About */
  cursor: pointer;
  transition: color 0.35s ease;
}

.sobre-oscuro .waffle,
.sobre-oscuro .idioma,
.sobre-oscuro .reproductor,
.menu-abierto .idioma,
.menu-abierto .reproductor,
.waffle[aria-expanded="true"] {
  color: var(--ink);
}

.waffle:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: -4px;
}

.waffle-grid {
  display: grid;
  grid-template-columns: repeat(3, 4px);
  gap: 5px;
  transition: transform 0.7s cubic-bezier(0.76, 0, 0.24, 1);
}

.waffle-dot {
  --anillo: 2; /* esquinas */
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  transition: transform 0.45s cubic-bezier(0.76, 0, 0.24, 1), opacity 0.3s ease;
  animation:
    waffle-entrada 0.7s cubic-bezier(0.22, 1, 0.36, 1) backwards,
    waffle-latido 6s ease-in-out infinite;
  animation-delay:
    calc(0.5s + var(--anillo) * 90ms),
    calc(3s + var(--anillo) * 110ms);
}

.waffle-dot:nth-child(even) { --anillo: 1; }
.waffle-dot:nth-child(5) { --anillo: 0; }

@keyframes waffle-entrada {
  from { transform: scale(0); }
}

/* Latido breve cada 6 s: en celular no hay hover que delate que es un botón. */
@keyframes waffle-latido {
  0%, 16%, 100% { transform: scale(1); }
  7% { transform: scale(0.35); }
}

@keyframes waffle-onda {
  0%, 100% { transform: scale(1); }
  40% { transform: scale(1.55); }
}

@media (hover: hover) {
  .waffle:hover .waffle-dot {
    animation: waffle-onda 0.9s ease-in-out infinite;
    animation-delay: calc(var(--anillo) * 90ms);
  }
}

.waffle[aria-expanded="true"] .waffle-grid {
  transform: rotate(90deg) scale(1.2);
}

.waffle[aria-expanded="true"] .waffle-dot {
  animation: none;
}

.waffle[aria-expanded="true"] .waffle-dot:nth-child(even) {
  transform: scale(0);
  opacity: 0;
}

/* El panel se abre como un círculo que nace del propio botón. */
.menu-panel {
  --origen: calc(100% - 31px) 31px;
  position: fixed;
  z-index: 200;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between; /* palabras arriba, pie abajo */
  gap: 8vh;
  padding: 150px var(--gutter) var(--gutter); /* ← el primer valor: distancia entre la parte superior y las palabras */
  background: var(--page-bg);
  color: var(--ink);
  font-family: var(--grotesk);
  clip-path: circle(0 at var(--origen));
  visibility: hidden;
  transition:
    clip-path 0.8s cubic-bezier(0.76, 0, 0.24, 1),
    visibility 0s linear 0.8s;
}

.menu-panel.is-open {
  clip-path: circle(150vmax at var(--origen));
  visibility: visible;
  transition: clip-path 0.8s cubic-bezier(0.76, 0, 0.24, 1), visibility 0s;
}

.menu-lista {
  list-style: none;
}

.menu-lista li {
  overflow: hidden;
  border-top: 1px solid var(--rule);
}

.menu-enlace {
  display: block;
  padding: 0.12em 0 0.2em;
  color: inherit;
  text-decoration: none;
  font-size: clamp(38px, 11vw, 104px); /* ← tamaño de las palabras del menú */
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.05em;
  transform: translateY(110%);
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1), color 0.25s ease;
}

.menu-panel.is-open .menu-enlace {
  transform: translateY(0);
  transition-delay: calc(0.22s + var(--i) * 70ms), 0s;
}

.menu-enlace[aria-current="page"] .menu-palabra,
.menu-enlace.is-pendiente {
  color: var(--ink-soft);
}

@media (hover: hover) {
  a.menu-enlace:hover {
    color: var(--accent);
  }
}

.menu-pie {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  font-weight: 600;
}

html.menu-abierto {
  overflow: hidden;
}

/* ═══════════════════════════════════════════════════════════════════════
   MEMORIAS (js/memorias.js) — palabra grande y listado de proyectos. Cada
   fila se despliega con su área audiovisual y toda la información. ═══ */

.memorias,
.muestra {
  position: relative;
  z-index: 1;
  padding: 1vh var(--gutter) 24vh; /* ← 1vh: distancia entre la portada y "ARCHIVO" */
  scroll-margin-top: 60px; /* al llegar desde el menú, ARCHIVO queda bajo la barra superior */
  font-family: var(--grotesk);
  color: var(--ink);
}

/* Entre la última línea de Archivo y GALERÍA. Con scroll-margin-top, al
   llegar desde el menú esa línea queda justo fuera de la pantalla. */
.memorias {
  padding-bottom: 110px; /* ← distancia entre el final de Archivo y GALERÍA */
}

/* El ancho disponible entre un factor fijo: la palabra llena la columna a
   cualquier tamaño de pantalla, sin saltos por puntos de corte. */
/* Centrada y con la misma línea que separa los proyectos debajo. La
   transparencia va en el color para que no afecte a la línea. */
.memorias-titulo,
.muestra-titulo {
  font-size: calc((100vw - 2 * var(--gutter)) / 3.942 * 0.3); /* ← 0.3 = 30% del ancho completo */
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.055em;
  text-align: center;
  white-space: nowrap;
  color: color-mix(in srgb, var(--ink) 50%, transparent); /* ← 50% = transparencia de ARCHIVO */
  padding-bottom: 14px; /* ← espacio entre la palabra y la línea */
  border-bottom: 1px solid var(--rule);
}

/* Misma idea que el título: el tamaño sale del ancho disponible y
   space-between reparte igual cada espacio entre palabra y línea. */
/* Casi pegadas a la línea de arriba. Abajo, el
   aire se mide desde la base de las letras hasta la línea (el em descuenta
   el espacio vacío que la tipografía deja bajo la base). La leyenda de
   Galería usa las mismas medidas. */
.memorias-categorias,
.muestra-subtitulo {
  --categorias-arriba: 5px; /* ← distancia con la línea de arriba */
  --categorias-abajo: 32px; /* ← distancia con la línea de abajo (o con los videos) */
  padding: var(--categorias-arriba) 0 calc(var(--categorias-abajo) - 0.164em);
  font-size: calc((100vw - 2 * var(--gutter)) / 23.5);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.memorias-categorias {
  display: flex;
  justify-content: space-between;
  list-style: none;
}

.muestra-subtitulo {
  text-align: center;
}

/* ─── Carrusel de portadas (js/carrusel.js) ─────────────────────────────────
   Ocupa todo el ancho de la pantalla; las orillas se desvanecen y las
   portadas se encogen y giran hacia ellas, como una perilla. */
.carrusel {
  --carrusel-ancho: 64px; /* ← ancho de cada portada (el alto sale de 9:16) */
  --carrusel-hueco: 8px; /* ← separación entre portadas */
  position: relative;
  height: calc(var(--carrusel-ancho) * 16 / 9);
  margin: 0 calc(-1 * var(--gutter)) 32px; /* ← 32px: distancia con la línea del primer proyecto */
  overflow: hidden;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 24%, #000 76%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 24%, #000 76%, transparent); /* ← degradado de las orillas */
}

.carrusel.is-arrastrando {
  cursor: grabbing;
}

.carrusel:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

.carrusel-item {
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--carrusel-ancho);
  height: 100%;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: var(--slot-bg);
  cursor: pointer;
  will-change: transform;
}

.carrusel-item img,
.carrusel-item video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  -webkit-user-drag: none;
}

/* ─── Galería (js/muestra.js): filas de dos piezas en zigzag ───────────────
   Con el scroll, en cada fila la grande se encoge mientras la chica crece
   hasta intercambiar tamaños. Entre las dos siempre ocupan lo mismo, así
   que el espacio entre ellas no cambia. */
.muestra-lista {
  --muestra-grande: 70; /* ← ancho de la pieza grande, en % (grande + chica = 100) */
  --muestra-chica: 30; /* ← ancho de la pieza chica, en % */
  --muestra-hueco: 6px; /* ← separación entre piezas, a lo ancho y a lo alto */
  display: flex;
  flex-direction: column;
  gap: var(--muestra-hueco);
}

.muestra-fila {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

/* Si el total es impar, la última fila lleva una sola pieza, en su lado. */
.muestra-fila.invertida > .grande:only-child {
  margin-left: auto;
}

.muestra-pieza {
  flex: none;
  aspect-ratio: 1; /* mientras carga; luego toma la proporción de su archivo */
  overflow: hidden;
  background: var(--slot-bg);
}

.muestra-pieza.grande {
  width: calc(var(--muestra-grande) * 1% - var(--muestra-hueco) / 2);
}

.muestra-pieza.chica {
  width: calc(var(--muestra-chica) * 1% - var(--muestra-hueco) / 2);
}

.muestra-pieza {
  cursor: pointer;
}

.muestra-pieza:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 2px;
}

/* ─── Pieza ampliada (js/ampliado.js) ───────────────────────────────────── */
html.ampliado-abierto {
  overflow: hidden;
}

/* La barra superior y el sonido se apartan: la flecha de volver ocupa su lugar. */
html.ampliado-abierto .idioma,
html.ampliado-abierto .waffle,
html.ampliado-abierto body .reproductor,
html.ampliado-abierto .portada-sound {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* El reproductor se muestra con una regla más específica (con :has). */
html.ampliado-abierto body:has(.portada-switch.is-on) .reproductor {
  opacity: 0;
}

.ampliado {
  position: fixed;
  inset: 0;
  z-index: 300; /* sobre la barra superior y el menú */
  color: #e8e6e0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.ampliado-fondo {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.88); /* ← qué tan oscuro queda lo de atrás */
  opacity: 0;
}

.ampliado-marco {
  position: fixed;
  transform-origin: 0 0;
  overflow: hidden;
  background: #000;
}

.ampliado-marco video,
.ampliado-marco img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.ampliado-volver {
  position: absolute;
  top: max(9px, env(safe-area-inset-top));
  left: max(9px, env(safe-area-inset-left));
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.ampliado-volver svg,
.ampliado-flecha {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
}

.ampliado-volver svg {
  width: 24px;
  height: 24px;
}

.ampliado-volver:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: -4px;
}

/* Señal de "desliza para volver", con la flecha empujando a la derecha. */
.ampliado-pista {
  position: fixed;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  font-family: var(--grotesk);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
  pointer-events: none;
}

.ampliado-flecha {
  width: 18px;
  height: 18px;
  animation: ampliado-empuje 1.6s ease-in-out infinite;
}

@keyframes ampliado-empuje {
  0%, 100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(6px);
  }
}

.ampliado-volver,
.ampliado-pista {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.ampliado.is-open .ampliado-volver,
.ampliado.is-open .ampliado-pista {
  opacity: 1;
  transition-delay: 0.25s;
}

@media (prefers-reduced-motion: reduce) {
  .ampliado-flecha {
    animation: none;
  }
}

.muestra-pieza video,
.muestra-pieza img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.memorias-separador {
  flex: none;
  width: 1px;
  background: currentColor;
}

#memoriasLista {
  border-bottom: 1px solid var(--rule);
}

.memoria {
  border-top: 1px solid var(--rule);
}

.memoria-encabezado {
  font: inherit;
}

.memoria-fila {
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 4px;
  row-gap: 8px;
  align-items: start;
  padding: 14px 0 16px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-align: left;
  cursor: pointer;
}

.memoria-fila:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 2px;
}

.memoria-fila-titulo {
  font-size: clamp(26px, 6.5vw, 64px); /* ← tamaño de los títulos de los proyectos */
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.05em;
  transition: color 0.3s ease;
}

.memoria.is-open .memoria-fila-titulo {
  color: var(--accent);
}

@media (hover: hover) {
  .memoria-fila:hover .memoria-fila-titulo {
    color: var(--accent);
  }
}

.memoria-info-areas {
  grid-column: 1;
  color: var(--ink-soft);
}

.memoria-anio {
  grid-column: 2;
  text-align: right;
  white-space: nowrap;
  color: var(--ink-soft);
}

/* Signo "+" hecho con dos barras: la vertical gira hasta acostarse y queda "–". */
.memoria-signo {
  position: relative;
  width: 12px;
  height: 12px;
  margin-top: 0.45em;
  justify-self: end;
}

.memoria-signo::before,
.memoria-signo::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 2px;
  margin-top: -1px;
  background: currentColor;
  transition: transform 0.6s cubic-bezier(0.76, 0, 0.24, 1);
}

.memoria-signo::after {
  transform: rotate(90deg);
}

.memoria.is-open .memoria-signo::after {
  transform: rotate(180deg);
}

.memoria-panel {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition:
    grid-template-rows 0.75s cubic-bezier(0.76, 0, 0.24, 1),
    visibility 0s linear 0.75s;
}

.memoria.is-open .memoria-panel {
  grid-template-rows: 1fr;
  visibility: visible;
  transition: grid-template-rows 0.75s cubic-bezier(0.76, 0, 0.24, 1), visibility 0s;
}

.memoria-recorte {
  min-height: 0;
  overflow: hidden;
}

.memoria-cuerpo {
  padding: 8px 0 56px;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.memoria.is-open .memoria-cuerpo {
  opacity: 1;
  transition: opacity 0.7s ease 0.2s;
}

/* Al cambiar de proyecto, el anterior se cierra sin animación: js/memorias.js
   compensa el scroll en ese mismo instante para que la fila tocada no salte. */
.memoria.sin-transicion .memoria-panel,
.memoria.sin-transicion .memoria-cuerpo {
  transition: none;
}

.memoria-media {
  width: min(100%, calc(var(--memoria-max-h) * 9 / 16));
}

.memoria-detalle {
  margin-top: 36px;
}

/* Ficha estilo tabla técnica: pares etiqueta/valor, filete vertical y una
   lista mínima a la derecha. */
.memoria-ficha {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  margin-bottom: 44px;
}

.memoria-ficha dl {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-right: 14px;
}

.memoria-ficha dt {
  font-size: 10px;
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 2px;
}

.memoria-ficha dd {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
}

.memoria-ficha dd a {
  color: inherit;
  text-decoration: none;
}

.memoria-flecha {
  width: 0.62em;
  height: 0.62em;
  margin-left: 0.25em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}

.memoria-ficha ul {
  list-style: none;
  padding-left: 10px;
  border-left: 1px solid var(--rule);
  font-size: 10px;
  font-weight: 600;
  line-height: 1.25;
}

.memoria-texto {
  display: flex;
  flex-direction: column;
  gap: 1.15em;
  max-width: 56ch;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: -0.012em;
}

.memoria-completo {
  display: inline-block;
  margin-top: 32px;
  color: var(--accent);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.015em;
  text-decoration: none;
}

/* Galería con swipe nativo: en celular va con el dedo y en escritorio con
   trackpad o flechas. El touch-action reabre el gesto horizontal que html y
   body limitan a vertical. */
.galeria-pista {
  display: flex;
  aspect-ratio: var(--memoria-ratio);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
  background: var(--slot-bg);
}

.galeria-pista::-webkit-scrollbar {
  display: none;
}

.galeria-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.galeria-slide video,
.galeria-slide img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A la izquierda: a la derecha quedarían bajo el control fijo de sonido. */
.galeria-control {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
}

.galeria-flechas {
  display: flex;
}

.galeria-flecha {
  width: 44px;
  height: 44px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 18px;
  cursor: pointer;
  transition: opacity 0.25s ease;
}

.galeria-flecha:disabled {
  opacity: 0.3;
  cursor: default;
}

.galeria-flecha:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: -4px;
}

/* Botón sobre la portada de los proyectos audiovisuales ("videos" en proyectos.js). */
.galeria-marco {
  position: relative;
}

.ver-contenido {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  background: none;
  color: #e8e6e0;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.012em;
  white-space: nowrap;
  text-shadow: 0 0 10px rgb(0 0 0 / 0.55);
  cursor: pointer;
}

.ver-contenido:active {
  opacity: 0.6;
}

.ver-contenido:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: -6px;
}

/* Visor a pantalla completa (js/visor.js). */
html.visor-abierto {
  overflow: hidden;
}

.visor {
  position: fixed;
  z-index: 300; /* sobre la barra superior y el menú */
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  background: #000;
  color: #e8e6e0;
  animation: visor-entra 0.25s ease;
}

@keyframes visor-entra {
  from {
    opacity: 0;
  }
}

.visor-pista,
.visor-slide {
  position: absolute;
  inset: 0;
}

.visor-pista {
  overflow: hidden;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.visor-slide {
  visibility: hidden;
}

.visor-slide video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Símbolo de play: solo se ve con el video detenido. */
.visor-play {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.visor.en-pausa .visor-play {
  opacity: 0.8;
}

.visor-play svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
  filter: drop-shadow(0 0 6px rgb(0 0 0 / 0.5));
}

/* Área táctil de 44px alrededor de una línea fina. */
.visor-progreso {
  position: absolute;
  left: max(20px, env(safe-area-inset-left));
  right: max(20px, env(safe-area-inset-right));
  bottom: max(8px, env(safe-area-inset-bottom));
  height: 44px;
  display: flex;
  align-items: center;
  touch-action: none;
  cursor: pointer;
}

.visor-progreso::before,
.visor-avance {
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
}

.visor-progreso::before {
  content: "";
  background: rgb(232 230 224 / 0.3);
}

.visor-avance {
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
}

.visor-flecha,
.visor-cerrar {
  position: absolute;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  filter: drop-shadow(0 0 4px rgb(0 0 0 / 0.6));
}

.visor-flecha svg,
.visor-cerrar svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
}

.visor-flecha {
  top: 50%;
  width: 44px;
  height: 88px;
  margin-top: -44px;
  opacity: 0.45;
}

.visor-flecha svg {
  width: 22px;
  height: 22px;
}

.visor-flecha[data-paso="-1"] {
  left: max(2px, env(safe-area-inset-left));
}

.visor-flecha[data-paso="1"] {
  right: max(2px, env(safe-area-inset-right));
}

.visor-cerrar {
  top: max(9px, env(safe-area-inset-top));
  right: max(9px, env(safe-area-inset-right));
  width: 44px;
  height: 44px;
}

.visor-cerrar svg {
  width: 22px;
  height: 22px;
}

.visor-flecha:focus-visible,
.visor-cerrar:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: -4px;
}

@media (prefers-reduced-motion: reduce) {
  .visor {
    animation: none;
  }
}

/* Aparición discreta al entrar en pantalla (clase puesta en js/memorias.js). */
.aparece {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 1s ease, transform 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}

.aparece.is-in {
  opacity: 1;
  transform: none;
}

/* En pantalla ancha, video a la izquierda e información a la derecha. */
@media (min-width: 900px) {
  :root {
    --gutter: 28px;
  }

  .memoria-cuerpo {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gutter);
    padding-top: 16px;
  }

  .memoria-media {
    grid-column: 1 / span 5;
  }

  .memoria-detalle {
    grid-column: 7 / -1;
    margin-top: 0;
  }

  .memoria-ficha {
    max-width: 520px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .waffle-dot,
  .waffle:hover .waffle-dot {
    animation: none;
  }

  .waffle-grid,
  .waffle-dot,
  .menu-panel,
  .menu-enlace,
  .memoria-panel,
  .memoria-cuerpo,
  .memoria-signo::before,
  .memoria-signo::after,
  .aparece {
    transition-duration: 0.01ms;
    transition-delay: 0s;
  }

  .aparece {
    opacity: 1;
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   SWITCH DE IDIOMA (js/menu.js) — arriba a la izquierda, a la altura del
   menú wafle. El estado sale del atributo lang de la página. ═══ */

.idioma {
  position: fixed;
  z-index: 210; /* sobre el panel del menú, igual que el wafle */
  top: 9px;
  left: var(--gutter);
  height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0;
  border: 0;
  background: none;
  color: #161513;
  font-family: "Space Mono", monospace;
  font-weight: 700;
  font-size: clamp(10px, 2.6vw, 13px);
  cursor: pointer;
  transition: color 0.35s ease;
}

.idioma:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 2px;
}

.idioma-opcion {
  opacity: 0.5;
  transition: opacity 0.3s ease;
}

html[lang="es"] .idioma-opcion[data-opcion="es"],
html[lang="en"] .idioma-opcion[data-opcion="en"] {
  opacity: 1;
}

.idioma-pista {
  position: relative;
  width: 28px;
  height: 14px;
  border: 1px solid currentColor;
  border-radius: 7px;
}

.idioma-boton {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  transition: transform 0.45s cubic-bezier(0.76, 0, 0.24, 1);
}

html[lang="en"] .idioma-boton {
  transform: translateX(14px);
}

@media (prefers-reduced-motion: reduce) {
  .idioma-boton,
  .idioma-opcion {
    transition-duration: 0.01ms;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   PÁGINA PROPIA DE UN PROYECTO (proyecto.html, js/proyecto.js). ═══ */

.proyecto-page .waffle,
.proyecto-page .idioma {
  color: var(--ink);
}

.proyecto {
  padding: 90px var(--gutter) 24vh;
  font-family: var(--grotesk);
  color: var(--ink);
}

.proyecto-titulo {
  font-size: clamp(56px, 15vw, 190px);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.05em;
  margin-left: -0.03em;
  overflow-wrap: anywhere;
}

.proyecto-datos {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 18px 0 32px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
  color: var(--ink-soft);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.memoria-cuerpo.proyecto-intro {
  opacity: 1;
}

.proyecto-bloques {
  display: flex;
  flex-direction: column;
  gap: 72px;
  margin-top: 40px;
}

.bloque-texto {
  display: flex;
  flex-direction: column;
  gap: 1.15em;
  max-width: 56ch;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: -0.012em;
}

.bloque-texto h2 {
  font-size: clamp(32px, 8vw, 64px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.045em;
}

.bloque-media img,
.bloque-media video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--slot-bg);
}

.bloque-media.mediano {
  width: min(100%, 720px);
}

.bloque-galeria .galeria-pista {
  aspect-ratio: 16 / 9;
}

.bloque-galeria.vertical {
  width: min(100%, calc(var(--memoria-max-h) * 9 / 16));
}

.bloque-galeria.vertical .galeria-pista {
  aspect-ratio: var(--memoria-ratio);
}

.proyecto figcaption {
  margin-top: 8px;
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 600;
}

.proyecto-volver {
  display: inline-block;
  margin-top: 96px;
  color: inherit;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
}

.proyecto-aviso {
  font-size: clamp(32px, 8vw, 64px);
  font-weight: 700;
  letter-spacing: -0.045em;
}

.proyecto-aviso + .proyecto-volver {
  margin-top: 32px;
}

@media (min-width: 900px) {
  .bloque-texto {
    margin-left: calc(50% + var(--gutter) / 2);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   CONTACTO (final de Inicio, js/contacto.js) — una perilla dentro de una
   cápsula: se arrastra hasta la flecha para abrir el correo. ═══ */

.muestra {
  padding-bottom: 106px; /* ← distancia entre la última fila de la galería y Contacto */
}

.contacto-seccion {
  display: flex;
  justify-content: space-between; /* cápsula a la izquierda, leyenda a la derecha */
  align-items: center; /* la leyenda queda a la altura del centro de la cápsula */
  gap: 16px;
  padding: 0 var(--gutter) 80px; /* ← 80px: espacio libre bajo la cápsula */
}

.contacto {
  flex-shrink: 0;
}

/* © a la derecha de la cápsula: gris y del mismo tamaño que CONTACTO. */
.contacto-legal {
  font-family: var(--grotesk);
  font-size: 10px; /* ← igual que .contacto-perilla */
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.4;
  color: var(--ink-soft);
  text-align: right;
}

.contacto {
  --contacto-borde: 3px; /* ← separación entre la perilla y la orilla de la cápsula */
  --contacto-alto: 34px; /* ← alto de la cápsula */
  --contacto-ancho: 130px; /* ← ancho de la cápsula */
  --contacto-perilla: #ffffff84; /* ← color de la perilla */
  --avance: 0; /* 0 = perilla a la izquierda, 1 = sobre la flecha (lo mueve js/contacto.js) */
  position: relative;
  width: var(--contacto-ancho);
  height: var(--contacto-alto);
  border-radius: 999px;
  background: rgb(255 255 255 / 0.07);
  box-shadow:
    inset 0 2px 5px rgb(0 0 0 / 0.55),
    inset 0 -1px 0 rgb(255 255 255 / 0.05);
  font-family: var(--grotesk);
  user-select: none;
  -webkit-user-select: none;
}

.contacto-flecha {
  position: absolute;
  top: 50%;
  right: 9px;
  width: 15px;
  height: 15px;
  color:  #0000007e;
  transform: translateY(-50%);
  opacity: calc(1 - var(--avance)); /* se apaga al llegar la perilla (se trasluciría) */
  pointer-events: none;
}

.contacto-flecha path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.contacto-perilla {
  position: absolute;
  top: var(--contacto-borde);
  left: var(--contacto-borde);
  height: calc(var(--contacto-alto) - 2 * var(--contacto-borde));
  padding: 0 18px; /* ← ancho de la perilla: menos = más recorrido para arrastrar */
  border: 0;
  border-radius: 999px;
  background: var(--contacto-perilla);
  color: #141312;
  font: inherit;
  font-size: 10px; /* ← tamaño de CONTACTO */
  font-weight: 600;
  letter-spacing: 0.06em; /* las mayúsculas respiran mejor un poco abiertas */
  text-transform: uppercase;
  white-space: nowrap;
  cursor: grab;
  touch-action: pan-y; /* el scroll vertical sigue libre; lo horizontal mueve la perilla */
  -webkit-tap-highlight-color: transparent;
  box-shadow:
    0 6px 14px rgb(0 0 0 / 0.45),
    0 1px 2px rgb(0 0 0 / 0.5),
    inset 0 -2px 4px rgb(0 0 0 / 0.08);
}

.contacto-perilla:active {
  cursor: grabbing;
}

.contacto-perilla:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

.contacto.is-suelta .contacto-perilla {
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.contacto.is-suelta .contacto-flecha {
  transition: opacity 0.45s ease;
}

/* Un toque sin arrastrar: la perilla se asoma hacia la flecha y regresa. */
.contacto.is-insinua .contacto-perilla {
  animation: contacto-insinua 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes contacto-insinua {
  40% {
    transform: translateX(14px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .contacto.is-insinua .contacto-perilla {
    animation: none;
  }
}
