/* =========================================================
   Traza — hoja de estilos del sitio
   Editorial minimalista: papel, carbón y un acento terracota.
   Todos los valores de color/tipografía/espaciado vienen de tokens.css
   (ver diseno/claude/tokens/ en el proyecto para la fuente de verdad).
   ========================================================= */

/* ---- Reset ligero ---- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

:root {
  /* Retícula común (medidas.md §2.1): margen lateral, radio del anillo (lo
     ajusta js/anillo.js) y alto que ocupa la cabecera fija, usado para que
     lo que queda debajo (filtro "sticky", cabecera del detalle) no se tape. */
  --hm: min(6.25vw, 100px);
  --ring-r: min(35vh, 24.06vw);
  --header-height: calc(var(--hm) + 48px);
  --paper: #FAFAF7; /* papel real de Traza (no cambia con el tema de la página) */
}
@media (max-width: 767px) {
  :root { --hm: 25px; --ring-r: 47.4vw; }
}

/* El atributo [hidden] debe ganar siempre sobre cualquier display: grid/flex
   de un componente, para que los estados (cargando / vacío / error / contenido)
   sean mutuamente excluyentes y nunca se superpongan. */
[hidden] { display: none !important; }
img { max-width: 100%; display: block; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, dl, dd, dt, figure { margin: 0; }
input { font: inherit; }

/* Sin desplazamiento animado del navegador: el suavizado lo hace js/scroll.js. */
html { scroll-behavior: auto; }

body {
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  min-width: 375px;
  overflow-x: hidden;
}

/* Tema de la página (cambia con la navegación interna): fondo y color base. */
body[data-theme="dark"] { background: var(--color-carbon-warm); color: var(--paper); }
a, button { -webkit-tap-highlight-color: transparent; }

/* ---- Foco visible (accesibilidad) ---- */
:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: var(--radius-sm);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-ink);
  color: var(--color-paper);
  padding: var(--space-3) var(--space-5);
  z-index: var(--z-toast);
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

/* ---- Tipografía base ---- */
.eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-gray-700);
  font-weight: var(--weight-medium);
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-heading);
  color: var(--color-ink);
}

.wrap {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding-left: var(--space-gutter);
  padding-right: var(--space-gutter);
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* =========================================================
   Cabecera persistente (medidas.md §2.1, §3.11, §4.4)
   Sin fondo ni borde, sobre el margen, igual en todas las páginas: logotipo
   a la izquierda y ES/EN · Proyectos|Inicio · Nosotros a la derecha. Proyectos
   (equivalente a All) e Inicio (Focus) comparten ranura. En el detalle, X
   arriba al centro; en nosotros, X en lugar del logotipo. Los cambios los
   anima js/nav.js; estos son los estados quietos (y los de sin JavaScript).
   ========================================================= */
.site-header {
  position: fixed;
  top: var(--hm);
  left: var(--hm);
  right: var(--hm);
  z-index: var(--z-header);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  color: var(--paper);
  pointer-events: none;
}
.site-header[data-tone="dark"] { color: var(--color-ink); }
.site-header > *, .nav-menu > * { pointer-events: auto; }

.brand {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: 18px;
  line-height: 25px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.nav-menu {
  display: flex;
  align-items: flex-start;
  gap: 60px;
  font-family: var(--font-display);
  font-size: 13px;
  line-height: 21px;
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
}
.nav-slot { display: inline-grid; }
.nav-slot__item { grid-area: 1 / 1; text-align: right; }
.nav-slot__item, .nav-about { position: relative; }
/* Subrayado con el acento al pasar el ratón (y en la página actual). */
.nav-slot__item::after, .nav-about::after {
  content: "";
  position: absolute;
  left: 0; right: 100%; bottom: -3px;
  height: 1px;
  background: var(--color-accent);
  transition: right 450ms var(--ease-c7);
}
.nav-slot__item:hover::after, .nav-about:hover::after, .nav-about[aria-current="page"]::after { right: 0; }

.lang-toggle {
  border: 0;
  border-radius: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  transition: color 450ms var(--ease-c7);
}
.lang-toggle:hover { color: var(--color-accent); }

/* X de cierre: caja de 45×45 con dos trazos de 16×1 a ±45°. */
.header-x {
  position: absolute;
  width: 45px;
  height: 45px;
  color: inherit;
  transition: color 450ms var(--ease-c7);
}
.header-x:hover { color: var(--color-accent); }
.header-x span {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 1px;
  background: currentColor;
}
.header-x span:first-child { transform: translate(-50%, -50%) rotate(45deg); }
.header-x span:last-child { transform: translate(-50%, -50%) rotate(-45deg); }
.header-x--detail { left: calc(50% - 22.5px); top: calc(80px - var(--hm)); }
.header-x--about { left: calc(75px - var(--hm)); top: calc(75px - var(--hm)); }

/* Estados quietos: oculto = 10 px más abajo (el logotipo, 10 px más arriba) y sin opacidad. */
.site-header[data-slot="all"] [data-slot-focus],
.site-header[data-slot="focus"] [data-slot-all],
.site-header[data-slot="none"] .nav-slot__item,
.site-header[data-mode="brand"] [data-x-about],
.site-header[data-x="off"] [data-x-detail] {
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
}
.site-header[data-mode="close"] [data-brand] {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px);
}

@media (max-width: 767px) {
  .brand { font-size: 13px; line-height: 18px; }
  .nav-menu { gap: 22px; font-size: 10px; line-height: 15px; }
  /* Zona de toque amplia sin mover el texto. */
  .nav-about, .lang-toggle { padding: 12px 0; margin: -12px 0; }
  .nav-about::after { bottom: 9px; }
  /* Proyectos e Inicio viven en la barra inferior. */
  .nav-slot { display: none; }
  .header-x span { width: 12px; }
  .header-x--detail { top: -15px; }
  .header-x--about { left: -15px; top: -18px; }
}

/* =========================================================
   Acceso a WhatsApp (mejora de Traza): sobrio, con el lenguaje del anillo,
   sin verde; abajo a la izquierda en escritorio (simétrico al contador),
   encima de la barra a la derecha en móvil. Cede su esquina al anillo
   pequeño de carga durante los cambios de página.
   ========================================================= */
.whatsapp-float {
  position: fixed;
  z-index: var(--z-whatsapp);
  left: var(--hm);
  bottom: calc(var(--hm) - 13px);
  width: 36px;
  height: 36px;
  border-radius: var(--radius-circle);
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(250, 250, 247, 0.3);
  color: var(--paper);
  transition: background-color 450ms var(--ease-c7), border-color 450ms var(--ease-c7), color 450ms var(--ease-c7);
}
body:not(.page-home)[data-theme="dark"] .whatsapp-float { background: rgba(21, 17, 14, 0.45); }
body[data-theme="light"] .whatsapp-float {
  background: rgba(250, 250, 247, 0.82);
  border-color: rgba(18, 18, 18, 0.22);
  color: var(--color-ink);
}
.whatsapp-float:hover,
body[data-theme] .whatsapp-float:hover { background: var(--color-accent); border-color: var(--color-accent); color: var(--paper); }
.whatsapp-float svg { width: 16px; height: 16px; }

/* Bloqueante #2 (auditoría ronda 1): el botón es "position: fixed", así que
   su franja horizontal es siempre la misma sin importar el scroll. Reservando
   ese ancho como padding-right en los bloques de texto que podrían llegar al
   borde derecho en móvil, el texto nunca puede quedar debajo del botón. */
@media (max-width: 767px) {
  .whatsapp-float {
    left: auto;
    right: 25px;
    bottom: calc(25px + env(safe-area-inset-bottom, 0px));
    width: 40px;
    height: 40px;
  }
  /* Con la barra inferior (portada y listado), justo encima de ella. */
  body[data-page="inicio"] .whatsapp-float,
  body[data-page="proyectos"] .whatsapp-float { bottom: calc(71px + env(safe-area-inset-bottom, 0px)); }
}
@media (max-width: 600px) {
  :root { --whatsapp-clear: 88px; }
}

/* =========================================================
   Botones
   ========================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-small);
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
  padding: 14px 28px;
  border-radius: var(--radius-sm);
  border: var(--border-hair-strong);
  transition: background var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard);
}
.btn--dark { background: var(--color-ink); color: var(--color-paper); border-color: var(--color-ink); }
.btn--dark:hover { background: var(--color-accent); border-color: var(--color-accent); }
.btn--outline { background: transparent; color: var(--color-ink); }
.btn--outline:hover { background: var(--color-ink); color: var(--color-paper); }
.btn--outline-light { background: transparent; color: var(--color-white); border-color: rgba(255,255,255,0.6); }
.btn--outline-light:hover { background: var(--color-white); color: var(--color-ink); }

/* =========================================================
   Portada (función corazón)
   Retícula igualada a la referencia (medidas.md §2.2): foto a sangre con
   viñeta, anillo fino centrado, título dentro del anillo, anterior y
   siguiente a media altura con sus líneas, contador abajo a la derecha y,
   en móvil, barra inferior. Colores y tipografía de Traza (tokens.css).
   Las animaciones las pinta js/home.js fotograma a fotograma.
   ========================================================= */
.page-home {
  --home-text: var(--color-paper);
  --home-text-80: rgba(250, 250, 247, 0.8); /* papel de Traza al 80 / 60 / 30 % */
  --home-text-60: rgba(250, 250, 247, 0.6);
  --home-text-30: rgba(250, 250, 247, 0.3);
  background: var(--color-carbon-warm);
  color: var(--home-text);
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
.main--home {
  --home-text: var(--color-paper);
  --home-text-80: rgba(250, 250, 247, 0.8);
  --home-text-60: rgba(250, 250, 247, 0.6);
  --home-text-30: rgba(250, 250, 247, 0.3);
}

.hero {
  position: relative;
  height: 100vh;
  height: 100dvh;
  background: var(--color-carbon-warm);
  color: var(--home-text);
  overflow: hidden;
}

/* Lienzo WebGL (js/hero3d.js): visible solo cuando ya pintó su primer cuadro. */
.hero-3d {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  visibility: hidden;
}
.hero.is-3d-active .hero-3d { visibility: visible; }
.hero.is-3d-active .hero-slides,
.hero.is-3d-active .hero-shade { display: none; }

/* Respaldo sin WebGL: las mismas fotos con fundido y la viñeta en CSS. */
.hero-slides { position: absolute; inset: 0; z-index: 0; }
.hero-slide { position: absolute; inset: 0; opacity: 0; }
.hero-slide__img { width: 100%; height: 100%; object-fit: cover; }
.hero-slide__img.is-fallback { object-fit: contain; padding: var(--space-9); background: var(--color-carbon-warm); }
/* Viñeta equivalente a la del shader: tinta cálida de Traza (#15110E) con la
   opacidad que deja el brillo de 75 % en el centro y 10 % en las esquinas. */
.hero-shade {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    rgba(21, 17, 14, 0.25) 0, rgba(21, 17, 14, 0.25) min(26vh, 28.08vw), rgba(21, 17, 14, 0.34) min(40vh, 43.2vw),
    rgba(21, 17, 14, 0.58) min(56vh, 60.48vw), rgba(21, 17, 14, 0.79) min(70vh, 75.6vw), rgba(21, 17, 14, 0.9) min(86vh, 92.88vw));
}

/* Títulos apilados en el centro del anillo; js/home.js los cruza. */
.hero-titles { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.hero-title {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: calc(var(--ring-r) * 1.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
  color: var(--home-text);
  /* Sombra muy suave: solo para que el título se lea sobre fotos claras. */
  text-shadow: 0 0 18px rgba(21, 17, 14, 0.45);
  opacity: 0;
  visibility: hidden;
  pointer-events: auto;
}
.hero-title__name {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: min(2.1vw, 30px);
  line-height: 1.36;
  letter-spacing: var(--tracking-display);
  color: inherit;
  text-wrap: balance;
}
.hero-title__meta {
  font-family: var(--font-display);
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--home-text-80);
  /* Cuerpo de 11 px: sombra más cercana que la del nombre para leerse sobre fotos claras. */
  text-shadow: 0 0 8px rgba(21, 17, 14, 0.6);
}

/* Anterior y siguiente a media altura, con sus líneas hacia el centro. */
.hero-nav {
  position: absolute;
  z-index: 3;
  top: 50%;
  width: 90px;
  height: 52px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-size: 12px;
  line-height: 12px;
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
  color: var(--home-text-60);
  transition: color 450ms var(--ease-c7);
}
.hero-nav:hover { color: var(--home-text); }
.hero-nav--prev { left: var(--hm); justify-content: flex-start; }
.hero-nav--next { right: var(--hm); justify-content: flex-end; }
.hero-line {
  position: absolute;
  z-index: 3;
  top: calc(50% - 3px);
  width: max(0px, calc(50% - var(--hm) - 96px - 1.21 * var(--ring-r)));
  height: 1px;
  background: var(--home-text-30);
  pointer-events: none;
}
.hero-line--prev { left: calc(var(--hm) + 96px); transform-origin: 0 50%; }
.hero-line--next { right: calc(var(--hm) + 96px); transform-origin: 100% 50%; }

/* Contador: obra actual, línea temporizadora (relleno con el acento) y total. */
.hero-counter {
  position: absolute;
  z-index: 7;
  right: var(--hm);
  bottom: calc(var(--hm) - 13px);
  height: 36px;
  display: flex;
  align-items: center;
  gap: 22px;
  font-family: var(--font-display);
  font-size: 12px;
  line-height: 12px;
  letter-spacing: var(--tracking-nav);
  font-variant-numeric: tabular-nums;
  color: var(--home-text);
}
.hero-counter__num { display: flex; }
.hero-counter__digit { position: relative; display: block; }
.hero-counter__d { display: block; }
.hero-counter__d--in { position: absolute; left: 0; top: 0; opacity: 0; }
.hero-counter__line { position: relative; width: 40px; height: 1px; background: var(--home-text-30); overflow: hidden; }
.hero-counter__fill { position: absolute; inset: 0; background: var(--color-accent-light); transform: scaleX(0); transform-origin: 0 50%; }


.hero-skeleton {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-carbon-warm);
}
.hero-skeleton__label {
  font-family: var(--font-display);
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
  color: var(--home-text-60);
  font-size: var(--text-small);
  opacity: 0;
  animation: hero-skeleton-in 300ms linear 900ms forwards;
}
@keyframes hero-skeleton-in { to { opacity: 1; } }

.hero-empty {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-4);
  padding: var(--space-7);
  background: var(--color-carbon-warm);
  color: var(--color-paper);
}
.hero-empty__title { font-size: var(--text-h1); color: var(--color-paper); }
.hero-empty__text { max-width: 32rem; color: var(--color-gray-300); }
.hero.is-empty .hero-nav,
.hero.is-empty .hero-line,
.hero.is-empty .hero-counter { display: none; }

@media (max-width: 767px) {
  .hero-title { max-width: min(300px, calc(var(--ring-r) * 1.69)); gap: 6px; }
  .hero-title__name { font-size: 17px; line-height: 1.4; }
  .hero-title__meta { font-size: 9px; }
  .hero-nav,
  .hero-line { display: none; }
  .hero-counter {
    right: auto;
    bottom: auto;
    left: 50%;
    top: calc(50% + 0.827 * var(--ring-r));
    height: 30px;
    transform: translate(-50%, -50%);
    gap: 16px;
    font-size: 10px;
    line-height: 10px;
  }
  .hero-counter__line { width: 30px; }
}

/* =========================================================
   Chips de filtro
   ========================================================= */
.chip {
  font-family: var(--font-display);
  font-size: var(--text-small);
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  border: var(--border-hair-strong);
  background: var(--color-paper);
  white-space: nowrap;
}
.chip:hover { border-color: var(--color-accent); }
.chip.is-active {
  background: var(--color-ink);
  color: var(--color-paper);
  border-color: var(--color-ink);
}

/* =========================================================
   Listado de proyectos
   ========================================================= */
.page-header {
  padding: calc(var(--space-9) + var(--space-5)) var(--space-gutter) var(--space-6);
}
.page-header__title { font-size: var(--text-display2); margin-top: var(--space-2); }

.filter-bar {
  position: sticky;
  top: var(--header-height);
  z-index: var(--z-filterbar);
  background: var(--color-paper);
  border-bottom: var(--border-hair);
  padding: var(--space-4) var(--space-gutter);
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  scrollbar-width: none;
}
.filter-bar::-webkit-scrollbar { display: none; }
/* Mientras el filtro está fijo arriba, una banda del color de la página tapa
   lo que pasa por encima (la cabecera no tiene fondo). */
.filter-bar.is-stuck { box-shadow: 0 calc(-1 * var(--header-height)) 0 var(--header-height) var(--color-paper); }

.grid-projects {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  padding: var(--space-7) var(--space-gutter) var(--space-10);
}
@media (max-width: 1024px) {
  .grid-projects { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .grid-projects { grid-template-columns: 1fr; gap: var(--space-5); padding: var(--space-6) var(--space-gutter) var(--space-9); }
}

.card-project__link { display: block; }
.card-project__frame {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--color-gray-100);
}
/* La foto mide el 130 % del marco, anclada arriba, y recorre el sobrante con
   el scroll (paralaje interior, js/scroll.js; medidas.md §2.3). */
.card-project__frame img {
  width: 100%; height: 130%;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-editorial);
  filter: grayscale(0.1);
}
.card-project__frame img.is-fallback { object-fit: contain; padding: var(--space-6); }
.card-project__link:hover .card-project__frame img { transform: scale(1.04); }
/* Cortina del color de la página: crece desde abajo al salir hacia un detalle (§3.16). */
.card-project__curtain {
  position: absolute;
  inset: 0;
  background: var(--color-paper);
  transform: scaleY(0);
  transform-origin: 50% 100%;
  pointer-events: none;
}
.card-project__meta { position: relative; z-index: 1; display: block; margin-top: var(--space-3); }
/* Con el paralaje, el texto sube sobre el borde de su foto: sombra corta para leerse. */
main[data-theme="dark"] .card-project__meta { text-shadow: 0 0 10px rgba(21, 17, 14, 0.55); }
.card-project__eyebrow { display: block; margin-bottom: 4px; }
.card-project__title {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--weight-semibold);
  display: block;
}
.card-project__link:hover .card-project__title { color: var(--color-accent); }

/* Esqueleto de tarjetas (estado "cargando") */
.grid-skeleton {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  padding: var(--space-7) var(--space-gutter) var(--space-10);
}
@media (max-width: 1024px) { .grid-skeleton { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .grid-skeleton { grid-template-columns: 1fr; } }
.skeleton-card__frame {
  aspect-ratio: 4/5;
  background: linear-gradient(100deg, var(--color-gray-100) 20%, var(--color-gray-150) 40%, var(--color-gray-100) 60%);
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
}
.skeleton-card__line {
  height: 12px;
  margin-top: var(--space-3);
  width: 70%;
  background: var(--color-gray-100);
}
.skeleton-card__line + .skeleton-card__line { width: 40%; margin-top: var(--space-2); }

/* Estados vacío / vacío por filtro / error (mutuamente excluyentes: ver
   hideAllStates() en js/listado.js, que oculta los 4 bloques de estado y
   la grilla antes de mostrar solo uno, para no repetir el bug de estados
   superpuestos del prototipo). */
.state-block {
  margin: var(--space-9) auto;
  max-width: 32rem;
  text-align: center;
  padding: 0 var(--space-gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}
.state-block__icon { color: var(--color-gray-300); width: 48px; height: 48px; }
.state-block__title { font-size: var(--text-h2); }
.state-block__text { color: var(--color-gray-700); }
.state-block--error .state-block__icon { color: var(--color-error); }

/* =========================================================
   Nosotros
   ========================================================= */
.nosotros-hero {
  padding: calc(var(--space-9) + var(--space-5)) var(--space-gutter) var(--space-7);
  max-width: 56rem;
}
.nosotros-hero__title { font-size: var(--text-display2); }
.nosotros-intro {
  padding: 0 var(--space-gutter) var(--space-7);
  max-width: 42rem;
  font-size: var(--text-body-lg);
  color: var(--color-gray-700);
}
.nosotros-filosofia {
  padding: var(--space-7) var(--space-gutter);
  border-top: var(--border-hair);
  border-bottom: var(--border-hair);
  background: var(--color-gray-100);
}
.nosotros-filosofia blockquote {
  max-width: 48rem;
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-heading);
  margin: 0 auto;
  font-style: normal;
}
@media (max-width: 600px) {
  /* Bloqueante #2: reportado exactamente aquí (auditoría ronda 1). */
  .nosotros-filosofia blockquote,
  .nosotros-intro,
  .timeline-item__text {
    padding-right: var(--whatsapp-clear);
  }
}

.nosotros-section { padding: var(--space-8) var(--space-gutter); }
.nosotros-section h2 { margin-bottom: var(--space-5); }

.timeline { display: flex; flex-direction: column; gap: 0; max-width: 42rem; }
.timeline-item {
  display: grid;
  grid-template-columns: 5rem 1fr;
  gap: var(--space-5);
  padding: var(--space-4) 0;
  border-top: var(--border-hair);
}
.timeline-item__year { font-family: var(--font-display); font-weight: var(--weight-bold); color: var(--color-accent); }

.team-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-5);
}
@media (max-width: 768px) { .team-grid { grid-template-columns: repeat(2, 1fr); } }
.team-card { display: flex; flex-direction: column; gap: var(--space-2); }
.team-card__avatar { display: block; aspect-ratio: 1; overflow: hidden; background: var(--color-gray-100); }
.team-card__avatar img { width: 100%; height: 100%; object-fit: cover; }
.team-card__name { font-family: var(--font-display); font-weight: var(--weight-semibold); }
.team-card__role { color: var(--color-gray-700); font-size: var(--text-small); }

/* =========================================================
   Detalle de proyecto
   ========================================================= */
.detail-skeleton { padding: calc(var(--space-9)) var(--space-gutter) var(--space-7); }
.detail-skeleton__hero {
  height: 60vh;
  min-height: 320px;
  background: linear-gradient(100deg, var(--color-gray-100) 20%, var(--color-gray-150) 40%, var(--color-gray-100) 60%);
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
}
.detail-skeleton__lines { padding: var(--space-6) 0; display: flex; flex-direction: column; gap: var(--space-3); }
.detail-skeleton__line { height: 14px; background: var(--color-gray-100); width: 100%; }
.detail-skeleton__line:nth-child(2) { width: 80%; }
.detail-skeleton__line:nth-child(3) { width: 60%; }

.detail-hero {
  position: relative;
  height: 72vh;
  min-height: 420px;
}
.detail-hero__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.detail-hero__img.is-fallback { object-fit: contain; background: var(--color-gray-100); padding: var(--space-9); }
.detail-hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(18,18,18,0.55) 0%, rgba(18,18,18,0.05) 35%, rgba(18,18,18,0.65) 100%);
  color: var(--color-white);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* Ajuste 2 de ELEGIDO.md / bug 6 (reporte Juanchi): "Volver al listado"
     quedaba tapado por el header fijo (.site-header, position: fixed,
     z-index var(--z-header)) porque el padding superior del prototipo
     (72px) era menor que el alto real del header (--header-height, 86px,
     ya usado por el sticky de .filter-bar en el listado). Se usa la misma
     variable aquí para garantizar el mismo espacio libre bajo el menú. */
  padding: calc(var(--header-height) + var(--space-4)) var(--space-gutter) var(--space-7);
}
/* Bug "Volver al listado" ilegible sobre imágenes claras (reporte Juanchi):
   el gradiente general de .detail-hero__overlay está pensado para el título
   al pie (muy claro en su primer 35%), así que sobre fotos de fondo claras
   el enlace de arriba casi no se lee. Se agrega el mismo degradado oscuro
   que ya usa el menú sobre los destacados claros de la portada
   (.site-header--light::before), aquí como capa adicional detrás del texto
   y por delante del gradiente base, solo en la franja donde vive el enlace. */
.detail-hero__overlay::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 160px;
  background: linear-gradient(180deg, rgba(18,18,18,0.65) 0%, rgba(18,18,18,0.32) 55%, rgba(18,18,18,0) 100%);
  pointer-events: none;
}
.detail-hero__back { position: relative; }
.detail-hero__back a { font-family: var(--font-display); font-size: var(--text-small); letter-spacing: var(--tracking-nav); text-transform: uppercase; }
.detail-hero__eyebrow { color: var(--color-gray-150); }
.detail-hero__title { font-size: var(--text-display2); margin-top: var(--space-2); max-width: 44rem; color: var(--color-white); }

.detail-body {
  padding: var(--space-8) var(--space-gutter);
  display: grid;
  grid-template-columns: minmax(200px, 320px) 1fr;
  gap: var(--space-8);
  border-bottom: var(--border-hair);
}
.detail-facts { display: flex; flex-direction: column; gap: var(--space-5); }
.detail-facts > div { border-top: var(--border-hair); padding-top: var(--space-3); }
.detail-facts dt { font-family: var(--font-display); font-size: var(--text-tiny); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-gray-700); }
.detail-facts dd { font-size: var(--text-h3); font-family: var(--font-display); margin-top: 4px; }
.detail-description { font-size: var(--text-body-lg); max-width: 42rem; color: var(--color-gray-700); }

@media (max-width: 768px) {
  .detail-body { grid-template-columns: 1fr; gap: var(--space-5); }
}
@media (max-width: 600px) {
  /* Bloqueante #2: mismo criterio que en "Nosotros" (ver arriba). */
  .detail-description {
    padding-right: var(--whatsapp-clear);
  }
}

.detail-gallery { padding: 0 var(--space-gutter) var(--space-8); }
.detail-gallery h2 { margin-bottom: var(--space-4); }
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}
.gallery-grid__item {
  display: block;
  width: 100%;
  aspect-ratio: 4/3;
  overflow: hidden;
  background: var(--color-gray-100);
  /* Corrección (revisión Juanchi): .gallery-grid__item es un <button>; el
     reset global de "button" (arriba) quita fondo/borde pero no el padding
     por defecto del navegador. Ese padding dejaba la imagen (width/height:
     100% del content-box, ya reducido por el padding) encogida dentro del
     botón, asomando el fondo gris como un marco alrededor de cada foto. */
  padding: 0;
  margin: 0;
  border: none;
}
.gallery-grid__item img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--duration-base) var(--ease-standard); }
.gallery-grid__item img.is-fallback { object-fit: contain; padding: var(--space-5); }
.gallery-grid__item:hover img { transform: scale(1.03); }
@media (max-width: 900px) {
  .gallery-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .gallery-grid { grid-template-columns: repeat(1, 1fr); gap: var(--space-3); }
}
@media (max-width: 600px) {
  /* Corrección (revisión Juanchi): recorta su parte del salto vacío antes
     del footer en móvil (ver también .detail-pager y .site-footer). */
  .detail-gallery { padding-bottom: var(--space-6); }
}

.detail-pager {
  display: flex;
  justify-content: space-between;
  /* Corrección (revisión Juanchi): el padding inferior usaba --space-9
     (96px) sumado luego al padding superior del footer (--space-7, 48px),
     dejando un salto vacío de 144px antes del pie de página. Se reduce a
     --space-7 aquí y se recorta más todavía en móvil (ver media query). */
  padding: var(--space-7) var(--space-gutter);
  gap: var(--space-5);
}
.detail-pager__link { display: flex; flex-direction: column; gap: var(--space-2); max-width: 20rem; }
.detail-pager__link--next { text-align: right; align-items: flex-end; }
.detail-pager__link span:last-child { font-family: var(--font-display); font-size: var(--text-h3); }
.detail-pager__link:hover span:last-child { color: var(--color-accent); }
@media (max-width: 600px) {
  .detail-pager {
    flex-direction: column;
    padding-top: var(--space-5);
    padding-bottom: var(--space-5);
  }
  .detail-pager__link--next { text-align: left; align-items: flex-start; }
  /* Bloqueante #2: antes de este breakpoint el enlace "siguiente" queda
     alineado a la derecha (text-align:right), justo en la franja del botón
     de WhatsApp; aquí ya pasa a alinearse a la izquierda, pero igual se
     reserva el margen por si el texto es largo y se acerca al borde. */
  .detail-pager__link {
    padding-right: var(--whatsapp-clear);
  }
}

/* Bug 6 (reporte Juanchi): mismo motivo que .detail-hero__overlay arriba,
   aplicado también al estado de error para que "Ir al listado de proyectos"
   nunca quede bajo el header cuando el id del proyecto no existe. */
.detail-error { padding-top: calc(var(--header-height) + var(--space-7)); }

/* =========================================================
   Lightbox
   ========================================================= */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  background: var(--color-overlay-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}
.lightbox__figure { max-width: min(90vw, 1200px); max-height: 80vh; display: flex; flex-direction: column; gap: var(--space-4); align-items: center; }
.lightbox__img { max-height: 70vh; width: auto; object-fit: contain; }
.lightbox__img.is-fallback { background: var(--color-carbon); padding: var(--space-8); }
.lightbox__caption { color: var(--color-gray-150); text-align: center; font-size: var(--text-small); }
.lightbox__close {
  position: absolute;
  top: var(--space-5); right: var(--space-5);
  width: 44px; height: 44px;
  border-radius: var(--radius-circle);
  border: 1px solid rgba(255,255,255,0.4);
  color: var(--color-white);
  display: flex; align-items: center; justify-content: center;
}
.lightbox__close:hover { background: var(--color-white); color: var(--color-ink); }
.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px; height: 48px;
  border-radius: var(--radius-circle);
  border: 1px solid rgba(255,255,255,0.4);
  color: var(--color-white);
  display: flex; align-items: center; justify-content: center;
}
.lightbox__nav:hover { background: var(--color-white); color: var(--color-ink); }
.lightbox__nav--prev { left: var(--space-5); }
.lightbox__nav--next { right: var(--space-5); }
.lightbox__counter {
  position: absolute;
  bottom: var(--space-5); left: 50%; transform: translateX(-50%);
  color: var(--color-gray-300);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-nav);
  font-size: var(--text-small);
}
@media (max-width: 600px) {
  .lightbox__nav--prev { left: var(--space-2); }
  .lightbox__nav--next { right: var(--space-2); }
  .lightbox__close { top: var(--space-3); right: var(--space-3); }
}

/* =========================================================
   Footer
   ========================================================= */
.site-footer {
  border-top: var(--border-hair);
  padding: var(--space-7) var(--space-gutter);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  color: var(--color-gray-700);
  font-size: var(--text-small);
}
.site-footer a:hover { color: var(--color-accent); }
@media (max-width: 600px) {
  /* Corrección (revisión Juanchi): recorta su parte del salto vacío que se
     acumulaba antes del footer en el detalle de proyecto, sobre todo en
     móvil (ver también .detail-gallery y .detail-pager). */
  .site-footer { padding-top: var(--space-5); padding-bottom: var(--space-5); }
}

/* =========================================================
   Aparición al hacer scroll (transversal, ficha sección 3): elementos que
   aparecen con leve movimiento/fundido al entrar en pantalla (js/main.js).
   Los cambios de página los hace js/nav.js (ver "Capa persistente").
   ========================================================= */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--duration-slow) var(--ease-editorial), transform var(--duration-slow) var(--ease-editorial);
}
[data-reveal].is-revealed { opacity: 1; transform: translateY(0); }


/* =========================================================
   Capa persistente (js/nav.js, js/anillo.js, js/lamina.js, js/scroll.js)
   Orden de abajo arriba: contenido de la portada (5) · lámina WebGL (10) ·
   anillo fino (12) · contenido de las demás páginas (15) · título en
   tránsito (30) · velo del final del detalle (40) · cabecera y barra (50) ·
   WhatsApp (60) · panel de entrada directa (90) · anillo pequeño (95).
   ========================================================= */
main { position: relative; z-index: 15; }
main.main--home { z-index: 5; }
/* Escritorio: el contenido va en un contenedor fijo que js/scroll.js desplaza
   (scroll virtual); un separador da al documento su altura. */
main.is-smooth {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  will-change: transform;
}
.scroll-spacer { width: 1px; pointer-events: none; }

/* Anillo fino persistente: claro en la portada, gris al fondo en las páginas
   oscuras, oculto en el detalle. js/anillo.js le da el radio y el trazo. */
.stage-ring {
  position: fixed;
  z-index: 12;
  left: 50%;
  top: 50%;
  width: calc(var(--ring-r) * 2 + 2px);
  height: calc(var(--ring-r) * 2 + 2px);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.stage-ring svg { display: block; width: 100%; height: 100%; overflow: visible; }
.stage-ring circle { fill: none; stroke-width: 1; }
.stage-ring__base { stroke: var(--paper); }
/* Arco y línea temporizadora con el acento claro y trazo de 2 px: medido, iguala el contraste del arco blanco de la referencia sobre fotos oscuras (etapa 12, encargo de Ani). */
.stage-ring__arc { stroke: var(--color-accent-light); stroke-width: 2; opacity: 0; }
.stage-ring[data-tono="gris"] .stage-ring__base { stroke-opacity: 0.15; }
.stage-ring[data-tono="oculto"] { opacity: 0; }

/* Barra inferior móvil (sin menú desplegable): en la portada, anterior,
   Proyectos y siguiente; en el listado, Inicio al centro (equivalente a Focus). */
.hero-bar { display: none; }
@media (max-width: 767px) {
  .hero-bar {
    display: flex;
    position: fixed;
    z-index: var(--z-header);
    left: 0;
    right: 0;
    bottom: 0;
    height: calc(57px + env(safe-area-inset-bottom, 0px));
    padding: 0 8px calc(7px + env(safe-area-inset-bottom, 0px));
    align-items: center;
    justify-content: space-between;
    background: rgba(21, 17, 14, 0.6); /* tinta cálida de Traza, translúcida */
    color: var(--paper);
  }
  .hero-bar__arrow {
    width: 44px;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: inherit;
  }
  .hero-bar__arrow svg { width: 12px; height: 10px; fill: none; stroke: currentColor; stroke-width: 1; }
  .hero-bar__slot { display: inline-grid; justify-items: center; }
  .hero-bar__all {
    grid-area: 1 / 1;
    font-family: var(--font-display);
    font-size: 10px;
    line-height: 15px;
    letter-spacing: var(--tracking-nav);
    text-transform: uppercase;
    padding: 17px 24px;
  }
  .hero-bar[data-mode="off"] { opacity: 0; visibility: hidden; }
  .hero-bar[data-mode="list"] .hero-bar__arrow { opacity: 0; visibility: hidden; }
  .hero-bar[data-mode="home"] [data-bar-focus],
  .hero-bar[data-mode="list"] [data-bar-all] { opacity: 0; visibility: hidden; transform: translateY(10px); }
  /* El listado deja sitio a la barra. */
  .main--list { padding-bottom: 57px; }
}

/* Lámina de cambio de página (WebGL propio, js/lamina.js). */
.lamina {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 10;
  pointer-events: none;
  display: none;
}
.lamina.is-on { display: block; }

/* Anillo pequeño de carga: dos aros de 2 px, uno al 30 % y otro con dos
   lados llenos y dos al 20 %, girando una vuelta cada 800 ms (§2.6, §3.1). */
.loader-ring {
  position: fixed;
  z-index: 95;
  left: var(--hm);
  bottom: var(--hm);
  width: 30px;
  height: 30px;
  color: var(--paper);
  mix-blend-mode: exclusion;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.loader-ring.is-on { visibility: visible; }
.loader-ring::before,
.loader-ring span {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid rgba(250, 250, 247, 0.3);
}
.loader-ring span {
  border-color: currentColor currentColor rgba(250, 250, 247, 0.2) rgba(250, 250, 247, 0.2);
  animation: traza-giro 800ms linear infinite;
}
@keyframes traza-giro { to { transform: rotate(1turn); } }
@media (max-width: 767px) {
  .loader-ring { left: 17px; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); width: 25px; height: 25px; }
}

/* Título en tránsito entre el anillo y la cabecera del detalle (§3.16–§3.18). */
.transit-title { position: fixed; inset: 0; z-index: 30; pointer-events: none; }
.transit-title__layer {
  position: absolute;
  left: 0;
  top: 0;
  width: max-content;
  transform-origin: 0 0;
  will-change: transform, opacity;
}
/* Con el aspecto del título de la portada, centrado en el anillo. */
.transit-title__ring {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: min(2.1vw, 30px);
  line-height: 1.36;
  letter-spacing: var(--tracking-display);
  text-align: center;
  text-wrap: balance;
  max-width: calc(var(--ring-r) * 1.5);
  text-shadow: 0 0 18px rgba(21, 17, 14, 0.45);
}
@media (max-width: 767px) {
  .transit-title__ring { font-size: 17px; line-height: 1.4; max-width: min(300px, calc(var(--ring-r) * 1.69)); }
}

/* Final del detalle (§3.21): 100 vh vacíos y un velo de tinta cálida ligado al scroll. */
.detail-end { position: relative; z-index: 1; height: 100vh; background: var(--color-paper); }
.end-veil {
  position: fixed;
  left: 0;
  right: 0;
  top: -5%;
  height: 110%;
  z-index: 40;
  background: var(--color-ink-warm);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.end-veil.is-on { visibility: visible; }
.end-veil__label {
  position: absolute;
  left: 50%;
  top: 50%;
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(250, 250, 247, 0.3);
  transform: translate(-50%, -50%);
}

/* Entrada directa (§3.22): panel de tinta cálida que sale hacia arriba con el
   borde recto. Si JavaScript no llega a retirarlo, se quita solo a los 6 s. */
html.traza-entrada::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--color-ink-warm);
  transform: translateY(var(--panel-y, 0%));
  animation: traza-panel-seguro 300ms linear 6s forwards;
}
@keyframes traza-panel-seguro { to { opacity: 0; visibility: hidden; } }

/* Durante un cambio de página: todo bloqueado y cursor de espera (§1.2, §4.6). */
html.is-navigating, html.is-navigating * { cursor: wait !important; }
html.is-navigating main,
html.is-navigating .site-header,
html.is-navigating .hero-bar { pointer-events: none; }

/* =========================================================
   Páginas oscuras (listado y nosotros, ficha §8): carbón cálido de Traza
   con el papel como texto y el acento en el filtro activo. Solo cambian los
   colores; la retícula y los componentes son los de siempre.
   ========================================================= */
main[data-theme="dark"] {
  --color-paper: var(--color-carbon-warm);
  --color-ink: var(--paper);
  --color-gray-700: rgba(250, 250, 247, 0.62);
  --color-gray-300: rgba(250, 250, 247, 0.3);
  --color-gray-150: #463C34;
  --color-gray-100: #3A312A;
  --border-hair: 1px solid rgba(250, 250, 247, 0.14);
  --border-hair-strong: 1px solid rgba(250, 250, 247, 0.3);
  color: var(--paper);
}
main[data-theme="dark"] .chip { color: var(--paper); background: transparent; }
main[data-theme="dark"] .chip.is-active { background: var(--color-accent); border-color: var(--color-accent); color: var(--paper); }
main[data-theme="dark"] .nosotros-filosofia { background: var(--color-ink-warm); }
main[data-theme="dark"] .btn--dark { background: var(--color-accent); border-color: var(--color-accent); color: var(--paper); }

/* Detalle: lo que sigue a la cabecera pasa por encima de ella (paralaje al 20 %). */
.detail-body,
.detail-gallery,
.detail-pager,
main[data-theme="light"] .site-footer { position: relative; z-index: 1; background: var(--color-paper); }
/* Fotos de la galería a 1,1× en su marco: recorren el sobrante con el scroll. */
.gallery-grid__item img { scale: 1.1; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .gallery-grid__item img { scale: 1; }
  .card-project__frame img { height: 100%; }
  * , *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
