/* ============ TOKENS ============ */
  @font-face{
  font-family: 'Barriecito';
  src: url('assets/fonts/Barriecito.ttf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
:root{
  --ink: #14130F;
  --ink-soft: #1D1B14;
  --paper: #EFEDE5;        /* gris cálido, clarito — fondo cuaderno */
  --paper-card: #F8F6EF;
  --paper-dark: #DCD8C9;
  --grid-line: rgba(20,19,15,0.075);
  --cherry: #DB812E;
  --moss: #59883F;
  --bone: #F2EEE3;
  --graphite: #8A8575;
  --graphite-dark: #6b6657;

  /* paleta de fondos de hover — de la referencia que compartiste */
  --pal-rosa: #C7A1B6;
  --pal-ciruela: #2E2233;
  --pal-azul: #56A8B8;
  --pal-verde-oscuro: #212E02;
  --pal-mostaza: #E7B84E;
  --pal-naranja: #DB812E;
  --pal-coral: #cd4f28;
  --pal-salvia: #59883F;

  --display: 'Fraunces', serif;
  --body: 'Inter', sans-serif;
  --mono: 'IBM Plex Mono', monospace;

  --maxw: 1200px;
  --header-h: 72px;
  --footer-h: 34px;
}



*{ box-sizing: border-box; }
html{ scroll-behavior: auto; } /* el smooth se maneja por JS en los links del nav, para no chocar con el scroll animado */
body{
  margin:0;
  overflow-x: hidden; /* red de seguridad: ninguna tarjeta/animación debe generar scroll horizontal */
  color: var(--ink);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;

  /* ===== cuadrícula tipo cuaderno, gris cálido + un poquito de grano ===== */
  background-color: var(--paper);
  background-attachment: fixed; /* la cuadrícula nunca se desplaza, sin importar el scroll — hasta salir del stage, ver .grid-scrolls */
  background-image:
    repeating-linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px 28px),
    repeating-linear-gradient(to bottom, var(--grid-line) 0 1px, transparent 1px 28px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='0.025'/></svg>");
}
/* una vez se cruza de la mesa hacia la sección de contacto (o se
   vuelve a entrar al stage haciendo scroll hacia arriba), JS alterna
   esta clase — la cuadrícula pasa a moverse con el documento en vez
   de quedarse fija respecto al viewport */
body.grid-scrolls{
  background-attachment: scroll;
}
img{ display:block; max-width:100%; }
a{ color: inherit; text-decoration: none; }
ul{ margin:0; padding:0; list-style:none; }
button{ font-family: inherit; }

.wrap{ max-width: var(--maxw); margin: 0 auto; padding: 0 2rem; }
@media (max-width: 720px){ .wrap{ padding: 0 1.25rem; } }

.eyebrow{
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--graphite);
  margin: 0 0 0.75rem;
}

/* ============ HEADER — flotante, sin recuadro ============ */
.site-header{
  position: fixed; top:0; left:0; right:0; z-index: 200;
  height: var(--header-h);
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 2rem;
  pointer-events: none; /* solo lo clickeable recupera pointer-events abajo */
}
.site-header .logo{
  font-family: var(--display); font-weight: 600; font-size: 1.05rem;
  color: var(--ink); pointer-events: auto;
}
.header-floating{
  display:flex; gap: 3rem;
  font-family: var(--body); font-size: 0.85rem; color: var(--graphite-dark);
}
/* el texto visible ("Bogotá, Colombia") se centra en la pantalla —
   igual que el H1 del hero, que también está centrado — en vez de
   quedar donde lo deja el space-between entre el logo y el nav (que
   se mueve según cuánto midan esos dos). position:absolute lo saca
   del flujo del header-floating (que sigue existiendo pero ahora sin
   ancho visible), y se posiciona relativo al .site-header (el
   ancestro fixed más cercano). */
.header-floating span:last-child{
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
}
.nav-list{
  display:flex; flex-direction:column; align-items:flex-end; gap: 0.32rem;
  pointer-events: auto;
  /* el header centra verticalmente a sus 3 hijos (logo, header-floating,
     nav-list) por defecto — eso funciona bien para el logo y "Bogotá,
     Colombia", que son una sola línea, pero el nav-list son 3 líneas
     apiladas: centrado como bloque, su primera línea queda mucho más
     arriba que el resto de los textos del header. align-self:flex-start
     lo saca de ese centrado automático, y el margin-top lo baja hasta
     que su primera línea quede a la misma altura que el logo. */
  align-self: flex-start;
  margin-top: 1.45rem;
}

.nav-list a{
  display:flex; align-items:center; gap: 0.45rem;
  font-family: var(--mono); font-size: 0.76rem; letter-spacing: 0.04em;
  color: var(--graphite-dark);
  transition: color .2s ease;
}
.nav-list a::before{
  content:''; width: 5px; height: 5px; border-radius: 50%;
  background: transparent; transition: background .2s ease;
}
.nav-list a.is-active::before{ background: var(--cherry); }
.nav-list a:hover, .nav-list a:focus-visible{ color: var(--ink); }

/* ---- hamburguesa: solo existe visualmente por debajo de 760px; en
   escritorio el nav ya se ve completo, no hace falta el botón ---- */
.nav-toggle{
  display:none;
  width: 26px; height: 18px;
  flex-direction: column; justify-content: space-between;
  background:none; border:none; padding:0; cursor:pointer;
  color: var(--ink); /* las líneas usan currentColor, así heredan el
                        mismo tween de color que el logo/nav al aparecer
                        el verde de contacto */
  pointer-events: auto;
}
.nav-toggle span{
  display:block; height:2px; width:100%; background: currentColor;
  transition: transform .25s ease, opacity .2s ease;
}
.nav-toggle.is-open span:nth-child(1){ transform: translateY(8px) rotate(45deg); }
.nav-toggle.is-open span:nth-child(2){ opacity:0; }
.nav-toggle.is-open span:nth-child(3){ transform: translateY(-8px) rotate(-45deg); }

@media (max-width: 760px){
  .header-floating{ display:none; }
  .site-header{ height: 58px; padding: 0 1.2rem; }
  .nav-toggle{ display:flex; }

  /* el nav pasa de fila visible a panel desplegable, anclado a la
     derecha bajo el header */
  .nav-list{
    position: fixed; top: 58px; right: 1.1rem;
    flex-direction:column; align-items:flex-end; gap:0;
    margin-top: 0; /* el offset de escritorio no aplica: acá ya se posiciona con position:fixed + top */
    background: var(--paper-card);
    border: 1px solid rgba(20,19,15,0.14);
    border-radius: 6px;
    padding: 0.5rem 0;
    box-shadow: 0 20px 40px -12px rgba(20,19,15,0.35);
    opacity:0; transform: translateY(-8px);
    pointer-events:none;
    transition: opacity .2s ease, transform .2s ease;
  }
  .nav-list.is-open{ opacity:1; transform: translateY(0); pointer-events:auto; }
  .nav-list a{ padding: 0.6rem 1.2rem; width: 100%; justify-content:flex-end; }
  .nav-list a::before{ display:none; }
}

/* ============ ESCENA ANCLADA — bienvenida + mesa superpuestas ============ */
.stage{
  position: relative;
  min-height: 100vh;
}
.stage-layer{
  display:flex; align-items:center; justify-content:center;
  padding: var(--header-h) 2rem var(--footer-h);
}
@media (min-width: 1025px){
  .stage-layer{ position:absolute; inset:0; }
}

.hero-layer{ text-align:center; z-index: 1; }
.desk-layer{ z-index: 2; flex-direction: column; }
/* por debajo de 1025px .stage-layer ya no es position:absolute (ver
   más abajo), así que hero-layer y desk-layer quedan uno debajo del
   otro en el flujo normal — sin esto, la mesa asomaba en la primera
   pantalla apenas se entraba al sitio. Con min-height:100vh el hero
   ocupa toda la primera pantalla y las tarjetas solo aparecen al
   hacer scroll de verdad.
   Mismo alto para desk-layer: además de evitar el asomo, hace que
   cada sección sea exactamente "una pantalla", que es lo que necesita
   el scroll-snap vertical de abajo para que el aterrizaje se sienta
   como una pantalla completa y no a medias. */
@media (max-width: 1024px){
  html{ scroll-snap-type: y mandatory; }
  .hero-layer{ min-height: 100vh; scroll-snap-align: start; scroll-snap-stop: always; }
  .desk-layer{ min-height: 100vh; scroll-snap-align: start; scroll-snap-stop: always; transform: translateY(-5%); }
  .about-teaser{ scroll-snap-align: start; }
  .hero-layer .hero-inner{ transform: translateY(0%); } /* en escritorio baja 5% a propósito (parte de la coreografía del pin); en táctil no aplica y solo hacía que se viera más abajo de lo necesario */
}
.hero-inner{ max-width: 640px; transform: translateY(5%); }
.hero-inner h1{
  font-family: var(--display); font-weight: 500;
  font-size: clamp(2.1rem, 6vw, 4rem); line-height: 1.1;
  margin: 0.6rem 0 1.6rem;
}
.hero-inner h1 .line{
  display:block; opacity:0; transform: translateY(0.6em);
  animation: lineUp .8s cubic-bezier(.2,.7,.2,1) forwards;
}
.hero-inner h1 .line:nth-child(2){ animation-delay: .12s; }
.hero-inner h1 .line:nth-child(3){ animation-delay: .24s; }
.hero-inner h1 .line.accent{ color: var(--cherry); font-family: 'Barriecito'; }
@keyframes lineUp{ to{ opacity:1; transform: translateY(0); } }

.hero-words{
  display:flex; flex-wrap:wrap; justify-content:center;
  gap: 0.6rem 0.8rem; margin: 1.6rem 0 2.4rem;
}
.word-tag{
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.03em;
  border: 1px dashed rgba(20,19,15,0.3); padding: 0.32rem 0.7rem; border-radius: 2px;
  transform: rotate(var(--r, 0deg)); color: var(--graphite-dark);
  opacity:0; animation: fadeIn .6s ease forwards .5s;
}
@keyframes fadeIn{ to{ opacity:1; } }
.scroll-hint{
  font-family: var(--mono); font-size: 0.7rem; color: var(--graphite);
  opacity:0; animation: fadeIn .6s ease forwards .9s;
}

/* ---- capa de la mesa: vacía/invisible al inicio (GSAP la anima) ---- */
.desk-inner{
  position: relative;
  max-width: var(--maxw);
  margin: 0 auto;
  width: 100%;
  padding: 0 2rem;
  min-height: 920px;
}
/* en pantallas más bajas que anchas (laptops chicos), .stage sólo mide
   100vh (min-height, sin contenido en flujo que lo estire) y GSAP lo fija
   así durante el pin — si desk-inner insistiera en sus 920px fijos,
   la composición se saldría por arriba/abajo de esa caja, empujando la
   fila superior de tarjetas fuera de la pantalla y sin forma de hacer
   scroll para alcanzarlas (queda fijo). Por eso el alto real nunca debe
   superar el espacio vertical disponible entre header y footer. */
@media (min-width: 1025px){
  .desk-inner{ min-height: 0; height: min(920px, calc(100vh - var(--header-h) - var(--footer-h))); }
}
/* ---- zona táctil (celular a tablet, hasta 1024px): nada de collage
   absoluto ni arrastre — carrusel horizontal con scroll-snap nativo
   (sin librería), una tarjeta centrada a la vez con las vecinas
   asomando a los lados. Al soltar el dedo, el navegador "imanta" la
   tarjeta más centrada (scroll-snap-align:center) — script.js detecta
   cuál quedó centrada y revela su nombre ~1s después de asentarse.
   El ancho es en vw así escala igual de celular a tablet. ---- */
@media (max-width: 1024px){
  .desk-layer{ padding-left: 0; padding-right: 0; } /* .stage-layer le hereda 2rem de padding lateral — eso recortaba el ancho real disponible para el carrusel, que necesita llegar de borde a borde */
  .desk-inner{
    min-height: 0; display:flex; flex-direction:row; flex-wrap:nowrap; align-items:center;
    gap: 1rem;
    overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding: 0 12vw;
    scroll-padding: 0 12vw;
    scrollbar-width: none; -ms-overflow-style: none; /* Firefox / IE viejo */
  }
  .desk-inner::-webkit-scrollbar{ display:none; } /* Chrome/Safari/Android */
  .desk-inner .sheet, .desk-inner .sheet--sm{
    flex: 0 0 76vw; max-width: 76vw; margin: 0;
    scroll-snap-align: center;
  }
  /* la foto mide siempre lo mismo (alto fijo) para que todas las
     tarjetas queden alineadas — pero la imagen adentro sigue
     mostrándose completa, sin recortar: se ajusta por contención
     (letterbox) en vez de por cover. La foto conserva su proporción
     real, solo cambia cuánto espacio en blanco queda alrededor. */
  .desk-inner .scan-photo{
    height: 42vh; max-height: 360px; min-height: 220px;
    display:flex; align-items:center; justify-content:center;
  }
  .desk-inner .scan-photo img{
    width:auto; height:100%; max-width:100%; max-height:100%;
    object-fit: contain;
  }
  /* la etiqueta con el nombre pasa de "flotante" (position:absolute,
     pensado para el collage de escritorio) a flujo normal, justo
     debajo de la foto — así el contenedor SÍ cuenta su altura real.
     Antes quedaba fuera de la caja (absolute no suma altura al
     padre), lo que forzaba un scroll vertical interno no deseado y
     cortaba el texto. Queda reservado el espacio siempre (aunque
     esté en opacity:0 hasta revelarse) para que no haya salto de
     layout cuando aparece. */
  .desk-inner .scan-caption{
    position: static;
    margin: 0.5rem 0 0;
    width: 100%; max-width: 100%;
    align-items: center; text-align: center;
  }
  .desk-swipe-hint{ display:block; }
}
.desk-swipe-hint{
  display:none;
  text-align:center;
  font-family: var(--mono); font-size: 0.68rem; color: var(--graphite);
  margin: 0.9rem 0 0;
}
.desk-heading{
  display:none;
  text-align:center;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--graphite-dark);
  margin: 0 0 1.1rem;
}
@media (max-width: 1024px){
  .desk-heading{ display:block; }
}

/* ---- sheet (base, mobile-first = static stack) ----
   Estructura: scan de boceto/papel a tamaño natural (.scan-inner >
   .scan-photo) + texto de proyecto (nombre, tipo, fecha) debajo del
   scan, alineado a la derecha (.scan-caption). En hover, el scan se
   inclina levemente (--hover-tilt, definido inline por tarjeta) y el
   texto aparece con un fade. En móvil no hay hover, así que el texto
   queda visible desde el inicio y no hay inclinación extra. ---- */
.sheet{
  display:block;
  position: relative;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  /* sin transition de opacity/visibility aquí: GSAP controla la opacidad
     de entrada por scroll-scrub frame a frame, y una transition CSS en la
     misma propiedad competía con eso — el navegador reinterpolaba cada
     frame que GSAP ya estaba escribiendo, así que la tarjeta nunca se
     veía del todo sólida (siempre "persiguiendo" el valor real, un paso
     por detrás). Ver .is-hidden abajo para el toggle de abrir/cerrar
     ventana, que ahora es instantáneo por la misma razón. */
}

/* la tarjeta se oculta mientras su ventana está abierta — no tiene
   sentido ver la vista previa Y la ventana al mismo tiempo. !important
   porque GSAP (animación de entrada / scroll-scrub) controla opacity
   y visibility como estilos inline, que de otro modo le ganarían a
   esta clase sin importar el orden o la especificidad */
.sheet.is-hidden{
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* ---- scan-inner: envoltura que recibe la inclinación de hover,
   independiente de la rotación base que GSAP aplica inline al .sheet
   (así no compiten por la misma propiedad transform) ---- */
.scan-inner{
  position: relative;
  transform: rotate(0deg);
  transform-origin: 50% 50%;
  transition: transform .4s cubic-bezier(.2,.7,.2,1);
}
.sheet:hover .scan-inner, .sheet:focus-visible .scan-inner{
  transform: rotate(var(--hover-tilt, -3deg)) scale(1.03);
}
/* al frente de todas las demás tarjetas mientras está en hover/focus —
   solo importa en desktop, donde las tarjetas están position:absolute
   con z-index propio; en móvil (flujo normal) esto no tiene efecto */
.sheet:hover, .sheet:focus-visible{ z-index: 20; }

/* ---- el scan en sí: tamaño natural (sin recortar la proporción
   real del papel), fondo transparente — solo se ve el PNG ---- */
.scan-photo{
  position: relative;
  width: 100%;
  min-height: 90px;
  background: transparent;
  border-radius: 2px;
  overflow: hidden;
}
.scan-photo .img-fallback{
  position: absolute; inset: 0; z-index: 1;
  display:flex; align-items:center; justify-content:center;
  font-family: var(--mono); font-size: 0.65rem; color: var(--graphite-dark);
  text-align:center; padding: 0.6rem;
}
.scan-photo img{
  position: relative; z-index: 2;
  display:block; width:100%; height:auto;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

/* ---- texto que aparece en hover: debajo del scan (no superpuesto),
   alineado a la derecha — position:absolute con top:100% para que no
   ocupe espacio propio en el flujo ni empuje otras tarjetas ---- */
.scan-caption{
  position: absolute; top: 100%; right: 0; z-index: 5;
  margin-top: 0.5rem;
  display: flex; flex-direction: column; align-items: flex-end;
  width: fit-content;
  max-width: 92%;
  padding: 0.55rem 1.5rem;
  border-radius: 999px; /* siempre "pill" sin importar cuántas líneas tenga adentro */
  background: var(--caption-bg, var(--paper-card));
  color: var(--caption-fg, var(--ink));
  text-align: right;
  opacity: 0; transform: translateY(-4px);
  transition: opacity .3s ease, transform .3s ease;
  pointer-events: none;
}
.sheet:hover .scan-caption, .sheet:focus-visible .scan-caption{
  opacity: 1; transform: translateY(0);
}
.scan-caption h3{
  font-family: var(--display); font-weight: 500; font-size: 0.9rem; line-height: 1.15;
  margin: 0 0 0.2rem; color: currentColor;
}
.scan-caption h4{
  font-family: var(--display); font-weight: 500; font-size: 0.9rem; line-height: 1.15;
  margin: 0 0 0.15rem; color: currentColor;
}
.scan-caption .meta{
  font-family: var(--mono); font-size: 0.66rem; color: currentColor; opacity: 0.72;
}

.sheet--sm{ max-width: 190px; }

/* las tarjetas de archivo son angostas (foto chica), pero su texto de
   hover no debe heredar ese ancho — con títulos más largos, atarlo al
   ancho de la foto las hacía envolver a 3 líneas en laptops angostas
   (~1025–1150px), mientras que las tarjetas protagonistas (mucho más
   anchas) nunca pasaban de 2. Un min-width propio nivela el resultado
   visual sin tocar el tamaño real de la foto/tarjeta. */
.sheet--sm .scan-caption{ min-width: 210px; max-width: none; }

/* ---- pantallas táctiles (<1024px, ver isDesktop() en script.js): no
   hay hover fiable, así que el nombre no se revela solo — se revela
   automáticamente cuando la tarjeta queda centrada por el carrusel
   (ver script.js), junto con el hint "Abrir proyecto" (ver más abajo,
   dentro del bloque del carrusel). Tampoco se aplica el tilt de
   hover, que no tiene sentido sin puntero. ---- */
.sheet.is-revealed .scan-caption{
  opacity: 1; transform: translateY(0);
}
@media (max-width: 1024px){
  .scan-inner{ transform: none !important; }
}


/* ---- desktop real (mouse, >1024px): tarjetas grandes, proporciones
   distintas, ocupando la mayor parte del área disponible en una
   composición tipo collage ---- */
@media (min-width: 1025px){
  .sheet{ position:absolute; }

  /* anchos relativos al contenedor (desk-inner) en vez de px fijos, así
     las tarjetas escalan juntas y conservan su posición relativa sin
     desbordar los bordes de la pantalla en laptops angostas; el clamp()
     evita que se vuelvan ilegibles en el extremo angosto del rango */
  /* max-width es un techo de seguridad además del clamp(): garantiza que,
     sin importar qué tan angosto sea el contenedor, el borde derecho de
     la tarjeta (left + width) nunca cruce el borde del escritorio — el
     piso en px del clamp() deja de bajar en algún punto, pero este techo
     sigue bajando con el contenedor, así que siempre gana el que sea
     más chico. Se acepta que las tarjetas se traslapen entre sí antes
     que salirse de la pantalla. */
    .sheet--clarito{ top: 20%; left: 3%; width: clamp(150px, 26.7%, 320px); max-width: calc(98% - 3%); z-index:2; }      /* retrato, protagonista */
  .sheet--territorios{ top: -10%; left: 35%; width: clamp(168px, 30.6%, 368px); max-width: calc(98% - 50%); z-index:1; }  /* panorámica, la más ancha */
  .sheet--catacion{ top: 15%; left: 70%; width: clamp(150px, 26.7%, 320px); max-width: calc(98% - 57%); z-index:1; }     /* cuadrada */
  .sheet--listening{ top: 60%; left: 13%; width: clamp(160px, 28.3%, 340px); max-width: calc(98% - 13%); z-index:1; }   /* pisa la esquina de clarito */

  /* pila de archivo: agrupadas y traslapadas, con la de en medio
     escondida detrás de las otras dos */
  .sheet--bioamazonia{ top: 50%; left: 60%; width: clamp(110px, 15.8%, 190px); max-width: min(190px, calc(98% - 27%)); z-index:1; }
  .sheet--rastrillo{ top: 55%; left: 80%; width: clamp(110px, 15.8%, 190px); max-width: min(190px, calc(98% - 68%)); z-index:3; }
  .sheet--kabadaura{ top: 65%; left: 65%; width: clamp(156px, 20.5%, 247px); max-width: min(247px, calc(98% - 60%)); z-index:2; }
  /* la rotación la controla GSAP (data-rotate) para poder animar entrada/salida sin pelearse con el transform */
}


/* ============ ABOUT + CONTACTO — pantalla 3 ============
   Ya no tiene un fondo sólido fijo: arranca igual que el resto del
   sitio (cuadrícula clara heredada del body) y, a medida que se hace
   scroll hacia esta sección, .contact-bg (mismo verde oscuro, sin
   patrón de cuadrícula) se revela por detrás del contenido, mientras
   el color del texto pasa de oscuro a claro en el mismo tramo — todo
   scrubbed por GSAP en script.js. Contenido centrado en una sola
   columna (ya no hay foto/columna derecha). */
.about-teaser{
  min-height: 100vh;
  display:flex; align-items:center;
  position: relative;
  color: var(--ink);
  padding: var(--header-h) 0 var(--footer-h);
}
.contact-bg{
  position: fixed; inset: 0; z-index: -1; /* detrás de absolutamente todo, cubre siempre el viewport completo */
  pointer-events: none;
  opacity: 0; /* GSAP la anima a 1 según el scroll, ver script.js */
  background-color: var(--pal-verde-oscuro);
  background-image:
    radial-gradient(circle at 30% 30%, rgba(242,238,227,0.06) 0, transparent 45%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='0.04'/></svg>");
}
.about-teaser .wrap{
  position: relative; z-index: 1;
  display:flex; flex-direction:column; align-items:center; text-align:center;
  max-width: 640px; margin: 0 auto;
}
.about-teaser .eyebrow{ color: var(--graphite); }

.contact-heading{
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(1.7rem, 3.4vw, 2.4rem); line-height: 1.15;
  margin: 0.2rem 0 1.3rem;
}
/* ---- el nombre lleva la misma tipografía de acento del H1 del hero
   (Barriecito + cherry) — por eso no hereda el itálico ni la fuente
   del resto del encabezado, y su color queda fijo en cherry en vez de
   animar a blanco con el resto del texto (igual que el acento del
   hero, que tampoco cambia de color al hacer scroll). ---- */
.name-wrap{ position: relative; display: inline-block; }
.name-trigger{
  font-family: 'Barriecito'; font-style: normal; font-weight: 400;
  font-size: inherit; line-height: inherit; color: var(--cherry);
  background: none; border: none; padding: 0; margin: 0;
  cursor: pointer;
}
.contact-copy p{
  font-family: var(--body); font-size: 0.95rem; line-height: 1.62;
  color: currentColor; opacity: 0.85;
  max-width: 46ch; margin: 0 auto 1rem;
}
.contact-copy p:last-child{ margin-bottom: 1.5rem; }
.contact-current{
  font-family: var(--mono); font-size: 0.8rem; line-height: 1.5;
  color: currentColor; opacity: 0.8;
  max-width: 40ch; margin: 0 auto 1.9rem;
}
.contact-current .current-label{
  display:block; text-transform: uppercase; letter-spacing: 0.06em;
  font-size: 0.66rem; opacity: 0.68; margin-bottom: 0.3rem;
}

/* ---- nota de intereses: por ahora una imagen placeholder (luego la
   reemplazas por tu PNG con tu letra), emerge encima del nombre al
   pasar el mouse o al hacer clic/foco (para táctil y teclado). ---- */
.interest-note{
  --note-w: 210px;
  position: absolute;
  bottom: 100%;
  left: 50%;
  width: var(--note-w);
  border-radius: 2px;
  box-shadow: 0 16px 30px -10px rgba(0,0,0,0.4);
  transform: translate(-50%, -6px) rotate(-3deg);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
  z-index: 6;
}
.interest-note::before{
  content:''; position:absolute; top:-9px; left: 50%;
  width: 38px; height: 15px; margin-left: -19px;
  background: rgba(143,173,142,0.65); transform: rotate(-4deg);
  z-index: 3;
}
.interest-note .img-fallback{
  position: relative; z-index: 1;
  display:flex; align-items:center; justify-content:center;
  background: var(--bone); color: var(--ink);
  min-height: 110px; padding: 1rem 1.1rem; border-radius: 2px;
  font-family: var(--mono); font-size: 0.7rem; line-height: 1.5; text-align:center;
}
.interest-note img{
  position: relative; z-index: 2;
  display:block; width:100%; height:auto; border-radius: 2px;
}
.name-trigger:hover + .interest-note,
.name-trigger:focus-visible + .interest-note,
.interest-note.is-visible{
  opacity: 1; pointer-events: auto; transform: translate(-50%, -16px) rotate(-3deg);
}
@media (max-width: 800px){
  .interest-note{ --note-w: 180px; }
}

.contact-actions{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap: 1rem 1.2rem; margin-top: 0;
}
.btn-cv{
  font-family: var(--mono); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em;
  background: var(--cherry); color: var(--bone);
  padding: 0.65rem 1.1rem; border-radius: 3px;
  transform: rotate(-1deg);
  transition: transform .2s ease;
}
.btn-cv:hover{ transform: rotate(0deg) translateY(-2px); }

/* ---- botones secundarios (LinkedIn, CV): mismo lenguaje de borde
   punteado que ya usan los tags/chips del sitio, para que se lean
   como "botón" (no como link de texto suelto) sin competir con el
   acento sólido de btn-cv ---- */
.btn-ghost{
  font-family: var(--mono); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: currentColor; opacity: 0.82;
  border: 1px dashed currentColor; border-radius: 3px;
  padding: 0.62rem 1.05rem;
  transition: color .2s ease, border-color .2s ease, opacity .2s ease, transform .2s ease;
}
.btn-ghost:hover{ color: var(--cherry); border-color: var(--cherry); opacity: 1; transform: translateY(-2px); }

/* ============ FOOTER — fijo, chiquito ============ */
.site-footer{
  position: fixed; left:0; right:0; bottom:0; z-index: 200; /* ← 200 es mayor que 150 del dog-ear */
  height: var(--footer-h);
  display:flex; align-items:center; gap: 0.9rem;
  padding: 0 1.4rem;
  background: var(--paper-card);
  border-top: 1px dashed rgba(20,19,15,0.25);
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--graphite-dark);
}
.site-footer > span:last-child{ margin-left: auto; }
.footer-divider{ opacity: 0.4; }
.site-footer a{ border-bottom: 1px dashed currentColor; }
.site-footer a:hover{ color: var(--cherry); }
@media (max-width: 600px){
  .site-footer{ font-size: 0.6rem; gap: 0.6rem; padding: 0 0.9rem; }
}

/* ============ BANNER "abrir en escritorio" ============
   Misma forma de píldora que las etiquetas de nombre de proyecto
   (.scan-caption: border-radius 999px), pero con fondo negro fijo en
   vez de un color de la paleta por proyecto — y tipografía mono, igual
   a la del "tipo · fecha" de esas mismas etiquetas (.scan-caption .meta).
   Solo se muestra en táctil (JS decide, ver script.js) y solo si no se
   cerró antes (localStorage). Oculto por completo en escritorio real.
   Entrada: JS agrega .is-ready de una vez (display:flex, pero todavía
   invisible) y .is-visible 2s después (dispara la transición de
   opacity+transform) — necesita ese paso intermedio porque no se puede
   animar directo desde display:none. */
.desktop-banner{
  display:none;
  position: fixed;
  top: calc(var(--header-h) + 8px);
  left: 50%;
  z-index: 300;
  width: 80%;
  align-items: center;
  gap: 0.6rem;
  background: #000;
  color: var(--bone);
  border-radius: 999px;
  padding: 0.6rem 2.3rem 0.6rem 1.15rem;
  box-shadow: 0 16px 30px -10px rgba(0,0,0,0.45);
  opacity: 0;
  transform: translate(-50%, -18px);
  transition: opacity .5s ease, transform .5s ease;
  pointer-events: none;
}
.desktop-banner.is-ready{ display:flex; }
.desktop-banner.is-visible{ opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.desktop-banner-text{
  font-family: var(--mono); font-size: 0.7rem; line-height: 1.4;
}
.desktop-banner-close{
  position: absolute; top: -8px; right: -8px;
  width: 22px; height: 22px; border-radius: 50%;
  background: #000; color: var(--bone);
  border: 1px solid rgba(242,238,227,0.4);
  font-size: 0.8rem; line-height: 1; padding: 0;
  display:flex; align-items:center; justify-content:center;
  cursor: pointer;
}
@media (max-width: 760px){
  .desktop-banner{ top: 66px; } /* el header mide 58px en este corte, --header-h se queda en 72px (pensado para escritorio) */
}
@media (min-width: 1025px){
  .desktop-banner{ display:none !important; } /* nunca en escritorio real, sin importar localStorage */
}

/* ============ WINDOW LAYER — sin overlay, varias ventanas conviven ============ */
#windowLayer{
  position: fixed; inset:0;
  z-index: 400;
  pointer-events: none;
}

/* ---- botón flotante "Cerrar todo" — oculto por defecto, aparece
   apenas se abre la primera ventana. Vive por fuera de #windowLayer
   así que no necesita pointer-events extra. ---- */
.close-all-btn{
  position: fixed;
  right: 1.4rem;
  bottom: calc(var(--footer-h) + 16px);
  z-index: 500;
  display: none;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--ink); color: var(--bone);
  border: none; border-radius: 4px;
  padding: 0.65rem 1.05rem;
  cursor: pointer;
  box-shadow: 0 16px 30px -10px rgba(20,19,15,0.4);
  transition: transform .2s ease, background .2s ease;
}
.close-all-btn.is-visible{ display: block; }
.close-all-btn:hover{ background: var(--cherry); transform: translateY(-2px); }
@media (max-width: 760px){
  .close-all-btn{ right: 0.9rem; bottom: calc(var(--footer-h) + 12px); font-size: 0.66rem; padding: 0.55rem 0.85rem; }
}

.proj-window{
  position: absolute;
  pointer-events: auto;
  background: var(--paper-card);
  color: var(--ink);
  border: 1px solid rgba(20,19,15,0.15);
  border-radius: 8px;
  box-shadow: 0 30px 60px -15px rgba(20,19,15,0.35);
  display:flex; flex-direction:column;
  overflow:hidden;
}

.win-bar{
  display:flex; align-items:center; justify-content:space-between;
  padding: 0.55rem 0.8rem;
  background: var(--paper-dark);
  border-bottom: 1px solid rgba(20,19,15,0.12);
  cursor: grab;
  user-select: none;
  flex-shrink: 0;
}
.win-bar:active{ cursor: grabbing; }
.win-title{ font-family: var(--mono); font-size: 0.74rem; color: var(--graphite-dark); }
.win-controls{ display:flex; gap: 0.45rem; }
.win-btn{
  width: 16px; height: 16px; border-radius: 50%; border: none; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  font-size: 0.65rem; line-height:1; color: rgba(20,19,15,0.55); padding:0;
}
.win-min{ background:#E8C468; }
.win-max{ background:#7FAE6E; }
.win-close{ background:#C1574A; color:#fff; }

.win-content{
  position: relative;
  flex: 1; min-height: 0;
}

/* ---- franja invisible a la derecha: dispara el menú al pasar el mouse ---- */
.win-hover-zone{
  position:absolute; top:0; right:0; width: 46px; height:100%;
  z-index: 5;
}

/* ---- menú de navegación interna: las rayas quedan siempre visibles
   (una por sección); al hacer hover aparece el fondo + las etiquetas ---- */
.win-outline{
  position:absolute; top:50%; right: 10px; z-index: 6;
  transform: translateY(-50%);
  display:flex; flex-direction:column; align-items:flex-end; gap: 0.5rem;
  padding: 0.7rem 0.6rem;
  border-radius: 8px;
  border: 1px solid transparent;
  transition: background .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.win-hover-zone:hover + .win-outline,
.win-outline:hover{
  background: var(--paper-card);
  border-color: rgba(20,19,15,0.12);
  box-shadow: 0 14px 30px -10px rgba(20,19,15,0.28);
}
.win-outline a{
  display:flex; align-items:center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.68rem; color: var(--graphite-dark);
  white-space: nowrap;
}
.win-outline a::after{
  content:''; order:2; width: 14px; height: 2px; border-radius: 1px;
  background: rgba(20,19,15,0.3); transition: background .2s ease, width .2s ease;
}
.win-outline a span{ order:1; opacity:0; max-width:0; overflow:hidden; transition: opacity .16s ease; }
.win-hover-zone:hover + .win-outline a span,
.win-outline:hover a span{ opacity:1; max-width: 220px; }
.win-outline a:hover{ color: var(--ink); }
.win-outline a.is-active::after{ background: var(--cherry); width: 20px; }
.win-outline a.is-active{ color: var(--cherry); }

/* ---- cuerpo: una sola columna, se scrollea completo ---- */
.win-body{ height:100%; overflow-y:auto; padding: 1.6rem 3.2rem 3rem 1.6rem; }

/* ============ LAYOUT "FINDER" — panel izquierdo de carpetas +
   páginas independientes (sin scroll compartido, sin outline derecho).
   Se usa en proyectos con varios productos/entregables en lugar de
   un único caso de estudio lineal (ej. Territorios Sanos). ============ */
.win-content.has-finder{ display:flex; height:100%; }

.win-finder-sidebar{
  width: 216px; flex-shrink:0;
  background: var(--paper-dark);
  border-right: 1px dashed rgba(20,19,15,0.22);
  padding: 1.2rem 0.9rem;
  overflow-y: auto;
}
.finder-sidebar-head{ margin: 0 0 1.3rem; padding: 0 0.3rem; }
.finder-eyebrow{
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--graphite); margin: 0 0 0.4rem;
}
.finder-title{ font-family: var(--display); font-weight: 500; font-size: 0.98rem; line-height: 1.28; margin: 0; color: var(--ink); }

.finder-list{ display:flex; flex-direction:column; gap: 0.2rem; }
.finder-item{
  display:flex; align-items:center; gap: 0.6rem;
  width:100%; text-align:left;
  padding: 0.55rem 0.6rem;
  background:none; border: 1px solid transparent; border-radius: 4px;
  font-family: var(--mono); font-size: 0.76rem; color: var(--graphite-dark);
  cursor:pointer; transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.finder-item:hover{ background: rgba(20,19,15,0.05); }
.finder-item.is-active{
  background: var(--paper-card);
  border-color: rgba(20,19,15,0.14);
  color: var(--ink);
  box-shadow: 0 3px 10px -4px rgba(20,19,15,0.2);
}
/* ícono de carpeta, dibujado en CSS — nada de emoji ni set de íconos */
.finder-icon{ position:relative; width:15px; height:11px; flex-shrink:0; }
.finder-icon::before{
  content:''; position:absolute; inset:0;
  background: var(--graphite); opacity:0.55; border-radius: 1px;
}
.finder-icon::after{
  content:''; position:absolute; top:-3px; left:0;
  width:7px; height:3px; background: var(--graphite); opacity:0.55;
  border-radius: 1px 1px 0 0;
}
.finder-item.is-active .finder-icon::before,
.finder-item.is-active .finder-icon::after{ background: var(--cherry); opacity:1; }

.win-finder-pages{ flex:1; min-width:0; overflow-y:auto; }
.win-finder-page{ display:none; padding: 1.7rem 3rem 3rem 2rem; }
.win-finder-page.is-active{ display:block; }

/* ---- variante de página que ocupa toda la altura disponible de la
   ventana (en vez de crecer con el contenido) — se usa cuando la
   página aloja un embed que debe estirarse hasta el borde inferior,
   como el flipbook del libro de resultados. El encabezado conserva su
   alto natural; el bloque marcado con --fill se lleva el resto. ---- */
.win-finder-page--fill{ box-sizing: border-box; height: 100%; }
.win-finder-page--fill.is-active{ display:flex; flex-direction:column; }
.win-finder-page--fill .finder-page-head{ flex-shrink:0; }

.finder-page-head{ margin-bottom: 1.4rem; }
.finder-page-head h3{
  font-family: var(--display); font-weight: 500; font-size: 1.55rem; line-height: 1.15;
  margin: 0;
}
.win-finder-page .win-meta{ margin: 0 0 1.8rem; padding-bottom: 1.4rem; border-bottom: 1px dashed rgba(20,19,15,0.2); }

@media (max-width: 1024px){
  .win-content.has-finder{ flex-direction: column; }
  .win-finder-sidebar{
    width:auto; border-right:none;
    border-bottom: 1px dashed rgba(20,19,15,0.22);
    padding: 0.8rem 0.9rem;
  }
  .finder-sidebar-head{ display:none; }
  .win-finder-page{ padding: 1.3rem 1.3rem 2.4rem; }
}

.win-body .draft-flag{
  display:inline-block; font-family: var(--mono); font-size: 0.62rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--cherry);
  border: 1px dashed rgba(179,58,46,0.5); padding: 0.2rem 0.5rem; margin-bottom: 1rem;
}
.win-body h2{ font-family: var(--display); font-weight: 500; font-size: 2.1rem; line-height: 1.08; margin: 0 0 0.9rem; }

/* ---- header de caso de estudio: título+lead a la izquierda, metadatos a la derecha ---- */
.win-header{
  display:grid; grid-template-columns: 1.3fr 1fr; gap: 2.2rem;
  align-items:center;
  padding-bottom: 1.4rem; margin-bottom: 1.8rem;
  border-bottom: 1px dashed rgba(20,19,15,0.2);
}
.win-header-main{ min-width:0; }
.eyebrow-mini{
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--graphite); margin: 0 0 0.7rem;
}
.win-lead{
  font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: 1.05rem; line-height: 1.4; color: var(--graphite-dark);
  max-width: 40ch; margin: 0;
}
.win-meta{ display:flex; flex-direction:column; gap: 0.65rem; padding-top: 0.15rem; }
.meta-row{ display:grid; grid-template-columns: 82px 1fr; gap: 0.8rem; }
.meta-row .meta-label{ font-family: var(--body); font-weight: 600; font-size: 0.82rem; color: var(--ink); }
.meta-row .meta-value{ font-family: var(--body); font-size: 0.82rem; color: var(--graphite-dark); }

@media (max-width: 760px){
  .win-header{ grid-template-columns: 1fr; gap: 1rem; }
}

/* ---- hero e imágenes de sección ---- */
.win-hero{ position: relative; height: 0; padding-top: 56.25%; border-radius: 4px; margin-bottom: 2rem; overflow:hidden; }
.win-hero .photo-block{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; aspect-ratio: auto; border-radius: 4px; }
.win-hero .photo-block img{ object-fit: cover; object-position: var(--hero-pos, center); } /* el cover sí llena el marco — es una imagen decorativa, no un diagrama con info que no se pueda perder */

/* ---- hero clickeable (opt-in vía hero.link en los datos del proyecto,
   por ahora solo Listening Map): oscurece la foto en hover y revela un
   botón centrado que abre el sitio real en una pestaña nueva. El botón
   reutiliza el lenguaje "fantasma" de .btn-ghost (borde punteado, sin
   relleno) en vez del acento sólido cherry de .btn-cv. ---- */
.win-hero-link{
  position:absolute; inset:0; z-index: 4;
  display:flex; align-items:center; justify-content:center;
}
.win-hero-overlay{
  position:absolute; inset:0;
  background: var(--ink);
  opacity: 0;
  transition: opacity .25s ease;
}
.win-hero-link:hover .win-hero-overlay,
.win-hero-link:focus-visible .win-hero-overlay{ opacity: 0.45; }
.win-hero-btn{
  position: relative; z-index: 1;
  font-family: var(--mono); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--bone);
  border: 1px dashed var(--bone);
  border-radius: 3px;
  padding: 0.62rem 1.05rem;
  transform: translateY(6px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, border-color .2s ease, color .2s ease;
}
.win-hero-link:hover .win-hero-btn,
.win-hero-link:focus-visible .win-hero-btn{
  opacity: 1; transform: translateY(0);
  border-color: var(--cherry); color: var(--cherry);
}
/* sin hover confiable en táctil (mismo corte de 1024px que el resto del
   sitio): el botón queda siempre visible en vez de depender de un hover
   que nunca va a disparar */
@media (max-width: 1024px){
  .win-hero-overlay{ opacity: 0.4; }
  .win-hero-btn{ opacity: 1; transform: translateY(0); pointer-events: auto; border-color: var(--cherry); color: var(--cherry); }
}

.case-section{ margin-bottom: 2.4rem; scroll-margin-top: 1rem; }
.case-section h3{
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--graphite-dark); margin: 0 0 0.9rem; padding-bottom: 0.4rem;
  border-bottom: 1px solid rgba(20,19,15,0.1);
}

.block-text p{ margin: 0 0 0.7rem; font-size: 0.92rem; }
.block-list ul{ margin: 0 0 0.7rem; padding-left: 1.1rem; list-style: disc; }
.block-list li{ margin-bottom: 0.35rem; font-size: 0.92rem; }
.block-subheading{
  font-family: var(--body); font-weight: 600; font-size: 0.85rem;
  margin: 1rem 0 0.4rem; color: var(--ink);
}

.img-caption{
  font-family: var(--body);
  font-style: italic;
  font-size: 0.78rem;
  text-align: right;
  color: var(--graphite-dark);
  margin: 0.3rem 0 1rem;
}

/* ---- tags: chips en fila para resaltar datos clave sin párrafo ---- */
.block-tags{
  display:flex; flex-wrap:wrap; gap: 0.5rem;
  margin: 0 0 1.1rem;
}
.tag-chip{
  display:inline-block;
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.02em;
  color: var(--graphite-dark);
  background: var(--paper);
  border: 1px dashed rgba(20,19,15,0.3);
  border-radius: 2px;
  padding: 0.32rem 0.65rem;
  white-space: nowrap;
}

/* ---- comparison: columnas lado a lado, cada una con su propio
   ícono + título + bloques (ej. comparar apps, personas, opciones) ---- */
.block-comparison{
  display:grid; grid-template-columns: 1fr 1fr; gap: 1.8rem;
  margin: 0 0 1.4rem;
}
.comparison-col + .comparison-col{
  border-left: 1px dashed rgba(20,19,15,0.2);
  padding-left: 1.8rem;
}
.comparison-header{
  display:flex; align-items:center; gap: 0.6rem;
  margin-bottom: 0.9rem;
}
.comparison-icon{
  width: 32px; height: 32px; border-radius: 6px; overflow:hidden;
  flex-shrink: 0; background: var(--paper-dark);
}
.comparison-icon img{ width:100%; height:100%; object-fit:cover; }
.comparison-header h4{
  font-family: var(--display); font-weight: 500; font-size: 0.95rem; margin:0;
}
.comparison-col .block-subheading{ margin-top:0; }
@media (max-width: 760px){
  .block-comparison{ grid-template-columns: 1fr; gap: 1.6rem; }
  .comparison-col + .comparison-col{
    border-left:none; padding-left:0;
    border-top: 1px dashed rgba(20,19,15,0.2); padding-top: 1.6rem;
  }
}

/* ---- recuadro de imagen: placeholder punteado por defecto (.img-fallback);
   si el <img> carga bien, la cubre por completo — si falla, onerror lo
   elimina y vuelve a verse el placeholder con el caption ---- */
.photo-block{
  position: relative; overflow:hidden;
  aspect-ratio: 4/3; border-radius: 4px; margin-bottom: 0.4rem;

}
.photo-block .img-fallback{
  position:absolute; inset:0; z-index:1;
  display:flex; align-items:center; justify-content:center;
  font-family: var(--mono); font-size: 0.68rem; color: var(--graphite-dark); text-align:center; padding:0.6rem; opacity: 0;
}
.photo-block img{
  position:absolute; inset:0; z-index:2;
  width:100%; height:100%; object-fit:cover; display:block;
}

/* ---- variante "natural": sin proporción forzada — la caja toma la
   altura real de la imagen (según su ancho disponible), así nunca
   queda espacio vacío ni se distorsiona. Se usa en imágenes sueltas
   (bloques "image"), no en galerías ni en el hero, que sí necesitan
   una proporción fija para verse alineados. ---- */
.photo-block--natural{
  aspect-ratio: auto;
}
/* el min-height solo debe existir como piso para el placeholder punteado
   (cuando la imagen aún no existe o falló y onerror la quitó del DOM);
   si el <img> sigue presente, el alto real de la imagen manda. Antes el
   min-height se aplicaba siempre, así que imágenes "cortas" por
   naturaleza (como los recortes de status bar de Listening Map) quedaban
   con hasta 80px de aire vacío debajo, dando la sensación de que las
   imágenes consecutivas estaban muy separadas entre sí — el contenedor
   no las "abrazaba". */
.photo-block--natural:not(:has(img)){
  min-height: 120px;
}
.photo-block--sm{
  width: 50%;
  max-width: 50%;
  margin-left: auto;
  margin-right: auto;
}
@media (max-width: 600px){
  .photo-block--sm{ width: 100%; max-width: 100%; } /* en móvil no tiene sentido forzar 50% */
}
.photo-block--natural img{
  position: relative; z-index: 2;
  width: 100%; height: auto;
  object-fit: initial;
  display: block;
}
.block-gallery{
  display:grid; grid-template-columns: repeat(2, 1fr); gap: 0.7rem; margin-bottom: 0.7rem;
}
.block-gallery .photo-block{ margin-bottom:0; }

/* ---- embed: visores externos (ej. flipbook del libro) — mismo
   lenguaje visual que las fotos (borde sutil, esquinas redondeadas) ---- */
.block-embed{
  width: 100%; height: 420px;
  border-radius: 4px; overflow: hidden; margin-bottom: 1.2rem;
  border: 1px solid rgba(20,19,15,0.15);
  background: var(--paper-dark);
}
.block-embed iframe{ width:100%; height:100%; border:0; display:block; }

/* ---- variante que se estira hasta ocupar todo el espacio restante
   de una .win-finder-page--fill, en vez del alto fijo de 420px ---- */
.block-embed--fill{
  height: auto;
  flex: 1;
  min-height: 0; /* sin esto flexbox no deja que se encoja por debajo del contenido */
  margin-bottom: 0;
}

/* ---- flipbook self-hosted (StPageFlip, modo fixed) — tamaño
   predecible: la ventana crece o se maximiza si el libro necesita
   más espacio, en vez de forzar un tamaño que pelee con la librería ---- */
.block-flipbook{
  display:flex; flex-direction:column; align-items:center; gap: 0.9rem;
  margin: 0 0 1.4rem; max-width: 100%; overflow-x: auto;
}
.flipbook-book{ margin: 0 auto; position: relative; }
/* la librería fija "width: 100%" por dentro incluso en modo fixed, así
   que sin este !important el libro se estira al ancho del contenedor
   de la ventana en vez de respetar el tamaño real configurado —
   confirmado inspeccionando el DOM que genera en vivo */
.flipbook-book.stf__parent{ width: var(--flip-w) !important; max-width: var(--flip-w) !important; }
.flipbook-page{
  background: #fff; overflow:hidden;
}
.flipbook-page img{
  width: 100%; height: 100%;
  object-fit: cover; display:block;
}
.flipbook-controls{
  display:flex; align-items:center; gap: 1rem;
}
.flipbook-btn{
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid rgba(20,19,15,0.25);
  background: var(--paper-card); color: var(--ink);
  font-size: 1rem; line-height: 1; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.flipbook-btn:hover{ background: var(--paper-dark); border-color: var(--cherry); color: var(--cherry); }
.flipbook-page-indicator{
  font-family: var(--mono); font-size: 0.7rem; color: var(--graphite-dark);
  min-width: 56px; text-align:center;
}

.proj-window.is-minimized{ height: auto !important; }
.proj-window.is-minimized .win-content{ display:none; }

/* ---- handles de resize en las esquinas, invisibles hasta hover ----
   (van DENTRO del borde: .proj-window tiene overflow:hidden por las
   esquinas redondeadas, así que un offset negativo se recortaría) ---- */
.resize-handle{
  position:absolute; z-index: 30;
}
.rz-nw{ top: 0; left: 0; width: 10px; height: 10px; cursor: nwse-resize; }
.rz-ne{ top: 0; right: 0; width: 10px; height: 10px; cursor: nesw-resize; }
.rz-sw{ bottom: 0; left: 0; width: 16px; height: 16px; cursor: nesw-resize; }
.rz-se{ bottom: 0; right: 0; width: 16px; height: 16px; cursor: nwse-resize; }

.proj-window.is-maximized .resize-handle,
.proj-window.is-minimized .resize-handle{ display:none; }

@media (max-width: 1024px){
  .proj-window{
    position: fixed !important;
    top: 8px !important; left: 8px !important; right: 8px !important; bottom: 8px !important;
    width: auto !important; height: auto !important;
  }
  .win-bar{ cursor: default; }
  .win-body{ padding: 1.3rem 1.3rem 2.4rem; }
  .win-hover-zone{ display:none; } /* sin hover confiable en pantallas táctiles */
  .win-outline{ display:none; }    /* el menú lateral depende de hover, no aplica aquí */
  .resize-handle{ display:none; }  /* la ventana es fullscreen fija, no se redimensiona */
}
@media (max-width: 600px){
  .block-gallery{ grid-template-columns: 1fr; } /* en celular angosto, 2 columnas quedan muy chicas */
}

/* ============ CURSOR PERSONALIZADO — solo escritorio real ============
   Punto sólido que sigue el mouse; sobre elementos clickeables o
   arrastrables se le suma un anillo punteado concéntrico más grande.
   El color de ambos usa currentColor y se anima junto con el resto
   del header al revelarse el verde de contacto (ver script.js), para
   no quedar invisibles sobre el fondo oscuro.
   Oculto por completo salvo que JS confirme escritorio + mouse real
   (clase .has-custom-cursor en <html>, ver script.js) — así en
   táctil/tablet el cursor nativo del sistema sigue intacto. */
.cursor-dot, .cursor-ring{
  position: fixed; top:0; left:0;
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  display: none;
  color: var(--ink);
}
.cursor-dot{
  width: 8px; height: 8px;
  background: currentColor;
}
.cursor-ring{
  width: 36px; height: 36px;
  border: 1.5px dashed currentColor;
  opacity: 0;
  transition: opacity .18s ease, width .18s ease, height .18s ease;
}
.cursor-ring.is-active{ opacity: 1; }

html.has-custom-cursor{ cursor: none; }
html.has-custom-cursor *:not(.resize-handle){ cursor: none !important; }
html.has-custom-cursor .cursor-dot,
html.has-custom-cursor .cursor-ring{ display:block; }
html.has-custom-cursor.cursor-hidden .cursor-dot,
html.has-custom-cursor.cursor-hidden .cursor-ring{ opacity: 0 !important; }

@media (prefers-reduced-motion: reduce){
  *{ animation-duration: 0.01ms !important; transition: none !important; }
}

/* ============ ENLACE A LA BIBLIOTECA — esquina doblada + iris ============ */
.dog-ear{
  position: fixed;
  right: 0;
  bottom: var(--footer-h);
  width: 74px;
  height: 74px;
  z-index: 150;
  display: block;
  overflow: visible;
  cursor: pointer;
}

.dog-ear-fold{
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 52%, var(--paper-dark) 52%);
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  box-shadow: -3px -3px 8px rgba(20,19,15,0.18) inset;
  transform-origin: bottom right;
  transition: transform .3s ease, background .3s ease;
}

/* ============ ENLACE A LA BIBLIOTECA — esquina doblada + iris ============ */
.dog-ear{
  position: fixed;
  right: 0;
  bottom: var(--footer-h);
  width: 74px;
  height: 74px;
  z-index: 150;
  display: block;
  overflow: visible;
  cursor: pointer;
}

/* --- Variables CSS para el color del doblez --- */
.dog-ear-fold{
  /* Variables que controlan los colores */
  --fold-bg-start: transparent;
  --fold-bg-end: var(--pal-mostaza);
  --fold-hover-end: var(--pal-coral);
  
  position: absolute;
  inset: 0;
  /* Usamos las variables en el background */
  background: linear-gradient(135deg, var(--fold-bg-start) 52%, var(--fold-bg-end) 52%);
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  box-shadow: -3px -3px 8px rgba(20,19,15,0.18) inset;
  transform-origin: bottom right;
  transition: transform .3s ease, background .3s ease;
}

/* --- HOVER: usamos la variable de hover --- */
.dog-ear:hover .dog-ear-fold,
.dog-ear:focus-visible .dog-ear-fold{
  transform: scale(1.18) translate(3px, 3px) rotate(-2deg);
  /* El hover usa su propia variable, que GSAP también puede animar */
  background: linear-gradient(135deg, transparent 46%, var(--fold-hover-end) 46%);
}

/* --- LABEL: texto plano --- */
.dog-ear-label{
  position: absolute;
  bottom: 25px;
  right: 60px;
  margin-bottom: 14px;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  opacity: 0;
  transform: translateX(24px);
  transition: opacity .3s ease, transform .3s ease, color .3s ease;
  pointer-events: none;
}

.dog-ear:hover .dog-ear-label,
.dog-ear:focus-visible .dog-ear-label{
  opacity: 1;
  transform: translateX(0);
}

/* --- RESPONSIVE --- */
@media (max-width: 1024px){
  .dog-ear{ width: 58px; height: 58px; bottom: var(--footer-h); }
  .dog-ear-label{ font-size: 0.56rem; right: 30px; }
}

/* Capa que se cierra en círculo desde el punto del clic, tapando toda
   la pantalla en negro antes de navegar a biblioteca.html (ver
   assets/js/biblioteca-link.js — el radio se anima con GSAP escribiendo
   clip-path en cada frame, no es una transition CSS). Empieza en
   clip-path: circle(0px) = invisible, así que no hace falta display:none. */
.iris-overlay{
  position: fixed; inset: 0;
  z-index: 9999;
  background-color: #05050a;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='0.05'/></svg>");
  clip-path: circle(0px at 50% 50%);
  pointer-events: none;
}
.iris-overlay.is-active{ pointer-events: all; }


/* ============ SELECTOR DE IDIOMA - Abajo a la izquierda ============ */
.lang-switcher {
  position: fixed;
  bottom: calc(var(--footer-h) + 16px);
  left: 1.4rem;
  z-index: 300;
  display: flex;
  gap: 0.25rem;
  background: var(--paper-card);
  border: 1px solid rgba(20, 19, 15, 0.12);
  border-radius: 999px;
  padding: 0.2rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
  transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}

.lang-btn {
  background: transparent;
  border: none;
  border-radius: 999px;
  padding: 0.3rem 0.6rem;
  min-width: 32px;
  font-family: var(--mono);
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--graphite-dark);
  cursor: pointer;
  transition: all 0.2s ease;
  letter-spacing: 0.04em;
  line-height: 1.4;
}

.lang-btn:hover {
  color: var(--ink);
}

.lang-btn.is-active {
  background: var(--ink);
  color: var(--bone);
}

.lang-btn:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

/* Modo oscuro (cuando el fondo verde aparece) */
body.dark-mode .lang-switcher {
  background: rgba(33, 46, 2, 0.92);
  border-color: rgba(242, 238, 227, 0.15);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

body.dark-mode .lang-btn {
  color: rgba(242, 238, 227, 0.7);
}

body.dark-mode .lang-btn:hover {
  color: var(--bone);
}

body.dark-mode .lang-btn.is-active {
  background: var(--bone);
  color: var(--ink);
}

/* Móvil */
@media (max-width: 760px) {
  .lang-switcher {
    bottom: calc(var(--footer-h) + 12px);
    left: 0.9rem;
    padding: 0.15rem;
  }
  
  .lang-btn {
    padding: 0.2rem 0.5rem;
    min-width: 28px;
    font-size: 0.6rem;
  }
}

@media (max-width: 480px) {
  .lang-switcher {
    bottom: calc(var(--footer-h) + 60px);
  }
}
