/* ============================================================
   NIVIZ — niviz.com.ar · v03
   Sistema derivado del Brand Manual v0.16 + rescates de V01
   (Selected Work, notch como recorte, ficha técnica, beneficio
   como título de servicio, overlay de grilla con tecla H).
   Violeta #7C3AED = placeholder de desarrollo, NO producción.
   ============================================================ */

:root {
  /* Paleta */
  --cloud: #F0EEE9;
  --teal: #0E776D;
  --charcoal: #2F312B;
  --violet: #7C3AED;

  /* Texto atenuado (única transparencia permitida: charcoal/cloud, nunca teal) */
  --ink-70: rgba(47, 49, 43, 0.7);
  --ink-60: rgba(47, 49, 43, 0.6);
  --ink-40: rgba(47, 49, 43, 0.4);
  --line: rgba(47, 49, 43, 0.14);
  --cloud-72: rgba(240, 238, 233, 0.72);
  --cloud-55: rgba(240, 238, 233, 0.55);
  --line-dark: rgba(240, 238, 233, 0.16);

  /* Spacing (base 8) */
  --sp-hair: 4px; --sp-xs: 8px; --sp-s: 16px; --sp-m: 24px;
  --sp-l: 32px; --sp-xl: 48px; --sp-xxl: 64px; --sp-xxxl: 96px;

  /* Grilla web */
  --container-max: none; /* ⚠️ enmienda a la grilla del manual (era 1200px): desktop usa todo el ancho */
  --gutter: 16px;
  --page-margin: clamp(16px, 6.7vw, 128px); /* ⚠️ desvío documentado de la grilla del manual */

  --font-main: 'Inter', system-ui, -apple-system, sans-serif;
  --font-serif: 'Fraunces', Georgia, serif;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  /* scroll-behavior NATIVO (auto): la inercia la maneja initSmoothScroll con
     window.scrollTo por frame — con behavior:smooth cada frame reiniciaria una
     animacion nativa y el motor avanzaria a paso de tortuga. (Ademas "sacar
     smooth scroll" fue decision del rebuild y esta regla habia quedado colada.) */
  overflow-anchor: none; /* el scroll anchoring pelea contra el colapso del header */
  overflow-x: clip;      /* red de seguridad: nada desborda el viewport en horizontal */
}
body {
  font-family: var(--font-main);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.6;
  color: var(--charcoal);
  background: var(--cloud);
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}
body.menu-open { overflow: hidden; }
img, video, svg { max-width: 100%; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }

/* Skip link (a11y) */
.skip {
  position: absolute; left: var(--sp-m); top: -48px; z-index: 500;
  background: var(--teal); color: var(--cloud);
  font-size: 11px; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase;
  padding: 10px 16px; text-decoration: none; transition: top 0.15s ease;
}
.skip:focus { top: var(--sp-s); }

/* ---------- Contenedor y grilla ---------- */
.container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--page-margin); min-width: 0; }
.grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter); }
@media (max-width: 1023px) { .grid { grid-template-columns: repeat(6, 1fr); } }
@media (max-width: 640px)  { .grid { grid-template-columns: repeat(4, 1fr); } }

.col-full { grid-column: 1 / -1; }
.col-6 { grid-column: span 6; }
.col-5 { grid-column: span 5; }
.col-5-end { grid-column: span 5 / -1; }
.col-6-end { grid-column: span 6 / -1; }
@media (max-width: 1023px) {
  .col-6, .col-5, .col-5-end, .col-6-end { grid-column: 1 / -1; }
}

/* ---------- Tipografía ---------- */
h1, h2, h3 { font-weight: 200; letter-spacing: -0.02em; line-height: 1.1; }
h1 { font-size: clamp(34px, 5vw, 60px); max-width: 16ch; }
h2 { font-size: clamp(26px, 3.4vw, 40px); max-width: 20ch; }
h3 { font-size: clamp(17px, 1.6vw, 21px); font-weight: 400; letter-spacing: -0.01em; }
strong { font-weight: 500; }

.eyebrow {
  display: block;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: var(--sp-m);
}
.lead {
  font-size: clamp(15px, 1.5vw, 18px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-70);
  max-width: 54ch;
}
.dark .lead { color: var(--cloud-72); }
.sig {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(14px, 1.3vw, 17px);
  color: var(--ink-60);
}
.dark .sig { color: var(--cloud-55); }
.serif { font-family: var(--font-serif); font-style: italic; font-weight: 300; }

/* Statement (ref. Phantom ETHOS) */
.statement {
  font-size: clamp(26px, 3.2vw, 50px);
  font-weight: 500;
  line-height: 1.22;
  letter-spacing: -0.02em;
  max-width: 42ch;
  color: var(--charcoal);
}
.dark .statement { color: var(--cloud); }
.statement-tag {
  display: inline-block;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--teal);
  margin-right: var(--sp-l);
  position: relative;
  top: -0.9em;
}
.tline { width: 48px; height: 2px; background: var(--teal); margin-block: var(--sp-m); }
.tnum { font-feature-settings: "tnum"; }

/* Quote editorial (Fraunces, uso <10%) */
.quote { margin-top: var(--sp-xxl); max-width: 26ch; }
.quote blockquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(22px, 2.6vw, 34px);
  line-height: 1.3;
}
.dark .quote blockquote { color: var(--cloud); }

/* ---------- Secciones ---------- */
.section { padding-block: clamp(64px, 9vw, 120px); }
.section-tight { padding-block: var(--sp-xxl); }
.dark { background: var(--charcoal); color: var(--cloud); }

/* ---------- Logo (wordmark SVG real) ---------- */
.logo-link { display: block; color: inherit; }
.logo { fill: currentColor; aspect-ratio: 882 / 250; display: block; height: 20px; width: auto; }
.site-footer .logo { height: 16px; }

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: transparent;
  /* Tinta camaleón (Juan, 2026-08-30 — EN PRUEBA, revert: _archivo/styles-pre-camaleon):
     sin velo de value en el vidrio; la tinta se adapta al fondo que cruza vía el hook
     .on-dark del JS (ya existía): charcoal sobre claro, blanco sobre oscuro.
     La EXCEPCIÓN de paleta (blanco puro #FFF + glow) sigue vigente SOLO sobre oscuro.
     El fade vive acá y solo acá: los hijos heredan el valor ya interpolado
     (transition también en el hijo = fade encadenado de ~0.7s, no hacerlo). */
  color: var(--charcoal);
  transition: color 0.35s ease;
}
.site-header.on-dark { color: #FFFFFF; }
/* Menú mobile abierto: el panel es charcoal y el header (logo + X) pinta encima */
body.menu-open .site-header { color: #FFFFFF; }
/* Entrada del nav al cargar: la fila (logo + Contacto) baja desde arriba y los
   links de sección — los que arrancan abajo sobre la cota y luego se incorporan
   a la fila — suben a su lugar, escalonados. SOLO opacity/transform: los botones
   son clickeables en cualquier momento de la animación (el hit area viaja con el
   transform y nunca se apaga pointer-events). Sin fill forwards: al terminar,
   las transiciones de hover recuperan el control. */
/* La placa de vidrio también entra: baja desde fuera de pantalla ANTES que su
   contenido (0.55s), como material que llega primero y recibe al nav. */
@keyframes glassIn { from { transform: translateY(-110%) translateZ(0); } to { transform: translateZ(0); } }
.site-header::before, .site-header::after {
  animation: glassIn 0.55s cubic-bezier(0.22, 0.61, 0.27, 1) 0s backwards;
}
/* Movimiento reducido — se aplica solo si <html> lleva la clase `mov-reducido`,
   que main.js agrega SOLO si HONRAR_REDUCE = true. Hoy está en false por
   decisión de Juan (2026-09-02): la página fuerza sus animaciones siempre.
   El interruptor vive en main.js, no acá. */
html.mov-reducido .site-header::before, html.mov-reducido .site-header::after { animation: none; }
@keyframes navRowIn  { from { transform: translateY(-16px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes navLinkIn { from { transform: translateY(14px);  opacity: 0; } to { transform: none; opacity: 1; } }
.site-header .logo-link { animation: navRowIn 0.6s cubic-bezier(0.22, 0.61, 0.27, 1) 0.1s backwards; }
.site-header .main-nav  { animation: navRowIn 0.6s cubic-bezier(0.22, 0.61, 0.27, 1) 0.22s backwards; }
.nav-links a:nth-child(1) { animation: navLinkIn 0.6s cubic-bezier(0.22, 0.61, 0.27, 1) 0.4s backwards; }
.nav-links a:nth-child(2) { animation: navLinkIn 0.6s cubic-bezier(0.22, 0.61, 0.27, 1) 0.52s backwards; }
.nav-links a:nth-child(3) { animation: navLinkIn 0.6s cubic-bezier(0.22, 0.61, 0.27, 1) 0.64s backwards; }
html.mov-reducido .site-header .logo-link, html.mov-reducido .site-header .main-nav, html.mov-reducido .nav-links a { animation: none; }

/* Glow sutil en todo el contenido del nav (drop-shadow sigue la forma de
   glifos y SVGs por igual: texto, subrayados, flecha, isotipo y burger).
   SOLO sobre fondo oscuro: acompaña al blanco puro; la tinta charcoal no glowea. */
.site-header.on-dark .logo-link,
.site-header.on-dark .nav-links a,
.site-header.on-dark .main-nav .cta-link,
.site-header.on-dark .nav-toggle,
body.menu-open .site-header .logo-link,
body.menu-open .site-header .nav-toggle {
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.46)) drop-shadow(0 0 12px rgba(255, 255, 255, 0.20));
}
/* ---- Liquid Glass (ref. Apple 2025) en dos capas de geometría FIJA ----
   ::before = MATERIAL (todos los browsers): blur + velo de value.
   ::after = REFRACCIÓN (solo Chromium soporta backdrop-filter:url(#svg)):
   la lente #lgLens curva el muestreo del fondo contra el canto inferior. En
   Safari/Firefox la capa no pinta nada y queda el fallback de blur+velo. */
.site-header::before {
  content: "";
  position: absolute;
  top: -24px; left: 0; right: 0; /* nace 24px fuera de pantalla: el artefacto de
     clamp del blur en el borde superior queda offscreen (parecía curvatura arriba) */
  height: 96px; /* canto inferior DURO sigue en 72px de viewport */
  z-index: -2;
  pointer-events: none;
  /* Fondo del nav: vidrio PURO — solo blur + lente, sin velo ni cambio de HSV.
     La legibilidad la resuelve la tinta camaleón, no una bajada de value. */
  background: transparent;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  /* canto: SOLO hairline oscuro de asiento; lo definen el corte del blur y la lente */
  box-shadow: 0 1px 0 rgba(47, 49, 43, 0.08);
  transform: translateZ(0);
}
/* Lente de refracción del borde (mejora progresiva Chromium) */
.site-header::after {
  content: "";
  position: absolute;
  top: -24px; left: 0; right: 0;
  height: 96px;
  z-index: -1;
  pointer-events: none;
  /* encadena su propio blur: las capas backdrop hermanas muestrean el MISMO
     backdrop crudo (no componen), así que la lente debe repetir el material */
  backdrop-filter: blur(2px) url(#lgLens);
  -webkit-mask-image: linear-gradient(to top, #000 0, #000 4px, transparent 7px);
  mask-image: linear-gradient(to top, #000 0, #000 4px, transparent 7px);
  transform: translateZ(0);
}
/* Home: header superpuesto al hero (fixed) para que el vidrio blure contenido real */
.site-header.overlay { position: fixed; left: 0; right: 0; }
.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px; /* la fila de logo/nav NUNCA se mueve */
}
/* Extensión colapsable (solo Home): se achica 1:1 con el scroll */
.header-ext {
  position: relative;
  pointer-events: none; /* decorativa: pintaba por encima de los nav-links grandes
     y les robaba TODOS los clicks en el estado inicial de la home (bug preexistente) */
  height: clamp(120px, 22vh, 240px);
  margin-inline: var(--page-margin);
  border-bottom: 1px solid rgba(240, 238, 233, 0.5);
}
/* Cota con tope (manual §8b): marcas perpendiculares en ambos extremos */
.header-ext::before, .header-ext::after {
  content: "";
  position: absolute;
  bottom: -4.5px;
  width: 1px;
  height: 8px;
  background: rgba(240, 238, 233, 0.5);
}
.header-ext::before { left: 0; }
.header-ext::after { right: 0; }
.site-header .logo { color: currentColor; }

/* Links de sección: capa centrada */
.nav-links {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2em;
  font-size: 12px;
  white-space: nowrap;
}
/* Links de sección: SIEMPRE tinta plena (currentColor = la misma del logo y
   Contacto vía camaleón: cloud pleno sobre oscuro, charcoal pleno sobre claro).
   Sin dimming y sin hover por color (nada de HSV): el hover es el scramble
   letra-por-letra de main.js. Página actual: subrayado hairline, neutro. */
.nav-links a {
  font-size: inherit;
  font-weight: 650; /* Juan 2026-08-30: un paso arriba de 600; Inter variable 200-800
     lo renderiza exacto. MISMO peso en ambas tintas (ninguna regla .on-dark lo toca) */
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: currentColor;
  transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.27, 1);
}
.nav-links a[aria-current="page"] { border-bottom: 1px solid currentColor; }
/* Hover: el link crece 30% (transform = sin reflow, el nav no se mueve)
   y los hermanos se apartan dándole espacio. Sin cambio de HSV. */
.nav-links a:hover { transform: scale(1.3); }
.nav-links a:hover ~ a { transform: translateX(14px); }      /* los de después → derecha */
.nav-links a:has(~ a:hover) { transform: translateX(-14px); } /* los de antes → izquierda */
html.mov-reducido .nav-links a,
html.mov-reducido .nav-links a:hover,
html.mov-reducido .nav-links a:hover ~ a,
html.mov-reducido .nav-links a:has(~ a:hover) { transition: none; transform: none; }
@media (max-width: 860px) { .nav-links { display: none; } }
.main-nav { display: flex; align-items: center; gap: var(--sp-l); }

/* ---------- Menú mobile ---------- */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  width: 44px; height: 44px;
  padding: 10px;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: currentColor;
}
.nav-toggle span {
  display: block; height: 1.5px; width: 100%;
  background: currentColor;
  transition: transform 0.25s ease, opacity 0.2s ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
@media (max-width: 860px) { .nav-toggle { display: flex; } }

body.menu-open .header-ext,
body.menu-open .nav-links { visibility: hidden; }
body.menu-open .wa-float { opacity: 0; pointer-events: none; }

.mobile-menu {
  position: fixed; inset: 0; z-index: 90;
  background: var(--charcoal); color: var(--cloud);
  display: flex; flex-direction: column; justify-content: center;
  padding: var(--sp-xxxl) var(--page-margin) var(--sp-xxl);
}
.mobile-menu[hidden] { display: none; }
.mobile-menu nav { display: flex; flex-direction: column; gap: var(--sp-m); }
.mobile-menu nav a {
  font-size: clamp(28px, 8vw, 40px);
  font-weight: 200;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--cloud);
  display: flex; align-items: baseline; gap: var(--sp-s);
}
.mobile-menu nav a .n { font-size: 11px; letter-spacing: 0.2em; color: var(--teal); font-weight: 600; }
.mobile-menu nav a[aria-current="page"] { color: var(--teal); }
.mobile-menu .mm-foot {
  margin-top: var(--sp-xxl);
  display: flex; flex-direction: column; gap: var(--sp-xs);
  font-size: 12px; color: var(--cloud-55);
}
.mobile-menu .mm-foot a { color: var(--cloud-72); text-decoration: none; }
.mobile-menu .sig { color: var(--cloud-55); }

/* ---------- Botones ----------
   Decisión 2026-08-30: cta-link es el ÚNICO estilo de botón de toda la web
   (el pill .btn se eliminó). Label + regla inferior + flecha ↗ que se desliza. */
.cta-link {
  display: inline-flex;
  align-items: flex-end;
  gap: var(--sp-s);
  padding-bottom: var(--sp-xs);
  border-bottom: 1px solid currentColor;
  color: var(--teal);
  font-size: clamp(16px, 1.5vw, 20px);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: gap 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.cta-link:hover { gap: var(--sp-l); }
.cta-link .arrow { width: 20px; height: 20px; flex: none; margin-bottom: 2px; }
.dark .cta-link { color: var(--cloud); }
/* Soporte para <button> (ej. Enviar del formulario): mismo diseño exacto */
button.cta-link {
  background: transparent;
  border: 0;
  border-bottom: 1px solid currentColor;
  padding: 0 0 var(--sp-xs) 0;
  font-family: inherit;
  cursor: pointer;
}

/* Contacto en el nav: cta-link a escala de la fila */
.main-nav .cta-link { font-size: 12px; font-weight: 600; letter-spacing: 0.18em; gap: 10px; padding-bottom: 6px; color: inherit; }
.main-nav .cta-link:hover { gap: 18px; }
.main-nav .cta-link .arrow { width: 14px; height: 14px; margin-bottom: 1px; }
@media (max-width: 480px) { .main-nav .cta-link { display: none; } } /* en mobile chico: Contacto vive en el menú */

/* ---------- Hero ---------- */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 78vh;
  padding-block: var(--sp-xxxl) var(--sp-xxl);
}
.hero .container { min-width: 0; width: 100%; } /* fix overflow: el container no hereda el ancho del headline nowrap */
.hero .lead { margin-top: var(--sp-l); }
.hero .sig { margin-top: var(--sp-xl); display: inline-block; }
.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--sp-s); margin-top: var(--sp-xl); }

/* Hero v3 — headline display bold (excepción documentada: Inter 800 solo hero web) */
.hero-v3 { min-height: 0; padding-block: calc(104px + clamp(120px, 22vh, 240px)) clamp(48px, 6vw, 80px); }
.hero-v3 .hero-ctas { justify-content: flex-end; }
.hero-v3 h1 {
  font-weight: 800;
  font-size: clamp(40px, 8.2vw, 118px);
  line-height: 0.8; /* solo caps, sin descendentes */
  letter-spacing: -0.03em;
  text-transform: uppercase;
  max-width: 1136px;
  width: 100%;
}
.hero-v3 h1 .hl { display: block; white-space: nowrap; }
.hero-v3 h1 .comma {
  display: inline-block;
  font-size: 0.55em;
  line-height: 1;
  transform: translateY(-0.18em);
}

/* Headline: el split .ch + clip mantiene las letras ocultas hasta que arranca el scramble.
   (La entrada letra-por-letra-desde-abajo se retiró el 2026-09-11; `.in` ya no se usa.) */
.hero-v3 h1.split .hl { clip-path: inset(-0.3em -1.2em 0 -0.1em); }
.hero-v3 h1.split .ch {
  display: inline-block;
  transform: translateY(115%);
  transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--d, 0s);
}
.hero-v3 h1.split.in .ch { transform: none; }
.hero-v3 h1.split .comma { opacity: 0; transition: opacity 0.5s ease; transition-delay: var(--d, 0s); }
.hero-v3 h1.split.in .comma { opacity: 1; }

/* Hero · entrada SCRAMBLE (elegida 2026-09-11). hero-scr anula el translate del
   split y deja el escenario al scramble: hid = todavía no llegó el frente,
   cyc = ciclando. */
.hero-v3 h1.hero-scr .hl { clip-path: none; }
.hero-v3 h1.hero-scr .ch {
  transform: none !important;
  transition: none !important;
  text-align: center;      /* el glifo que cicla se centra en el slot congelado */
}
.hero-v3 h1.hero-scr .comma { opacity: 1 !important; transition: none !important; }
.hero-v3 h1.hero-scr .hid { visibility: hidden; }
.hero-v3 h1.hero-scr .cyc { opacity: 0.5; }

/* Carrusel de renders (marquee hacia la derecha + acople al scroll) */
.hero-marquee { overflow: hidden; padding-bottom: 32px; }
.marquee-track {
  display: flex;
  gap: var(--gutter);
  width: max-content;
  will-change: transform;
}
.marquee-item { flex: none; height: clamp(220px, 36vh, 400px); }
@media (max-width: 640px) { .marquee-item { height: clamp(180px, 28vh, 260px); } }
.marquee-item img { height: 100%; width: auto; display: block; }
.marquee-item .ph-block { height: 100%; width: 100%; }

/* ---------- Líneas de servicio (estilo one-pager) ---------- */
.lines { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-xl); margin-top: var(--sp-xl); }
.lines.lines-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 900px) { .lines, .lines.lines-2 { grid-template-columns: 1fr; gap: var(--sp-l); } }
.ln-num {
  font-size: 11px;
  letter-spacing: 0.2em;
  font-weight: 500;
  color: var(--teal);
  margin-bottom: var(--sp-s);
}
.ln-name {
  font-size: clamp(17px, 1.7vw, 21px);
  font-weight: 400;
  letter-spacing: -0.01em;
  padding-bottom: var(--sp-s);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-xs);
}
.ln-legend {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 15px;
  margin-bottom: var(--sp-s);
  color: var(--charcoal);
}
.blist { list-style: none; }
.blist li {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-70);
  padding: var(--sp-xs) 0;
  display: flex;
  gap: var(--sp-s);
}
.blist li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 1px;
  background: var(--teal);
  margin-top: 11px;
}
.dark .blist li { color: var(--cloud-72); }
.blist li.soon { color: var(--violet); }
.blist li.soon::before { background: var(--violet); }

/* ---------- Servicios: banda USP (ref. Daylight · mecánica de Clare /casas/) ----------
   Tercios con líneas visibles a 25% y 75% del viewport (grilla 1fr 2fr 1fr).
   La imagen es full-bleed en su celda lateral, con parallax (scale 1.6 + translateY
   acoplado al scroll, en .usp-media). El copy es FIXED centrado en el viewport y el
   clip-path:inset(0) de cada item lo recorta: el texto vive por debajo y aparece /
   desaparece mientras su item cruza la pantalla. JS: initUsp() en main.js. */
.usp-band { position: relative; background: var(--cloud); }
.usp-band::before, .usp-band::after {
  content: "";
  position: absolute; top: 0; bottom: 0;
  width: 1px;
  background: var(--line);
  z-index: 2;
  pointer-events: none;
}
.usp-band::before { left: 25%; }
.usp-band::after { left: 75%; }
.usp-list { list-style: none; margin: 0; padding: 0; position: relative; }
.usp {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  grid-template-rows: minmax(0, 100%);
  height: 61.2svh; /* 72svh - 15% (Juan 2026-08-31) */
  border-bottom: 1px solid var(--line);
  clip-path: inset(0); /* recorta el copy fixed a los límites del item */
}
.usp:first-child { border-top: 1px solid var(--line); }
.usp-lbl {
  margin: 0;
  position: absolute; top: var(--sp-m); z-index: 3;
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal);
}
.usp:nth-child(odd) .usp-lbl { left: calc(25% + var(--sp-l)); }
.usp:nth-child(even) .usp-lbl { right: calc(25% + var(--sp-l)); }
.usp-txt { grid-area: 1 / 2; position: relative; min-height: 0; height: 100%; }
.usp-fix {
  position: fixed;
  left: 50%; top: calc(50svh - var(--fixh, 220px) / 2);
  transform: translateX(-50%);
  width: min(560px, 40vw);
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-m);
  text-align: center;
  opacity: 0; visibility: hidden;
  pointer-events: none;
  will-change: opacity;
  z-index: 5;
}
.usp-fix h2 {
  margin: 0;
  font-weight: 800;
  font-size: clamp(28px, 3.2vw, 48px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  max-width: none;
}
/* Un solo párrafo por banda: qué hacemos + beneficio + ejemplos englobados.
   El catálogo de servicios detallado vive en la futura sección Servicios. */
.usp-desc {
  font-size: clamp(14px, 1.2vw, 16px);
  line-height: 1.75;
  letter-spacing: 0.01em;
  color: var(--ink-70);
  max-width: 46ch;
  margin: 0;
}
.usp-fig {
  margin: 0;
  position: relative;
  overflow: hidden;
  grid-row: 1;
  width: 100%; height: 100%; min-height: 0;
}
.usp:nth-child(odd) .usp-fig { grid-column: 3; }
.usp:nth-child(even) .usp-fig { grid-column: 1; }
.usp-media { position: absolute; inset: 0; will-change: transform; }
.usp-media img, .usp-media .ph-block { width: 100%; height: 100%; object-fit: cover; }
/* el ph-block viaja escalado 1.6 dentro del marco: contener el label al área visible */
.usp-media .ph-block { padding: 24%; }

/* Mobile / tablet: sin líneas ni copy fijo — columna simple */
@media (max-width: 1023px) {
  .usp-band::before, .usp-band::after { display: none; }
  .usp-list { padding: var(--sp-xl) 0 var(--sp-l); }
  .usp {
    display: flex; flex-direction: column; gap: var(--sp-l);
    height: auto;
    padding: var(--sp-xl) var(--page-margin);
    clip-path: none;
  }
  .usp:first-child { border-top: 0; }
  .usp-txt { height: auto; min-height: 0; width: 100%; }
  .usp-fix {
    position: static; transform: none; width: 100%;
    opacity: 1; visibility: visible; pointer-events: auto;
  }
  .usp-lbl { position: static; text-align: center; order: -1; }
  .usp-fig { width: min(360px, 78vw); height: auto; aspect-ratio: 3 / 4; align-self: center; }
}
html.mov-reducido .usp-media { will-change: auto; }

/* ---------- PRUEBA (2026-08-31): tema del home — tecla T ----------
   Cicla data-theme en <html>: (vacio) mix actual -> "dark" todo oscuro ->
   "light" todo claro. Solo overrides de tokens y fondos: el layout no se toca.
   Codigo de prueba: se borra este bloque + initThemeTest y no queda rastro. */

/* — TODO OSCURO — */
html[data-theme="dark"] {
  --ink-70: rgba(240, 238, 233, 0.72);
  --ink-60: rgba(240, 238, 233, 0.62);
  --ink-40: rgba(240, 238, 233, 0.42);
  --line: rgba(240, 238, 233, 0.16);
}
html[data-theme="dark"] body { background: var(--charcoal); color: var(--cloud); }
/* fondos que "recortan" (notch) y bandas con cloud explicito pasan al fondo oscuro */
html[data-theme="dark"] .usp-band,
html[data-theme="dark"] .sw-cap,
html[data-theme="dark"] .notch-media .nm-cap { background: var(--charcoal); }
/* el statement pina charcoal explicito: sobre fondo oscuro pasa a cloud */
html[data-theme="dark"] .statement { color: var(--cloud); }
/* nav: siempre blanco + glow (todo el fondo es oscuro; el camaleon queda sin efecto) */
html[data-theme="dark"] .site-header { color: #FFFFFF; }
html[data-theme="dark"] .site-header .logo-link,
html[data-theme="dark"] .site-header .nav-links a,
html[data-theme="dark"] .site-header .main-nav .cta-link,
html[data-theme="dark"] .site-header .nav-toggle {
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.46)) drop-shadow(0 0 12px rgba(255, 255, 255, 0.20));
}

/* — TODO CLARO — */
html[data-theme="light"] {
  --cloud-72: rgba(47, 49, 43, 0.72);
  --cloud-55: rgba(47, 49, 43, 0.55);
}
html[data-theme="light"] .dark,
html[data-theme="light"] .site-footer { background: var(--cloud); color: var(--charcoal); }
html[data-theme="light"] .dark .cta-link { color: var(--charcoal); }
/* el panel del menu mobile sigue charcoal: sus textos vuelven a claros */
html[data-theme="light"] .mobile-menu {
  --cloud-72: rgba(240, 238, 233, 0.72);
  --cloud-55: rgba(240, 238, 233, 0.55);
}
/* cota del hero: era clara sobre hero oscuro; sobre cloud pasa a tinta */
html[data-theme="light"] .header-ext { border-bottom-color: rgba(47, 49, 43, 0.3); }
html[data-theme="light"] .header-ext::before,
html[data-theme="light"] .header-ext::after { background: rgba(47, 49, 43, 0.3); }
/* nav: siempre tinta charcoal, sin glow (todo el fondo es claro) */
html[data-theme="light"] .site-header,
html[data-theme="light"] .site-header.on-dark { color: var(--charcoal); }
html[data-theme="light"] .site-header.on-dark .logo-link,
html[data-theme="light"] .site-header.on-dark .nav-links a,
html[data-theme="light"] .site-header.on-dark .main-nav .cta-link,
html[data-theme="light"] .site-header.on-dark .nav-toggle { filter: none; }
html[data-theme="light"] body.menu-open .site-header { color: #FFFFFF; }

/* chip de estado del toggle */
.theme-chip {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 200; pointer-events: none;
  font-size: 10px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--cloud); background: rgba(47, 49, 43, 0.88);
  padding: 8px 14px;
  opacity: 0; transition: opacity 0.25s ease;
}
.theme-chip.on { opacity: 1; }

/* ---------- PRUEBA (2026-09-01): sección Servicios — 4 variantes, tecla S ----------
   data-sv en .serv-band elige la variante visible. Cada variante tiene su CSS
   aislado. Al elegir una: promover su bloque y borrar el resto + este comentario. */
.serv-band { position: relative; background: var(--cloud); }
.serv-head { padding-top: var(--sp-xl); }
.serv-tag {
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal);
}
/* [hidden] es una regla del UA (baja especificidad): cualquier display propio de
   una variante la pisa y quedarian dos visibles a la vez. Esta gana siempre. */
.sv[hidden] { display: none !important; }

/* — V1 · índice encendido — */
.sv1 {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  padding: var(--sp-xl) 0 var(--sp-xxl);
}
.sv1-idx { grid-column: 2; }
.sv1-area { padding-block: var(--sp-l); }
.sv1-area + .sv1-area { border-top: 1px solid var(--line); }
.sv1-lbl {
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal);
  margin-bottom: var(--sp-m);
}
.sv1-row {
  margin: 0;
  font-size: clamp(24px, 2.9vw, 42px);
  font-weight: 200;
  letter-spacing: -0.02em;
  line-height: 1.32;
}
.sv1-row .lt { color: rgba(47, 49, 43, 0.22); transition: color 0.18s linear; }
.sv1-row .lt.on { color: var(--charcoal); }
.sv1-row.soon .lt.on { color: var(--violet); }
/* preview sticky del área activa, en el tercio derecho */
.sv1-side { grid-column: 3; position: relative; }
.sv1-img {
  position: sticky;
  top: calc(50svh - 130px);
  width: min(280px, 82%);
  aspect-ratio: 3 / 4;
  object-fit: cover;
  display: block;
  margin-inline: auto;
  opacity: 0;
  transition: opacity 0.45s ease;
}
.sv1-img.on { opacity: 1; }
/* las tres imgs comparten el mismo lugar: se apilan con margen negativo */
.sv1-img + .sv1-img { margin-top: calc(min(280px, 82%) * -4 / 3); }

/* — V2 · filas hairline con expansión — */
.sv2 { padding: var(--sp-xl) var(--page-margin) var(--sp-xxl); max-width: 920px; margin-inline: auto; }
.sv2-lbl {
  font-size: 10px; font-weight: 600; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal);
  margin: var(--sp-xl) 0 var(--sp-s);
}
.sv2-lbl:first-child { margin-top: 0; }
.sv2-row { border-bottom: 1px solid var(--line); }
.sv2-btn {
  width: 100%;
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-m);
  background: transparent; border: 0; cursor: pointer;
  padding: var(--sp-m) 0;
  font-family: inherit;
  font-size: clamp(17px, 1.7vw, 22px);
  font-weight: 300; letter-spacing: -0.01em;
  color: var(--charcoal);
  text-align: left;
}
.sv2-row.soon .sv2-t { color: var(--violet); }
/* indicador +: dos hairlines, rota a x al abrir (transform only) */
.sv2-x { position: relative; width: 14px; height: 14px; flex: none; align-self: center; }
.sv2-x::before, .sv2-x::after {
  content: ""; position: absolute; left: 0; top: 6.5px;
  width: 14px; height: 1px; background: currentColor;
  transition: transform 0.3s ease;
}
.sv2-x::after { transform: rotate(90deg); }
.sv2-row.open .sv2-x::after { transform: rotate(0deg); }
/* expansión sin medición: grid-rows 0fr -> 1fr */
.sv2-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s cubic-bezier(0.22, 0.61, 0.27, 1);
}
.sv2-row.open .sv2-body { grid-template-rows: 1fr; }
.sv2-inner { overflow: hidden; }
.sv2-inner p {
  margin: 0;
  padding: 0 0 var(--sp-m);
  max-width: 56ch;
  font-size: 14px; line-height: 1.7;
  color: var(--ink-60);
}

/* — V3 · capítulos sticky que se apilan — */
.sv3-slot { height: 118svh; }
.sv3-cap {
  position: sticky; top: 0;
  height: 100svh;
  background: var(--cloud);
  border-top: 1px solid var(--line);
  display: flex; align-items: center;
}
/* .dark se define ANTES en la hoja y misma especificidad: sin esto, el background
   cloud de .sv3-cap la pisa y queda texto cloud sobre fondo cloud (invisible). */
.sv3-cap.dark { background: var(--charcoal); color: var(--cloud); border-top-color: rgba(240, 238, 233, 0.16); }
.sv3-in { margin-inline: var(--page-margin); width: 100%; }
.sv3-lbl {
  font-size: 10px; font-weight: 600; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal);
  margin-bottom: var(--sp-l);
}
.sv3-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--sp-s);
}
.sv3-list li {
  font-size: clamp(26px, 3.4vw, 48px);
  font-weight: 200; letter-spacing: -0.02em; line-height: 1.2;
  opacity: 0; transform: translateY(18px);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 0.61, 0.27, 1);
}
.sv3-cap.in .sv3-list li { opacity: 1; transform: none; }
.sv3-list li:nth-child(1) { transition-delay: 0.05s; }
.sv3-list li:nth-child(2) { transition-delay: 0.15s; }
.sv3-list li:nth-child(3) { transition-delay: 0.25s; }
.sv3-list li:nth-child(4) { transition-delay: 0.35s; }
.sv3-list li.soon { color: var(--violet); }

/* — V4 · riel horizontal por scroll vertical — */
.sv4 { height: 340svh; position: relative; }
.sv4-pin {
  position: sticky; top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex; align-items: center;
}
.sv4-rail {
  display: flex;
  gap: var(--page-margin);
  padding-inline: var(--page-margin);
  will-change: transform;
}
.sv4-panel { flex: 0 0 58vw; }
.sv4-intro { flex-basis: 44vw; }
.sv4-big {
  margin: 0;
  font-size: clamp(30px, 3.6vw, 56px);
  font-weight: 200; letter-spacing: -0.02em; line-height: 1.15;
}
.sv4-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--sp-s);
}
.sv4-list li {
  font-size: clamp(22px, 2.4vw, 34px);
  font-weight: 200; letter-spacing: -0.02em; line-height: 1.25;
}
.sv4-list li.soon .lt.on { color: var(--violet); }
/* mismo encendido que el índice (V1), acá ligado al eje X del riel */
.sv4-big .lt, .sv4-list .lt { color: rgba(47, 49, 43, 0.22); transition: color 0.18s linear; }
.sv4-big .lt.on, .sv4-list .lt.on { color: var(--charcoal); }
.sv4-bar {
  position: absolute; left: var(--page-margin); right: var(--page-margin); bottom: 32px;
  height: 1px; background: var(--line);
}
.sv4-bar i {
  position: absolute; inset: 0;
  background: var(--teal);
  transform-origin: left center;
  transform: scaleX(0);
}

/* mobile: la única honesta en touch es la V2; las demás caen a columna simple */
@media (max-width: 1023px) {
  .sv1 { display: block; padding-inline: var(--page-margin); }
  .sv1-side { display: none; }
  .sv1-row { font-size: 24px; }
  .sv3-slot { height: auto; }
  .sv3-cap { position: static; height: auto; padding: var(--sp-xl) 0; }
  .sv4 { height: auto; }
  .sv4-pin { position: static; height: auto; overflow: visible; }
  .sv4-rail { flex-direction: column; transform: none !important; }
  .sv4-panel { flex-basis: auto; }
  .sv4-bar { display: none; }
}
html.mov-reducido .sv1-row .lt, html.mov-reducido .sv4-big .lt, html.mov-reducido .sv4-list .lt { color: var(--charcoal); transition: none; }
html.mov-reducido .sv3-list li { opacity: 1; transform: none; transition: none; }

/* el tag del statement pasó a bloque propio al recibir su propio reveal */
.rv-tag { display: block; margin-bottom: var(--sp-m); }

/* ---------- Proyectos seleccionados — tríptico (2026-09-11) ----------
   Debajo de Servicios. Tres 4:5 con brief. La media lleva el MISMO parallax que la
   banda "Qué hacemos": capa escalada dentro de un marco con overflow hidden, y el JS
   la desplaza en Y según la posición del marco en el viewport (initProyectos).
   Ventana: la imagen va a todo el ancho, más alta que el marco, y se desplaza en Y en
   el sobrante. Sin recorte horizontal. Altura del marco = la del sobrante más chico
   × 0,82, acotada a 44vh para que imagen y texto entren juntos en 1080p. */
.proy-band { position: relative; background: var(--cloud); padding-bottom: var(--sp-xxxl); }
.proy-head { padding-top: var(--sp-xxxl); }
.proy-tag {
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--teal); margin-bottom: var(--sp-m);
}
.proy-h { margin-bottom: var(--sp-xl); }
.proy-foot { margin-top: var(--sp-xl); }
.proy-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-l); align-items: start; }
.proy-media {
  position: relative; overflow: hidden;
  height: var(--proy-h, 40vh);          /* la fija initProyectos: una sola altura para las tres */
  margin-bottom: var(--sp-m);
  background: var(--charcoal);
}
/* ventana de parallax: la imagen va a TODO el ancho (nunca se recorta en horizontal) y
   más alta que el marco; el JS la desplaza en Y dentro del sobrante */
.proy-pl { position: absolute; left: 0; right: 0; top: 0; will-change: transform; }
.proy-pl img { width: 100%; height: auto; display: block; }
.proy-n { font-size: 10px; letter-spacing: 0.12em; color: var(--ink-40); font-weight: 600; margin-bottom: 4px; }
.proy-t { font-size: clamp(20px, 1.8vw, 26px); font-weight: 300; letter-spacing: -0.02em; margin-bottom: 4px; }
.proy-m { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-60); margin-bottom: var(--sp-s); }
.proy-brief { font-size: 14px; line-height: 1.55; color: var(--ink-60); margin-bottom: var(--sp-s); }
/* líneas entregadas: chips hairline, la entregada en tinta, la no entregada apagada */
.pv-ln {
  display: inline-block; font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 5px 10px; margin: 0 6px 6px 0;
  border: 1px solid var(--line); color: var(--ink-40);
}
.pv-ln.on { color: var(--teal); border-color: var(--teal); }
@media (max-width: 860px) {
  .proy-grid { grid-template-columns: 1fr; gap: var(--sp-xl); }
}
html.mov-reducido .proy-pl { will-change: auto; transform: none !important; }

/* ---------- Sistema de reveals de texto (2026-09-02) ----------
   Tres mecánicas con regla de uso, no una sola para todo:
   A · WIPE      → headlines cortos (1-3 líneas). Franja que barre y deja las letras.
   B · SCRAMBLE  → textos cortos de acento: eyebrows, labels, números. Y el hover del nav.
   C · ENCENDIDO → bloques largos ligados al scroll (statement, índices, listas).
   El cuerpo de texto NO lleva reveal protagonista: se revela con el fade discreto
   de .reveal, porque su trabajo es que lo leas, no que lo mires.
   Nada de esto toca el hero: su entrada tiene mecanismo propio. */

/* A · wipe — UNA barra para todo el bloque (Juan, 2026-09-17). Antes: una por línea,
   escalonadas; desincronizadas se veían raro. .rv-line envuelve el texto entero. */
.rv-wipe { display: block; }
.rv-wipe .rv-line {
  position: relative; display: block; overflow: hidden;
  padding-bottom: 0.14em; margin-bottom: -0.14em;   /* aire para las descendentes */
}
.rv-wipe .rv-t { display: block; clip-path: inset(0 100% 0 0); }
/* Barra = NIVIZ GLASS (Juan, 2026-09-24). Excepción explícita a "el vidrio vive solo en
   el nav" (decisión del 2026-09-01): la pide él. Mismo material que el nav — blur de
   fondo, sin velo de color, canto con luz arriba y asiento hairline abajo — SIN la lente
   de refracción: no se refracta tipografía display (lección 24).
   Secuencia: el vidrio avanza y el texto aparece DEBAJO de él (se lee borroso a través
   del material); después el vidrio se retira hacia la derecha y deja el texto nítido. */
.rv-wipe .rv-bar {
  position: absolute; left: 0; right: 0; top: 0.02em; bottom: 0.12em; z-index: 2;
  background: rgba(240, 238, 233, 0.18);
  -webkit-backdrop-filter: blur(7px) saturate(1.15);
  backdrop-filter: blur(7px) saturate(1.15);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    inset 0 -1px 0 rgba(47, 49, 43, 0.14),
    0 1px 0 rgba(47, 49, 43, 0.08);
  transform: scaleX(0); transform-origin: left center;
}
.dark .rv-wipe .rv-bar {
  background: rgba(240, 238, 233, 0.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 -1px 0 rgba(0, 0, 0, 0.3);
}
.rv-wipe.in .rv-t   { animation: rvWipeT 1.1s cubic-bezier(0.22, 0.61, 0.27, 1) var(--rvd, 0s) both; }
.rv-wipe.in .rv-bar { animation: rvWipeB 1.1s cubic-bezier(0.22, 0.61, 0.27, 1) var(--rvd, 0s) both; }
@keyframes rvWipeB {
  0%   { transform: scaleX(0); transform-origin: left center; }
  46%  { transform: scaleX(1); transform-origin: left center; }
  56%  { transform: scaleX(1); transform-origin: right center; }
  100% { transform: scaleX(0); transform-origin: right center; }
}
@keyframes rvWipeT { 0% { clip-path: inset(0 100% 0 0); } 46%, 100% { clip-path: inset(0 0 0 0); } }

/* B · scramble */
.rv-scr .lt { display: inline-block; }
.rv-scr .lt.hid { visibility: hidden; }   /* ancho reservado: el bloque no se mueve */
.rv-scr .lt.cyc { opacity: 0.55; }

/* C · encendido */
.rv-lit .lt { color: rgba(47, 49, 43, 0.22); transition: color 0.18s linear; }
.rv-lit .lt.on { color: var(--charcoal); }
.dark .rv-lit .lt { color: rgba(240, 238, 233, 0.25); }
.dark .rv-lit .lt.on { color: var(--cloud); }

html.mov-reducido .rv-wipe .rv-t { clip-path: none !important; animation: none !important; }
html.mov-reducido .rv-wipe .rv-bar { display: none; }
html.mov-reducido .rv-lit .lt { color: var(--charcoal); transition: none; }
html.mov-reducido .dark .rv-lit .lt { color: var(--cloud); }

/* ---------- Ciclo / proceso ---------- */
.phases { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-xl); margin-top: var(--sp-xl); }
.phases.phases-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1023px) { .phases, .phases.phases-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .phases, .phases.phases-3 { grid-template-columns: 1fr; } }
.phase-key {
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--teal);
  font-weight: 500;
  padding-bottom: var(--sp-s);
  border-bottom: 1px solid var(--teal);
  margin-bottom: var(--sp-s);
}
.phase-h { font-size: clamp(18px, 1.8vw, 24px); font-weight: 300; margin-bottom: var(--sp-xs); }
.phase-d { font-size: 13px; line-height: 1.6; color: var(--ink-60); }
.dark .phase-d { color: var(--cloud-72); }
.phase-list { list-style: none; margin-top: var(--sp-s); }
.phase-list li { font-size: 13px; line-height: 1.6; color: var(--cloud-72); padding: var(--sp-hair) 0; }

/* ---------- Selected Work (rescate V01: índice ↔ imagen, notch como recorte) ---------- */
.sw-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: var(--sp-xl);
  margin-top: var(--sp-xl);
  align-items: start;
}
@media (max-width: 900px) { .sw-grid { grid-template-columns: 1fr; gap: var(--sp-l); } }
.sw-stage { position: relative; aspect-ratio: 3 / 2; overflow: hidden; }
.sw-layer { position: absolute; inset: 0; opacity: 0; transition: opacity 0.45s ease; }
.sw-layer.show { opacity: 1; }
.sw-layer .ph-block { height: 100%; }
.sw-layer img { width: 100%; height: 100%; object-fit: cover; }
/* Notch: bloque de Cloud Dancer que recorta la imagen (gesto V01, sistema §8 full-bleed) */
.sw-cap {
  position: absolute; left: 0; bottom: 0; z-index: 2;
  background: var(--cloud);
  padding: var(--sp-s) var(--sp-m) 0 0;
  max-width: 78%;
  display: flex; align-items: baseline; gap: var(--sp-s); flex-wrap: wrap;
}
.sw-cap .fn { font-size: 10px; letter-spacing: 0.12em; color: var(--teal); font-weight: 600; }
.sw-cap .fname { font-size: clamp(17px, 1.8vw, 24px); font-weight: 300; letter-spacing: -0.02em; }
.sw-cap .fmeta { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-60); width: 100%; }
.sw-index { display: flex; flex-direction: column; min-height: 0; }
.sw-label {
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--ink-40); font-weight: 500; margin-bottom: var(--sp-xs);
}
.sw-row {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: baseline; gap: var(--sp-s);
  padding: 12px 0;
  border-top: 1px solid var(--line);
  text-decoration: none;
  cursor: pointer;
  transition: padding-left 0.25s cubic-bezier(0.22, 0.61, 0.27, 1);
}
.sw-row:last-of-type { border-bottom: 1px solid var(--line); }
.sw-row .rn { font-size: 10px; letter-spacing: 0.12em; color: var(--ink-40); font-weight: 600; }
.sw-row .rname { font-size: 17px; font-weight: 400; }
.sw-row .ryear { font-size: 10px; letter-spacing: 0.08em; color: var(--ink-40); }
.sw-row:hover, .sw-row:focus-visible, .sw-row.act { padding-left: 12px; }
.sw-row.act .rn, .sw-row.act .rname { color: var(--teal); }
.sw-more { margin-top: var(--sp-l); }

/* ---------- Notch-media: recorte de Cloud sobre imagen (sistema, uso general) ---------- */
.notch-media { position: relative; overflow: hidden; }
.notch-media img { width: 100%; height: 100%; object-fit: cover; }
.notch-media .ph-block { width: 100%; height: 100%; }
.notch-media .nm-cap {
  position: absolute; left: 0; bottom: 0; z-index: 2;
  background: var(--cloud);
  padding: var(--sp-xs) var(--sp-m) 0 0;
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-60);
  max-width: 78%;
}

/* ---------- Proyectos ---------- */
.case { padding-block: var(--sp-xxl); border-top: 1px solid var(--line); }
.case:first-of-type { border-top: 0; }
.case-data { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--sp-m); margin-block: var(--sp-l); }
.case-data dt {
  font-size: 10px; font-weight: 500; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--teal); margin-bottom: var(--sp-hair);
}
.case-data dd { font-size: 14px; }

/* ---------- Galería (legado: la usa presencia-online.html hasta que se rehaga) ---------- */
.gallery { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter); margin-top: var(--sp-xl); }
@media (max-width: 900px) { .gallery { grid-template-columns: 1fr; } }
.g-wide { grid-column: span 12; } .g-wide .ph-block { aspect-ratio: 21 / 9; }
.g-half { grid-column: span 6; }  .g-half .ph-block { aspect-ratio: 4 / 3; }
.g-third { grid-column: span 4; } .g-third .ph-block { aspect-ratio: 4 / 5; }
.g-video { grid-column: span 6; } .g-video .ph-block { aspect-ratio: 16 / 9; }
@media (max-width: 900px) { .g-wide, .g-half, .g-third, .g-video { grid-column: 1 / -1; } }
.g-caption { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-60); margin-top: var(--sp-xs); }

/* ---------- Portfolio: galería densa por filas de proporción (2026-09-12) ----------
   Regla: nunca se recorta en horizontal. Cada fila junta imágenes de la MISMA
   proporción a igual ancho (grid de columnas iguales), así las alturas coinciden
   solas y no hace falta object-fit. Pedido de Juan: muchas a la vez, galería y no
   muestra → 4 columnas, gap chico, sin captions. Sin hero, sin lightbox. */
.pf-grid { display: flex; flex-direction: column; gap: 12px; }
.pf-row { display: grid; gap: 12px; align-items: start; }
.pf-row.c2 { grid-template-columns: repeat(2, 1fr); }
.pf-row.c3 { grid-template-columns: repeat(3, 1fr); }
.pf-row.c4 { grid-template-columns: repeat(4, 1fr); }
.pf-fig { margin: 0; }
.pf-fig img, .pf-video { width: 100%; height: auto; display: block; background: var(--charcoal); }
.pf-grid-vid { margin-top: var(--sp-xl); }
@media (max-width: 860px) {
  .pf-row.c4, .pf-row.c3, .pf-row.c2 { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .pf-grid { gap: 8px; }
}
@media (max-width: 480px) {
  .pf-grid-vid .pf-row.c3 { grid-template-columns: 1fr; }
}

/* ---------- Formulario ---------- */
.form { display: flex; flex-direction: column; gap: var(--sp-m); max-width: 480px; }
.form label {
  font-size: 10px; font-weight: 500; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--teal);
  display: block; margin-bottom: var(--sp-xs);
}
.form input, .form textarea {
  width: 100%;
  font-family: inherit;
  font-size: 15px;
  font-weight: 300;
  color: var(--charcoal);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: var(--sp-xs) 0 var(--sp-s);
  border-radius: 0;
}
.form input:focus, .form textarea:focus { outline: none; border-bottom-color: var(--teal); }
.form textarea { resize: vertical; min-height: 96px; }
.form .cta-link { align-self: flex-start; margin-top: var(--sp-s); }

/* NAP / datos de contacto */
.nap { display: flex; flex-direction: column; gap: var(--sp-m); }
.nap .ck {
  font-size: 9px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--ink-40); display: block; margin-bottom: var(--sp-hair); font-weight: 500;
}
.dark .nap .ck { color: var(--cloud-55); }
.nap .cv { font-size: 16px; font-weight: 300; text-decoration: none; }

/* ---------- Panel de contacto (2026-09-11) ----------
   Mecánica de Form&Fun (panel derecho que sube, backdrop, la página quieta) sobre
   el sistema Niviz: Cloud, hairlines, radio 0, cta-link. Cierra por botón, ESC y
   backdrop. En ≤860px ocupa toda la pantalla. z 300: sobre header (100), menú
   mobile (90) y WhatsApp flotante (200). */
.cpanel { position: fixed; inset: 0; z-index: 300; }
.cpanel[hidden] { display: none; }
.cp-backdrop {
  position: absolute; inset: 0;
  background: rgba(47, 49, 43, 0.42);
  opacity: 0; transition: opacity 0.5s ease;
}
.cp-panel {
  position: absolute; top: 0; right: var(--sp-s); bottom: 0;
  width: clamp(420px, 34vw, 560px);
  padding-top: var(--sp-s);
  transform: translateY(100%);
  transition: transform 0.9s cubic-bezier(0.22, 0.61, 0.27, 1);
  outline: none;
}
.cpanel.open .cp-backdrop { opacity: 1; }
.cpanel.open .cp-panel { transform: none; }
.cpanel.closing .cp-panel { transition-duration: 0.6s; }
.cp-panel::before {                      /* la tarjeta: Cloud con hairline a la izquierda */
  content: ''; position: absolute; inset: var(--sp-s) 0 0 0;
  background: var(--cloud); border-left: 1px solid var(--line);
}
.cp-head, .cp-body { position: relative; }
.cp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-l) var(--sp-l) 0;
}
.cp-eyebrow { margin-bottom: 0; }
.cp-close {
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid var(--line); background: none; color: var(--charcoal);
  cursor: pointer; padding: 0; border-radius: 0;
  transition: border-color 0.25s ease, color 0.25s ease;
}
.cp-close svg { width: 18px; height: 18px; }
.cp-close:hover, .cp-close:focus-visible { border-color: var(--teal); color: var(--teal); }
.cp-body {
  height: calc(100% - 44px - var(--sp-l));
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--sp-l) var(--sp-l) var(--sp-xl);
}
.cp-title { font-size: clamp(24px, 2vw, 30px); max-width: 16ch; margin-bottom: var(--sp-xl); }
.cp-form { max-width: none; }
.cp-form input:invalid:not(:placeholder-shown), .cp-form textarea:invalid:not(:placeholder-shown) { border-bottom-color: var(--line); }
.cp-form .is-bad { border-bottom-color: #B4462B; }
.cp-done { padding-top: var(--sp-s); }
.cp-done-t { font-size: clamp(20px, 1.6vw, 24px); font-weight: 300; letter-spacing: -0.01em; max-width: 22ch; margin-bottom: var(--sp-s); }
.cp-done-s { font-size: 14px; line-height: 1.55; color: var(--ink-60); max-width: 40ch; }
.cp-alt { margin-top: var(--sp-xl); font-size: 13px; color: var(--ink-60); }
.cp-alt a { color: inherit; }
/* El bloqueo va en <html>, no en body: html tiene overflow-x:clip, y con eso el
   overflow del body ya no se propaga al viewport (gotcha clásico). */
html.cp-open { overflow-y: hidden; }
@media (max-width: 860px) {
  .cp-panel { right: 0; width: 100%; padding-top: 0; }
  .cp-panel::before { inset: 0; border-left: 0; }
  .cp-head { padding: var(--sp-m) var(--sp-m) 0; }
  .cp-body { padding: var(--sp-m) var(--sp-m) var(--sp-xl); height: calc(100% - 44px - var(--sp-m)); }
}
html.mov-reducido .cp-backdrop, html.mov-reducido .cp-panel { transition: none; }

/* ---------- Footer ---------- */
.site-footer { background: var(--charcoal); color: var(--cloud); padding-block: 0 var(--sp-l); }
/* Ficha técnica (rescate V01): fila de celdas tipo rótulo de plano */
.ficha {
  display: flex; flex-wrap: wrap;
  border-bottom: 1px solid var(--line-dark);
  padding-block: var(--sp-s);
  margin-bottom: var(--sp-xxl);
}
.ficha .cell {
  font-size: 9px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--cloud-55); font-weight: 500;
  padding: 4px 20px;
  border-left: 1px solid var(--line-dark);
}
.ficha .cell:first-child { border-left: 0; padding-left: 0; }
.ficha .cell b { color: var(--cloud); font-weight: 600; }
.site-footer .footer-grid {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  gap: var(--sp-xl); align-items: flex-start;
}
.site-footer a { color: var(--cloud); text-decoration: none; }
.site-footer a:hover { color: var(--teal); }
.footer-nav, .footer-contact { display: flex; flex-direction: column; gap: var(--sp-xs); font-size: 13px; }
.footer-nav a { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--cloud-72); }
.footer-tag { font-family: var(--font-serif); font-style: italic; font-size: 13px; color: var(--cloud-55); margin-top: var(--sp-s); }
.footer-legal {
  margin-top: var(--sp-xl); padding-top: var(--sp-m);
  border-top: 1px solid var(--line-dark);
  font-size: 11px; color: var(--cloud-55);
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-s);
}

/* ---------- WhatsApp flotante ---------- */
.wa-float {
  position: fixed;
  right: var(--sp-m);
  bottom: var(--sp-m);
  z-index: 200;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--teal);
  color: var(--cloud);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 24px rgba(47, 49, 43, 0.25);
  transition: opacity 0.25s ease, transform 0.15s ease;
}
.wa-float:hover { transform: scale(1.06); }
.wa-float svg { width: 26px; height: 26px; fill: currentColor; }
.wa-float.is-hidden { opacity: 0; pointer-events: none; }

/* ---------- Reveal on scroll ---------- */
.js .reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.7s ease, transform 0.7s ease; }
.js .reveal.in { opacity: 1; transform: none; }
html.mov-reducido.js .reveal { opacity: 1; transform: none; transition: none; }
html.mov-reducido .sw-layer { transition: none; }
html.mov-reducido .cta-link, html.mov-reducido .sw-row { transition: none; }

/* ---------- Overlay de grilla · tecla H (herramienta de trabajo, rescate V01) ---------- */
.gridov {
  position: fixed; inset: 0; z-index: 9999;
  pointer-events: none;
  display: none;
  padding-inline: var(--page-margin);
  gap: var(--gutter);
}
.gridov.on { display: grid; grid-template-columns: repeat(12, 1fr); }
@media (max-width: 1023px) { .gridov.on { grid-template-columns: repeat(6, 1fr); } }
@media (max-width: 640px)  { .gridov.on { grid-template-columns: repeat(4, 1fr); } }
.gridov i { background: rgba(124, 58, 237, 0.06); border-inline: 1px solid rgba(124, 58, 237, 0.35); }

/* ---------- Placeholders (violeta — solo desarrollo) ---------- */
.ph { color: var(--violet) !important; }
.ph-block {
  display: flex; align-items: center; justify-content: center; text-align: center;
  background: rgba(124, 58, 237, 0.06);
  border: 1px dashed rgba(124, 58, 237, 0.45);
  color: var(--violet);
  font-size: 11px; font-weight: 400;
  letter-spacing: 0.18em; text-transform: uppercase;
  padding: var(--sp-s);
}
.ph-img { aspect-ratio: 3 / 2; width: 100%; }
.ph-note { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--violet); }

/* ---------- Utilidades ---------- */
.max-prose { max-width: 62ch; }
.mt-s { margin-top: var(--sp-s); }
.mt-m { margin-top: var(--sp-m); }
.mt-l { margin-top: var(--sp-l); }
.mt-xl { margin-top: var(--sp-xl); }
.center { text-align: center; }

/* ============================================================
   §  PROYECTOS · índice sticky por capítulos (2026-09-15)
   Referencia: ref.digital/work/* — analizado 2026-09-14.
   Las barras de título viajan entre DOS pilas: arriba las ya
   abiertas, abajo las que faltan. El índice ocupa siempre el
   mismo alto; lo que cambia es el reparto.
   Es FLEX y no grid a propósito: el bloque contenedor de un
   grid item es su celda, y ahí el sticky no tendría recorrido.
   ============================================================ */
.caps {
  display: flex; flex-wrap: wrap; position: relative;
  --cap-bar: 34px;
  --cap-pad: 88px;          /* fila del header sticky (72) + aire */
  --cap-pad-b: var(--sp-m);
  --cap-col: calc((100% - 23 * var(--gutter)) / 24);
  --cap-w8: calc(var(--cap-col) * 8 + var(--gutter) * 7);
  --cap-w15: calc(var(--cap-col) * 15 + var(--gutter) * 14);
}
.cap { display: contents; }

/* Tapas: sin esto el contenido asoma por encima y por debajo del stack.
   Ocupan solo la columna del indice (w8) para no cortar los medios de la
   derecha, que tienen que seguir pasando por debajo del vidrio del header.
   .cap-break fuerza el salto de linea del flex (si no, tapa y primera barra
   entran juntas en la misma fila). */
.cap-mask { flex: 0 0 var(--cap-w8); position: sticky; z-index: 40; background: var(--cloud); }
.cap-mask.top { top: calc(var(--cap-pad) - 16px); height: 16px; }
.cap-mask.bot { bottom: 0; height: var(--cap-pad-b); }
.cap-break { flex: 0 0 100%; height: 0; }
.caps.no-stick .cap-mask, .caps.no-stick .cap-bar { position: static; }

.cap-bar {
  flex: 0 0 var(--cap-w8);
  position: sticky; z-index: 2;
  height: var(--cap-bar);
  display: flex; align-items: center; gap: var(--gutter);
  background: var(--cloud);
  border: 0; border-top: 1px solid var(--line);
  appearance: none; -webkit-appearance: none;
  font-family: inherit;
  font-size: 11px; font-weight: 400; letter-spacing: 0.1em;
  text-transform: uppercase; line-height: 1;
  color: var(--ink-40);
  cursor: pointer; text-align: left;
  transition: color 0.3s ease;
}
.cap-bar .n { flex: 0 0 calc(var(--cap-col) + var(--gutter)); }
.cap-bar .t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cap-bar.is-bottom { top: auto; bottom: calc(var(--cap-pad-b) + var(--j) * var(--cap-bar)); z-index: 30; }
/* Arriba se apilan igual que abajo: paso de una barra por capitulo abierto. */
.cap-bar.is-top { top: calc(var(--cap-pad) + var(--i, 0) * var(--cap-bar)); bottom: auto; z-index: calc(20 + var(--i, 0)); color: var(--ink-60); }
.cap-bar.is-open { color: var(--charcoal); }
.cap-bar.is-open .n { color: var(--teal); }

/* Capitulo = barra + texto + contenido, los TRES hijos directos del flex .caps
   (via .cap display:contents). Asi barra y texto tienen como bloque contenedor
   la seccion entera y pueden quedarse pegados hasta el final: cada capitulo
   nuevo TAPA al anterior en el mismo lugar (todas las barras a top = pad, todos
   los textos a top = pad + barra; z-index creciente por --i). El texto lleva
   fondo y alto minimo para cubrir de verdad al de abajo. */
.cap-txt {
  flex: 0 0 var(--cap-w8);
  align-self: flex-start;
  position: sticky;
  /* pega justo debajo de la pila abierta (i+1 barras). El aire va como padding
     ADENTRO del bloque, asi el fondo cubre al copy anterior sin dejar franja. */
  top: calc(var(--cap-pad) + (var(--i, 0) + 1) * var(--cap-bar));
  z-index: calc(10 + var(--i, 0));
  background: var(--cloud);
  padding-top: var(--sp-m);
  min-height: 38vh;
}
.caps.no-stick .cap-txt { position: static; }
.cap-txt p { font-size: 14px; line-height: 1.7; color: var(--ink-60); max-width: 46ch; }
.cap-content {
  flex: 0 0 var(--cap-w15);
  margin-left: calc(var(--cap-col) + 2 * var(--gutter));
  min-width: 0; display: grid; gap: var(--gutter); padding-top: var(--gutter);
}

/* Ficha del capítulo — el dato relevante va acá, en bold y FUERA de las barras
   de título (si va adentro se lee como una barra dentro de otra barra). */
.cap-ficha { display: flex; flex-wrap: wrap; gap: var(--sp-m) var(--sp-xxl); padding-bottom: var(--sp-m); }
.cap-ficha > div { min-width: 0; }
.cap-ficha dt {
  font-size: 10px; font-weight: 500; letter-spacing: 0.32em;
  text-transform: uppercase; color: var(--ink-40);
}
.cap-ficha dd {
  font-size: clamp(15px, 1.4vw, 19px); font-weight: 600;
  letter-spacing: -0.01em; line-height: 1.35; margin-top: 8px;
}

.cap-media { display: grid; gap: var(--gutter); grid-template-columns: 1fr; }
.cap-media.duo  { grid-template-columns: 1fr 1fr; }
.cap-media.trio { grid-template-columns: repeat(3, 1fr); }
.cap-media.solo { grid-template-columns: 1fr 1fr; }
.cap-media.solo .cap-mf { grid-column: 2; }

.cap-mf { position: relative; overflow: hidden; width: 100%; background: rgba(124, 58, 237, 0.06); }
/* Galeria de renders: 3 por fila, filas agrupadas por ratio (mismo ratio a
   igual ancho = misma altura, sin recortar). Al hover se agranda el LIENZO
   entero, no la imagen adentro: misma escala que "Otros proyectos". */
.cap-media.renders { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); align-items: start; }
.cap-media.renders .cap-mf {
  transition: transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.7s ease;
  transform-origin: center;
}
.cap-media.renders .cap-mf:hover { transform: scale(1.04); z-index: 2; }
html.mov-reducido .cap-media.renders .cap-mf { transition: none; }
.cap-mf > img, .cap-mf > video { width: 100%; height: 100%; object-fit: cover; }
/* El ratio del marco sigue al del archivo: nunca se recorta el ancho. */
.cap-mf.r45  { aspect-ratio: 4 / 5; }
.cap-mf.r34  { aspect-ratio: 3 / 4; }
.cap-mf.r43  { aspect-ratio: 4 / 3; }
.cap-mf.r54  { aspect-ratio: 5 / 4; }
.cap-mf.r11  { aspect-ratio: 1 / 1; }
.cap-mf.r32  { aspect-ratio: 3 / 2; }
.cap-mf.r169 { aspect-ratio: 16 / 9; }
.cap-mf.r916 { aspect-ratio: 9 / 16; }
/* ---------- Capturas de una página web dentro de un capítulo (2026-09-17) ----------
   Marco de navegador mínimo: una barra hairline con el nombre de la pantalla, SIN
   semáforo de macOS ni URL. La barra hace de pie de foto: una captura de interfaz no
   se explica sola como un render. Si el marco es <a>, toda la captura abre la página. */
.cap-browser { display: block; border: 1px solid var(--line); background: var(--cloud); color: inherit; text-decoration: none; }
.cb-bar {
  display: flex; justify-content: space-between; align-items: center; height: 34px; padding: 0 var(--sp-s);
  border-bottom: 1px solid var(--line);
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; line-height: 1; color: var(--ink-60);
}
.cb-go { color: var(--teal); }
.cb-shot { display: block; overflow: hidden; }
.cb-shot img { display: block; width: 100%; height: auto; transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); }
a.cap-browser:hover .cb-shot img { transform: scale(1.02); }
html.mov-reducido .cb-shot img { transition: none; }
/* botón bajo el copy del capítulo: mismo cta-link, a escala de la columna de texto */
.cap-cta { margin-top: var(--sp-m); font-size: 12px; gap: var(--sp-xs); }
.cap-cta .arrow { width: 14px; height: 14px; }
/* celular que ocupa toda la celda (trío de pantallas mobile) */
.cap-phone.fill { aspect-ratio: 9 / 19; background: none; overflow: visible; }
.cap-phone.fill .ph-frame { top: 0; bottom: 0; left: 0; transform: none; width: 100%; }

/* Celular placeholder dentro de una celda de medios (2026-09-17). Marco en CSS hasta
   que entre el mockup profesional; ese día la celda pasa a ser un <img> común. */
.cap-phone .ph-frame {
  position: absolute; top: 6%; bottom: 6%; left: 50%; aspect-ratio: 9 / 19;
  transform: translateX(-50%); padding: 9px; border-radius: 38px; background: var(--charcoal);
}
.cap-phone .ph-frame::before {
  content: ""; position: absolute; z-index: 2; top: 18px; left: 50%; width: 26%; height: 16px;
  transform: translateX(-50%); border-radius: 10px; background: var(--charcoal);
}
.cap-phone .ph-screen { position: relative; height: 100%; border-radius: 30px; overflow: hidden; background: var(--cloud); }
.cap-phone .ph-screen > img, .cap-phone .ph-screen > video { width: 100%; height: 100%; object-fit: cover; display: block; }

.cap-plh {
  position: absolute; inset: 0; display: flex; align-items: flex-end;
  padding: var(--sp-m);
  border: 1px dashed rgba(124, 58, 237, 0.45);
  color: var(--violet); font-size: 11px; font-weight: 400;
  letter-spacing: 0.18em; text-transform: uppercase;
}

/* ---------- Dos medios a media página + preview que persigue el cursor ---------- */
.duo-bleed { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; }
.dbl { position: relative; display: block; text-decoration: none; }
.dbl__wrap {
  position: relative; overflow: hidden; aspect-ratio: 1 / 1;
  padding: var(--sp-m);
  transition: padding 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.dbl:hover .dbl__wrap { padding: 0; }
.dbl__inner { position: relative; width: 100%; height: 100%; overflow: hidden; background: rgba(124, 58, 237, 0.06); }
.dbl__inner img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1); }
.dbl:hover .dbl__inner img { transform: scale(1.04); }
.dbl__meta {
  display: flex; justify-content: space-between; gap: var(--sp-s);
  padding: 14px var(--sp-m) 0;
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-40); transition: color 0.3s ease;
}
.dbl:hover .dbl__meta { color: var(--charcoal); }
.dbl__chase { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 4; opacity: 0; transition: opacity 0.35s ease; }
.dbl.on .dbl__chase { opacity: 1; }
.dbl__chase .box {
  width: 320px; overflow: hidden; background: rgba(124, 58, 237, 0.92);
  transform: translate(-50%, -50%) scale(0.92);
  transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.dbl__chase .box.r169 { aspect-ratio: 16 / 9; }
.dbl__chase .box.r45 { aspect-ratio: 4 / 5; width: 260px; }
.dbl.on .dbl__chase .box { transform: translate(-50%, -50%) scale(1); }
.dbl__chase video, .dbl__chase img { width: 100%; height: 100%; object-fit: cover; }
.dbl__chase .cap-plh { border-color: rgba(240, 238, 233, 0.5); color: var(--cloud); align-items: center; justify-content: center; text-align: center; }

/* ---------- Cursor: píldora con marquesina (solo sobre [data-cursor]) ---------- */
.ncur { position: fixed; top: 0; left: 0; width: 0; height: 0; z-index: 60; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; }
.ncur.on { opacity: 1; }
.ncur__pill {
  position: absolute; top: 12px; left: 12px; width: 124px; padding: 6px 0;
  overflow: hidden; background: var(--charcoal); color: var(--cloud);
  transform: scale(0.6); transform-origin: top left;
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.ncur.on .ncur__pill { transform: scale(1); }
.ncur__track { display: flex; width: max-content; animation: ncurMarq 7s linear infinite; }
.ncur__track span {
  padding: 0 12px; font-size: 10px; font-weight: 500; letter-spacing: 0.18em;
  text-transform: uppercase; white-space: nowrap; line-height: 1;
}
@keyframes ncurMarq { to { transform: translateX(-50%); } }

/* Hero de página interior: mismo headline del home (Inter 800 caps + scramble)
   pero sin el escalonado ni el alto del hero de portada. */
.hero-v3.hero-pag { min-height: 0; padding-block: calc(104px + clamp(40px, 8vh, 96px)) clamp(32px, 4vw, 56px); }
.hero-pag h1 { font-size: clamp(30px, 5.6vw, 76px); max-width: none; }
.hero-pag .lead { margin-top: var(--sp-l); }

html.mov-reducido .dbl__wrap,
html.mov-reducido .dbl__inner img { transition: none; }
html.mov-reducido .dbl__chase { display: none; }
html.mov-reducido .ncur__track { animation: none; }

@media (max-width: 1023px) {
  .cap-bar { flex: 0 0 100%; }
  /* el indice pasa a ancho completo: las tapas tambien, si no el contenido
     asoma por debajo de la ultima barra */
  .cap-mask { flex: 0 0 100%; }
  .cap-txt { flex: 0 0 100%; position: static; min-height: 0; }
  .cap-content { flex: 0 0 100%; margin-left: 0; margin-top: var(--sp-m); }
  .cap-media.solo { grid-template-columns: 1fr; }
  .cap-media.solo .cap-mf { grid-column: 1; }
  .duo-bleed { grid-template-columns: 1fr; }
  .ncur { display: none; }
}
@media (max-width: 640px) {
  .cap-media.duo, .cap-media.trio { grid-template-columns: 1fr; }
  .cap-media.renders { grid-template-columns: 1fr 1fr; }
  .cap-ficha { gap: var(--sp-m) var(--sp-l); }
  .hero-pag h1 { line-height: 0.92; }
  .hero-pag h1 .hl { white-space: normal; }
}

/* ============================================================
   §  PANEL DE PROYECTOS (2026-09-15)
   Misma carcasa que el panel de Contacto (.cpanel / .cp-panel /
   .cp-backdrop / html.cp-open). Lo propio: la lista de filas, que
   son las MISMAS barras de titulo del indice sticky, y el gimmick
   de entrada — apiladas con 34px de offset, igual que la pila de
   abajo del indice, y se despliegan.
   ============================================================ */
.ppanel .cp-panel { width: clamp(420px, 40vw, 680px); }
.ppanel .cp-title { margin-bottom: var(--sp-l); }

.pp-list { list-style: none; margin: 0; padding: 0; }
.pp-row {
  position: relative;
  background: var(--cloud);          /* al apilarse, cada fila tapa a la anterior */
  border-top: 1px solid var(--line);
}
.pp-row:last-child { border-bottom: 1px solid var(--line); }
/* El despliegue va por ANIMACION, no por transicion: el panel viene de
   display:none y el estado inicial (la pila) no alcanza a comprometerse, asi
   que una transicion arranca desde 0 y no se ve nada. Con @keyframes +
   backwards el navegador sostiene el `from` durante el delay. --dy lo calcula
   JS al abrir, porque depende del alto real de la fila. */
@keyframes ppDesplegar {
  from { transform: translateY(var(--dy, 0px)); }
  to   { transform: none; }
}
.ppanel.open .pp-row {
  animation: ppDesplegar 0.75s cubic-bezier(0.22, 0.61, 0.27, 1) var(--d, 0s) backwards;
}
/* al cerrar el panel se va entero: que las filas no hagan el camino de vuelta */
.ppanel.closing .pp-row { transition: none; }

.pp-link {
  display: grid;
  grid-template-columns: var(--pp-mini-w, 96px) 2.4em 1fr auto;
  gap: var(--gutter);
  align-items: start;                /* el renglon de texto vive en los 34px de arriba */
  padding: var(--sp-xs) 0;
  text-decoration: none;
  color: var(--ink-40);
  transition: color 0.3s ease;
}
.pp-n, .pp-t, .pp-y {
  height: 34px; display: flex; align-items: center;
  font-size: 11px; font-weight: 400; letter-spacing: 0.1em;
  text-transform: uppercase; line-height: 1;
}
.pp-t { color: var(--ink-60); min-width: 0; }
.pp-y { justify-content: flex-end; }
.pp-link:hover, .pp-link:focus-visible { color: var(--charcoal); }
.pp-link:hover .pp-t, .pp-link:focus-visible .pp-t { color: var(--charcoal); }
.pp-link:hover .pp-n, .pp-link:focus-visible .pp-n { color: var(--teal); }

.pp-mini { display: block; overflow: hidden; background: rgba(124, 58, 237, 0.06); }
.pp-mini img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.pp-link:hover .pp-mini img { transform: scale(1.05); }
/* Dos variantes en prueba — tecla M alterna. Cuadrada = referencia ref.digital
   (recorta en vertical, el ancho se respeta). 4:5 = ratio de nuestros renders. */
.pp-list[data-mini="cuadrada"] .pp-mini { aspect-ratio: 1 / 1; }
.pp-list[data-mini="r45"] .pp-mini { aspect-ratio: 4 / 5; }

html.mov-reducido .ppanel.open .pp-row { animation: none; }
html.mov-reducido .pp-mini img { transition: none; }

@media (max-width: 860px) {
  .ppanel .cp-panel { width: auto; }
  .pp-link { grid-template-columns: 72px 2.4em 1fr auto; }
}

/* Hero de pagina de proyecto: el nombre como titulo grande. */
.hero-pag.hero-titulo h1 { font-size: clamp(56px, 13vw, 190px); }
.hero-pag .cap-ficha { margin-top: var(--sp-xl); padding-bottom: 0; }

/* ============================================================
   §  MVP (2026-09-22)
   ============================================================ */

/* ---------- Web en construcción: aviso sutil ----------
   Abajo al centro, charcoal, dos renglones cortos. Sube, se queda 3,6 s y se va.
   Por encima del WhatsApp flotante (200) y debajo de los paneles (300). */
.wip-toast {
  position: fixed; left: 50%; bottom: var(--sp-l); z-index: 250;
  display: flex; flex-direction: column; gap: 4px;
  max-width: min(420px, calc(100vw - 2 * var(--page-margin)));
  padding: 14px 20px;
  background: var(--charcoal); color: var(--cloud);
  box-shadow: 0 10px 30px rgba(47, 49, 43, 0.18);
  transform: translate(-50%, 16px); opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.wip-toast.on { opacity: 1; transform: translate(-50%, 0); }
.wip-k { font-size: 9px; font-weight: 500; letter-spacing: 0.28em; text-transform: uppercase; color: var(--cloud-55); }
.wip-m { font-size: 13px; line-height: 1.5; }
html.mov-reducido .wip-toast { transition: none; }

/* ---------- Home: tarjetas de proyecto clickeables ---------- */
.proy-a { display: block; color: inherit; text-decoration: none; }
.proy-a .proy-pl img { transition: filter 0.6s ease; }
.proy-a:hover .proy-t, .proy-a:focus-visible .proy-t { color: var(--teal); }
.proy-t { transition: color 0.3s ease; }

/* ---------- Home: salida del riel de Servicios ---------- */
.serv-foot { padding-block: var(--sp-xl) 0; }

/* ---------- Formulario: nota de estado (sin endpoint) ---------- */
.form-note { font-size: 13px; line-height: 1.6; color: var(--ink-60); min-height: 1.6em; }
.form-note.on { color: var(--charcoal); }

/* ---------- Lista de servicios dentro del copy de un capítulo ----------
   Mismo lenguaje que las barras del índice: filas hairline, texto chico. El nombre
   del servicio en tinta y la aclaración atenuada, en una sola línea cuando entra. */
.cap-list { list-style: none; margin-top: var(--sp-l); max-width: 46ch; border-bottom: 1px solid var(--line); }
.cap-list li {
  display: grid; grid-template-columns: 1fr; gap: 2px;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.cap-list b { font-size: 14px; font-weight: 400; color: var(--charcoal); }
.cap-list span { font-size: 13px; line-height: 1.5; color: var(--ink-60); }

/* ---------- Muestras a pedido ----------
   Donde el material existe pero no se publica (brochures, fichas: son del cliente),
   en vez de un placeholder, un bloque honesto que invita a pedirlo. */
.cap-sample {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 1fr 1fr; min-height: 420px;
  background: var(--charcoal); color: var(--cloud);
}
.cap-sample__txt { padding: clamp(24px, 3vw, 48px); display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-xl); }
.cap-sample__txt .eyebrow { margin-bottom: var(--sp-s); }
.cap-sample__h { font-size: clamp(22px, 2.2vw, 32px); font-weight: 200; letter-spacing: -0.02em; line-height: 1.15; max-width: 16ch; }
.cap-sample__p { font-size: 14px; line-height: 1.7; color: var(--cloud-72); max-width: 38ch; margin-top: var(--sp-m); }
.cap-sample .cta-link { color: var(--cloud); font-size: 13px; gap: var(--sp-xs); align-self: flex-start; }
.cap-sample .cta-link .arrow { width: 14px; height: 14px; }
.cap-sample__img { position: relative; }
.cap-sample__img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 860px) {
  .cap-sample { grid-template-columns: 1fr; }
  .cap-sample__img { aspect-ratio: 4 / 5; }
}

/* ---------- Planta humanizada: fondo cloud, sin marco ---------- */
.cap-mf.r43 > img.planta { object-fit: contain; background: var(--cloud); }

/* ---------- Servicios: cómo trabajamos ---------- */
.proceso .phase-h { font-weight: 300; }
.proceso-lead { margin-top: var(--sp-m); }

/* Contacto: datos */
.nap .cv { color: var(--charcoal); }
.nap a.cv:hover { color: var(--teal); }

/* [hidden] siempre gana: .form (display:flex) y otras clases lo pisaban y el
   formulario del panel seguía visible debajo del mensaje de "enviado". */
[hidden] { display: none !important; }
.wip-toast { border: 1px solid var(--line-dark); }
@media (max-width: 640px) {
  .hero-pag:not(.hero-titulo) h1 { font-size: clamp(24px, 7.2vw, 30px); }
}
/* WhatsApp flotante: oculto mientras no haya número (data-wip). Al cargar el
   número real y sacar data-wip, vuelve solo. */
.wa-float[data-wip] { display: none; }

/* ============================================================
   §  Correcciones pre-lanzamiento (2026-09-24)
   ============================================================ */

/* CTA siempre sobre fondo claro: una hairline lo separa de la sección anterior */
.cta-band { border-top: 1px solid var(--line); }

/* Servicios: "qué incluye" pasa a la columna de medios. La columna del índice queda
   con un solo párrafo; la lista se lee como una ficha de dos columnas. */
.cap-deliv {
  list-style: none; display: grid; grid-template-columns: repeat(2, 1fr);
  column-gap: var(--gutter); margin-bottom: var(--sp-l);
  border-bottom: 1px solid var(--line);
}
.cap-deliv li {
  display: grid; grid-template-columns: 1fr; row-gap: 4px;
  padding: 14px 0 18px; border-top: 1px solid var(--line);
}
.dv-n { grid-row: 1 / 3; font-size: 11px; letter-spacing: 0.1em; color: var(--teal); padding-top: 4px; }
.cap-deliv b { font-size: 15px; font-weight: 400; color: var(--charcoal); }
.dv-d { font-size: 13px; line-height: 1.55; color: var(--ink-60); }
@media (max-width: 640px) { .cap-deliv { grid-template-columns: 1fr; } }

/* Portfolio: mismo hover que la galería de Visualización (escala el lienzo entero) */
.pf-fig { position: relative; overflow: hidden; }
/* Hover como "Otros proyectos": el marco se abre hasta el borde de la celda y la
   imagen se acerca adentro. Se anima la imagen (no la figura) para no pelear con
   el transform del .reveal (.js .reveal.in le ganaba a .pf-fig:hover). */
.pf-fig > img, .pf-fig > video {
  clip-path: inset(6px); transform: scale(1);
  transition: clip-path 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.pf-fig:hover > img, .pf-fig:hover > video { clip-path: inset(0); transform: scale(1.04); }
html.mov-reducido .pf-fig > img, html.mov-reducido .pf-fig > video { transition: none; }
.pf-title { font-weight: 700; text-transform: uppercase; letter-spacing: -0.01em; }

/* ---------- Cursor circular en negativo ----------
   Un disco blanco con mix-blend-mode:difference: sobre cloud se ve casi negro, sobre
   charcoal casi blanco, sobre una imagen invierte lo que tiene abajo. Crece sobre lo
   clickeable. Solo con mouse (pointer fine); en touch no existe. En campos de texto
   vuelve el cursor de texto del sistema. */
html.has-cursor, html.has-cursor * { cursor: none !important; }
html.has-cursor input, html.has-cursor textarea { cursor: text !important; }
.ncircle {
  position: fixed; top: 0; left: 0; z-index: 10000; pointer-events: none;
  width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
  background: #FFFFFF; mix-blend-mode: difference;
  transition: width 0.3s cubic-bezier(0.2, 0.7, 0.2, 1), height 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
              margin 0.3s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.2s ease;
  will-change: transform;
}
.ncircle.big { width: 44px; height: 44px; margin: -22px 0 0 -22px; }
.ncircle.down { width: 10px; height: 10px; margin: -5px 0 0 -5px; }
.ncircle.off { opacity: 0; }

/* Muestras: también es un CTA → fondo claro (Juan, 2026-09-24: ningún CTA en oscuro) */
.cap-sample { background: transparent; color: var(--charcoal); border: 1px solid var(--line); }
.cap-sample__p { color: var(--ink-70); }
.cap-sample .cta-link { color: var(--teal); }
.cb-shot video { display: block; width: 100%; height: auto; }

/* ---------- Piezas reales dentro de un capítulo (2026-09-27) ----------
   Material de venta: páginas del brochure/ficha/flyer apoyadas sobre un plano
   apenas más oscuro que el fondo (charcoal 5%), con sombra corta de papel.
   Mismo plano para el mockup de Instagram: todo lo "entregado" vive ahí. */
.doc-stage {
  background: rgba(47, 49, 43, 0.05);
  padding: clamp(16px, 3.2vw, 56px);
  display: grid; gap: clamp(20px, 2.6vw, 44px);
}
.doc-row { display: grid; gap: clamp(12px, 1.6vw, 28px); align-items: start; }
.doc-row.two { grid-template-columns: 1fr 1fr; }
.doc-row.three { grid-template-columns: repeat(3, 1fr); }
.doc-page { margin: 0; min-width: 0; }
.doc-page img {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  background: var(--cloud);
  box-shadow: 0 0 0 1px rgba(47, 49, 43, 0.06), 0 18px 34px -22px rgba(47, 49, 43, 0.5);
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.doc-page:hover img { transform: translateY(-4px); box-shadow: 0 0 0 1px rgba(47, 49, 43, 0.06), 0 26px 40px -24px rgba(47, 49, 43, 0.55); }
html.mov-reducido .doc-page img { transition: none; }
.doc-cap {
  display: flex; justify-content: space-between; gap: var(--sp-s);
  margin-top: 12px; font-size: 10px; font-weight: 500; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--ink-40);
}
/* versión celular: la pieza larga baja sola dentro de la pantalla */
.doc-phones { grid-template-columns: repeat(var(--n, 2), minmax(0, 210px)); justify-content: center; column-gap: clamp(28px, 6vw, 96px); }
.doc-phones .doc-cap { justify-content: center; margin-top: 18px; }
.ph-scroll {
  position: absolute; inset: 0;
  background-size: 100% auto; background-repeat: no-repeat; background-position: 50% 0%;
}
.ph-scroll.run { animation: phScroll var(--dur, 80s) linear infinite alternate; }
.doc-ph:hover .ph-scroll { animation-play-state: paused; }
html.mov-reducido .ph-scroll.run { animation: none; }
@keyframes phScroll { to { background-position: 50% 100%; } }

/* ---------- Mockup de Instagram (2026-09-27) ----------
   Una publicación de carrusel reducida a lo mínimo que la hace legible como
   Instagram (cabecera, contador, puntos, íconos de línea), sin cuenta real ni
   interfaz de la app. Al lado, las láminas de la serie: tocar una la muestra. */
.igm {
  display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: clamp(24px, 3.6vw, 64px); align-items: center;
}
.igm-card {
  background: var(--cloud);
  box-shadow: 0 0 0 1px rgba(47, 49, 43, 0.06), 0 22px 40px -26px rgba(47, 49, 43, 0.55);
}
.igm-h { display: flex; align-items: center; gap: 10px; padding: 12px 14px; }
.igm-av {
  flex: 0 0 30px; height: 30px; border-radius: 50%;
  background-size: cover; background-position: center;
  box-shadow: 0 0 0 1.5px var(--cloud), 0 0 0 2.5px rgba(47, 49, 43, 0.25);
}
.igm-id { display: grid; line-height: 1.25; min-width: 0; }
.igm-id b { font-size: 12px; font-weight: 600; letter-spacing: -0.005em; }
.igm-id span { font-size: 11px; color: var(--ink-60); }
.igm-more { margin-left: auto; font-size: 14px; letter-spacing: 0.1em; color: var(--ink-60); line-height: 1; }
.igm-media { position: relative; overflow: hidden; aspect-ratio: 4 / 5; background: rgba(47, 49, 43, 0.06); touch-action: pan-y; }
.igm-track { display: flex; height: 100%; transition: transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1); }
html.mov-reducido .igm-track { transition: none; }
.igm-track img { flex: 0 0 100%; width: 100%; height: 100%; object-fit: cover; display: block; user-select: none; -webkit-user-drag: none; }
.igm-count {
  position: absolute; top: 12px; right: 12px; padding: 4px 8px; border-radius: 20px;
  background: rgba(47, 49, 43, 0.62); color: var(--cloud);
  font-size: 10px; font-weight: 500; letter-spacing: 0.06em; font-variant-numeric: tabular-nums;
}
.igm-f { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 10px 12px 14px; }
.igm-ic { display: flex; gap: 14px; color: var(--charcoal); }
.igm-ic.r { justify-content: flex-end; }
.igm-ic svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.igm-dots { display: flex; gap: 4px; }
.igm-dots i { width: 5px; height: 5px; border-radius: 50%; background: rgba(47, 49, 43, 0.22); transition: background 0.3s ease; }
.igm-dots i.on { background: var(--teal); }
.igm-lbl { font-size: 10px; font-weight: 500; letter-spacing: 0.32em; text-transform: uppercase; color: var(--ink-40); margin-bottom: var(--sp-m); }
.igm-thumbs { display: grid; grid-template-columns: repeat(var(--cols, 3), 1fr); gap: 26px clamp(10px, 1.2vw, 16px); max-width: 360px; }
.igm-t {
  position: relative; display: block; padding: 0; border: 0; background: none; cursor: pointer;
  aspect-ratio: 4 / 5; opacity: 0.42; transition: opacity 0.5s ease;
}
.igm-t img { width: 100%; height: 100%; object-fit: cover; display: block; }
.igm-t::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -10px; height: 1px;
  background: var(--charcoal); transform: scaleX(0); transform-origin: left;
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.igm-t:hover { opacity: 0.75; }
.igm-t[aria-current="true"] { opacity: 1; }
.igm-t[aria-current="true"]::after { transform: scaleX(1); }
.igm-t:focus-visible { outline: 1px solid var(--teal); outline-offset: 3px; }
.igm-note { margin-top: calc(var(--sp-m) + 10px); font-size: 13px; line-height: 1.6; color: var(--ink-60); max-width: 44ch; }

@media (max-width: 860px) {
  .doc-row.three { grid-template-columns: 1fr 1fr; }
  .doc-row.three > :first-child { grid-column: 1 / -1; }
  .igm { grid-template-columns: 1fr; }
  .igm-card { max-width: 420px; }
  .igm-thumbs { grid-template-columns: repeat(var(--n, 5), 1fr); max-width: 420px; }
}
@media (max-width: 560px) {
  .doc-row.two, .doc-row.three { grid-template-columns: 1fr; }
  .doc-phones { column-gap: 16px; }
}

/* ---------- Mockups de dispositivo para las piezas digitales (2026-09-27) ----------
   Notebook / tablet en CSS, con una barra mínima de visor (nombre de la pieza y
   página) y las páginas reales pasando solas. Un celular se apoya adelante con la
   versión mobile de la misma pieza. Pantalla 16:10: barra 6,25cqw + página 16:9. */
.mk-scene { position: relative; margin: 0; padding-bottom: clamp(28px, 4vw, 56px); }
.mk-dev { position: relative; filter: drop-shadow(0 26px 30px rgba(47, 49, 43, 0.22)); }
.mk-a .mk-dev { width: 84%; }
.mk-b .mk-dev { width: 78%; margin-left: auto; }
.mk-lid { background: var(--charcoal); padding: 2%; border-radius: 14px 14px 5px 5px; }
.mk-tablet .mk-lid { padding: 2.6%; border-radius: 26px; }
.mk-screen {
  position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--cloud);
  container-type: inline-size; display: flex; flex-direction: column;
}
.mk-tablet .mk-screen { border-radius: 8px; }
.mk-bar {
  flex: 0 0 6.25cqw; display: flex; justify-content: space-between; align-items: center;
  padding: 0 2.4cqw; border-bottom: 1px solid var(--line);
  font-size: max(8px, 1.25cqw); font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-60); white-space: nowrap;
}
.mk-pg { font-variant-numeric: tabular-nums; color: var(--ink-40); }
.mk-view { position: relative; flex: 1 1 auto; }
.mk-view img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 0.9s ease;
}
.mk-view img.on { opacity: 1; }
html.mov-reducido .mk-view img { transition: none; }
.mk-base {
  position: relative; width: 112%; margin-left: -6%; height: 0; padding-bottom: 2.6%;
  background: linear-gradient(to bottom, #dcd9d2 0%, #c4c0b8 60%, #a9a59c 100%);
  border-radius: 2px 2px 16px 16px / 2px 2px 100% 100%;
}
.mk-base::before {
  content: ""; position: absolute; top: 0; left: 50%; width: 15%; height: 38%;
  transform: translateX(-50%); background: #b3afa7; border-radius: 0 0 8px 8px;
}
.mk-ph { position: absolute; bottom: clamp(20px, 3vw, 44px); right: 0; width: 20%; filter: drop-shadow(0 20px 24px rgba(47, 49, 43, 0.3)); }
.mk-b .mk-ph { right: auto; left: 2%; }
.mk-ph .cap-phone .ph-frame { padding: 6%; border-radius: 17% / 8%; }
.mk-ph .cap-phone .ph-frame::before { top: 3.2%; height: 3%; border-radius: 99px; }
.mk-ph .cap-phone .ph-screen { border-radius: 13% / 6%; }
.mk-scene > .doc-cap { position: absolute; left: 0; right: 0; bottom: 0; margin: 0; }
.mk-b > .doc-cap { flex-direction: row-reverse; }
@media (max-width: 560px) {
  /* en celular el teléfono pisa el rótulo de la derecha: queda solo el de la izquierda */
  .mk-scene > .doc-cap > span:last-child { display: none; }
  .mk-b > .doc-cap { flex-direction: row; justify-content: flex-end; }
  .mk-a .mk-dev, .mk-b .mk-dev { width: 88%; }
  .mk-ph { width: 26%; }
  .mk-lid { border-radius: 8px 8px 3px 3px; }
  .mk-tablet .mk-lid { border-radius: 14px; }
}

/* ---------- Portfolio: 5 columnas + vistas que ciclan de luz (2026-09-27) ---------- */
.pf-row.c5 { grid-template-columns: repeat(5, 1fr); }
.pf-cycle .pf-alt {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transition: opacity 1.4s ease, clip-path 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.pf-cycle .pf-alt.on { opacity: 1; }
.pf-dots { position: absolute; left: 18px; bottom: 18px; z-index: 2; display: flex; gap: 5px; pointer-events: none; }
.pf-dots i { width: 5px; height: 5px; border-radius: 50%; background: rgba(240, 238, 233, 0.45); transition: background 0.6s ease; }
.pf-dots i.on { background: var(--cloud); }
@media (max-width: 860px) {
  .pf-row.c5 { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .pf-row.c5 > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* Honeypot de Netlify Forms: fuera de pantalla, invisible para personas */
.hp { position: absolute !important; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Home con dos proyectos (2026-09-30: sale Simona) */
.proy-grid.dos { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 860px) { .proy-grid.dos { grid-template-columns: 1fr; } }
/* "Otros proyectos" con uno solo: ocupa el ancho, apaisado */
.duo-bleed.one { grid-template-columns: 1fr; }
.duo-bleed.one .dbl__wrap { aspect-ratio: 21 / 9; }
@media (max-width: 640px) { .duo-bleed.one .dbl__wrap { aspect-ratio: 4 / 3; } }

/* ---------- Aviso de cookies (2026-09-30) ----------
   Sutil: tarjeta chica abajo a la izquierda, fondo cloud, hairline, dos botones de texto.
   Solo aparece si hay IDs de medición cargados en main.js. */
.consent {
  position: fixed; left: var(--page-margin); bottom: 24px; z-index: 70; max-width: 340px;
  padding: 16px 18px; background: var(--cloud); border: 1px solid var(--line);
  box-shadow: 0 18px 34px -24px rgba(47, 49, 43, 0.45);
  opacity: 0; transform: translateY(8px); transition: opacity 0.5s ease, transform 0.5s ease;
}
.consent.on { opacity: 1; transform: none; }
.consent-t { font-size: 12px; line-height: 1.6; color: var(--ink-70); }
.consent-b { display: flex; gap: var(--sp-m); margin-top: 12px; }
.consent-b button {
  padding: 4px 0; border: 0; background: none; cursor: pointer; font: inherit;
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
}
.consent-ok { color: var(--teal); border-bottom: 1px solid currentColor !important; }
.consent-no { color: var(--ink-60); }
.consent-b button:focus-visible { outline: 1px solid var(--teal); outline-offset: 3px; }
html.mov-reducido .consent { transition: none; }
@media (max-width: 640px) {
  .consent { left: 16px; right: 16px; bottom: 16px; max-width: none; }
  html.has-consent .wa-float { opacity: 0; pointer-events: none; }
}

/* ---------- Política de privacidad (2026-09-30): columna de lectura angosta ---------- */
.legal h1 { font-size: clamp(34px, 5vw, 64px); font-weight: 200; letter-spacing: -0.02em; line-height: 1.05; margin-top: var(--sp-s); }
.legal-fecha { margin-top: var(--sp-m); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-40); }
.legal-body { max-width: 64ch; margin-top: var(--sp-xxl); padding-bottom: var(--sp-xxl); }
.legal-body h2 {
  font-size: 11px; font-weight: 500; letter-spacing: 0.24em; text-transform: uppercase; color: var(--teal);
  margin-top: var(--sp-xl); padding-top: var(--sp-m); border-top: 1px solid var(--line);
}
.legal-body h2 { max-width: none; width: 100%; line-height: 1.4; }
.legal-body h2:first-child { margin-top: 0; }
.legal-body p { margin-top: var(--sp-s); font-size: 15px; line-height: 1.7; color: var(--ink-70); }
.legal-body b { font-weight: 500; color: var(--charcoal); }
.legal-body a { color: var(--teal); }
.legal-body .legal-nota { font-size: 12px; line-height: 1.6; color: var(--ink-40); }
.consent-t a { color: var(--ink-70); text-decoration: underline; text-underline-offset: 2px; }
.footer-legal a { color: inherit; text-decoration: none; }
.footer-legal a:hover { text-decoration: underline; }
/* Proyectos sin página todavía: misma tarjeta, sin link, con una marca chica */
.proy-prox .proy-a { cursor: default; }
.proy-prox .proy-a:hover .proy-t { color: inherit; }
.proy-soon {
  margin-top: 10px; font-size: 10px; font-weight: 500; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-40); display: flex; align-items: center; gap: 10px;
}
.proy-soon::before { content: ""; width: 18px; height: 1px; background: currentColor; }
