/* ============================================================
   PRISMA · helloprisma.com
   Sistema visual · Brandbook 2024 + Brochure 2026
   ============================================================ */

/* Tipografía oficial de la web: Manrope (Google Fonts, cargada en el HTML). */

:root {
  /* Cromática Prisma */
  --orange: #FF4201;        /* primario · todos los acentos de UI */
  --orange-deep: #C42D00;   /* hover / presionado */
  --tangerine: #EE7D00;     /* solo dentro de degradados decorativos */
  --grad: linear-gradient(90deg, #FF4201, #FF6A00);
  --ink: #0A0A0A;
  --ink-2: #151516;
  --ink-3: #202023;
  --text-on-ink: rgba(244, 244, 246, .92);
  --text-on-ink-2: rgba(244, 244, 246, .55);
  --line-on-ink: rgba(244, 244, 246, .14);

  /* Los tokens "paper" ya NO son claros. El sitio es oscuro de principio a
     fin: el salto a un fondo casi blanco justo después del hero rompía el
     ritmo, y era el único punto tan claro de todo el sitio. Se mantienen
     los NOMBRES para no tener que reescribir las clases .s-paper ni los
     `style` en línea del HTML; lo que cambia es que ahora apuntan a
     superficies oscuras secundarias. El naranja queda solo como acento. */
  --paper: #151516;
  --paper-2: #202023;
  --text-on-paper: rgba(244, 244, 246, .92);
  --text-on-paper-2: rgba(244, 244, 246, .55);
  --line-on-paper: rgba(244, 244, 246, .14);

  /* Tipografía */
  --f-display: 'Manrope', system-ui, -apple-system, sans-serif;
  --f-text: 'Manrope', system-ui, -apple-system, sans-serif;
  /* Escala calibrada con erretres.com (1440px: h1 51 · h2 32 · h3 20) */
  --fs-hero: clamp(2.1rem, 3.6vw, 3.2rem);
  --fs-h2: clamp(1.5rem, 2.25vw, 2rem);
  --fs-h3: clamp(1.1rem, 1.4vw, 1.25rem);
  --fs-lead: clamp(1.02rem, 1.15vw, 1.18rem);
  /* Titular de portada de Soluciones y sus hijas (Programas, Shop, 360,
     Contenido & Redes, Brand Fit): un mismo tamaño para toda la familia, un
     punto por encima de --fs-hero porque cada una es la puerta de un servicio.
     66 px a 1440, 70 px como máximo, 40 px en el teléfono. */
  --fs-display: clamp(2.5rem, 4.6vw, 4.4rem);
  --lh-display: 1.03;
  --ls-display: -0.028em;
  /* Dónde empieza el kicker (o las migas) de cada portada interior, medido
     desde arriba de la página: el mismo en todas para que el titular no salte
     al navegar entre páginas hermanas. Es el valor que ya usaba .page-hero
     (198 px a 1440×900); en el teléfono baja (139 px a 390×844, ver abajo).
     Se usa como padding-top del hero, con el texto arriba (no centrado en
     vertical contra la pieza de al lado). */
  --hero-top: calc(90px + 12vh);

  /* Forma y ritmo */
  --r: 24px;
  --r-lg: 36px;
  --gutter: clamp(20px, 5vw, 72px);
  --sect: clamp(90px, 14vh, 170px);
  /* Curvas de movimiento por TIPO de movimiento (referencia: apple.com).
     Elige por lo que hace el elemento, no por gusto; nunca bounce/elastic/back. */
  --ease-ui:    cubic-bezier(0.4, 0, 0.6, 1);         /* botones, hover, color, fondo, borde, opacidad, estados de UI controlados */
  --ease-enter: cubic-bezier(0.32, 0.08, 0.24, 1);    /* entrar, abrir, transformarse: responde rápido y asienta suave */
  --ease-exit:  cubic-bezier(0.52, 0.16, 0.52, 0.84); /* cerrar, salir, navegación más suave */
  --ease-snap:  cubic-bezier(0.04, 0.04, 0.12, 0.96); /* transformaciones pequeñas y rápidas con aterrizaje muy suave */
  --ease-soft:  cubic-bezier(0.25, 0.1, 0.3, 1);      /* movimiento sutil de interfaz (equivale a un `ease` afinado) */
  --ease-std:   cubic-bezier(0.25, 0.1, 0.25, 1);     /* el `ease` estándar de CSS, explícito */

  /* Componentes RGB de la paleta. Existen para poder cambiar la OPACIDAD sin
     reescribir el color: rgb(var(--fg-rgb) / .17). Antes cada velo, borde o
     sombra repetía el valor a mano y había 48 literales distintos sueltos. */
  --ink-rgb: 10 10 10;
  --ink-2-rgb: 21 21 22;
  --fg-rgb: 244 244 246;
  --orange-rgb: 255 66 1;
  --tangerine-rgb: 255 106 0;
  --warm-rgb: 10 8 6;            /* negro cálido de los velos sobre fotografía */
  --on-photo-rgb: 255 255 255;   /* blanco puro: SOLO encima de una foto, nunca sobre naranja */
  --on-photo: rgb(var(--on-photo-rgb));
  --shadow-rgb: 0 0 0;
  --ink-card: #1C1C1F;           /* superficie de las tarjetas de cliente */

  /* Superficies translúcidas y trazos derivados de lo anterior. */
  --glass: rgb(var(--ink-rgb) / .55);          /* píldoras y botones sobre foto */
  --glass-hover: rgb(var(--ink-rgb) / .8);
  --glass-panel: rgb(var(--ink-2-rgb) / .94);  /* panel del submenú */
  --glass-pill: rgb(var(--ink-2-rgb) / .82);
  --tint-hover: rgb(var(--fg-rgb) / .17);      /* fondo de un enlace de nav al pasar el cursor */
  --tint-soft: rgb(var(--fg-rgb) / .08);
  --shadow-sm: 0 3px 10px rgb(var(--shadow-rgb) / .4);
  --shadow-md: 0 8px 30px rgb(var(--shadow-rgb) / .35);
  --shadow-lg: 0 24px 70px rgb(var(--shadow-rgb) / .55);
  --shadow-panel: 0 18px 40px rgb(var(--shadow-rgb) / .35);
}
@media (max-width: 640px) { :root { --hero-top: calc(72px + 8vh); } }
/* Nota: los #000 y #fff que quedan en el archivo están todos dentro de una
   `mask` o `mask-image`. Ahí el color no se ve: es la plantilla de opacidad
   (negro = oculta, blanco = muestra). Convertirlos en tokens de color sería
   engañoso, así que se quedan como literales a propósito. */

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* scroll-padding: al tabular, el navegador acomoda el elemento con foco
   debajo de la cabecera fija (antes quedaba tapado al volver hacia arriba). */
html { scroll-behavior: auto; scroll-padding-top: 96px; scroll-padding-bottom: 24px; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
body {
  font-family: var(--f-text);
  font-size: 1.06rem;
  line-height: 1.65;
  color: var(--text-on-ink);
  background: var(--ink);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }
::selection { background: var(--orange); color: var(--ink); }
:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; border-radius: 4px; }

h1, h2, h3, h4 {
  font-family: var(--f-display);
  font-weight: 500;
  line-height: 1.14;
  letter-spacing: -0.01em;
}
/* Titulares equilibrados (2026-10-02): sin esto quedaban viudas ("¿Prefieres
   armar el / tuyo?") y oraciones partidas. Va con :where() (especificidad 0)
   para que cualquier regla de una página gane, también un `text-wrap: pretty`
   elegido a propósito, y con el longhand -style para no tocar el modo de
   corte (un `nowrap` heredado sigue mandando). splitLines (main.js) mide
   después del layout, así que congela el corte ya equilibrado. Para separar
   dos oraciones, un <br> en el HTML: splitLines lo respeta. */
:where(h1, h2, h3, .section__title, .cta__title, [data-split], [data-split-hero]) { text-wrap-style: balance; }

.container { max-width: 1440px; margin-inline: auto; padding-inline: var(--gutter); }

/* Saltar la cabecera: son diez enlaces repetidos en cada página, y sin este
   atajo quien navega con teclado o lector de pantalla tiene que recorrerlos
   una y otra vez (WCAG 2.4.1, nivel A). Solo aparece al recibir el foco. */
.skip-link {
  position: fixed; top: 10px; left: 10px; z-index: 300;
  padding: 12px 20px; border-radius: var(--r);
  background: var(--orange); color: var(--ink);
  font-weight: 500; font-size: .95rem; line-height: 1;
  transform: translateY(-160%);
  transition: transform .22s var(--ease-enter);
}
.skip-link:focus-visible { transform: translateY(0); outline-offset: 4px; }

/* Solo para lectores de pantalla (texto que existe pero no se ve). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Secciones claras */
.s-paper { background: var(--paper); color: var(--text-on-paper); }
.s-paper .muted { color: var(--text-on-paper-2); }
.s-ink { background: var(--ink); color: var(--text-on-ink); }
.s-ink .muted { color: var(--text-on-ink-2); }

/* ---------- Loader ---------- */
.loader {
  position: fixed; inset: 0; z-index: 200;
  background: var(--ink);
  display: flex; align-items: center; justify-content: center;
}
.loader__mark { width: clamp(48px, 6.6vw, 76px); height: auto; opacity: 0; transform: translateY(24px); }
.loader__count {
  position: absolute; right: var(--gutter); bottom: 6vh;
  font-family: var(--f-display); font-weight: 200;
  font-size: clamp(3rem, 8vw, 6rem); line-height: 1;
  /* .38 y no .2: a .2 el contador daba 1,71:1 y es el único texto que se lee
     durante la carga. A .38 llega a 3,3:1, que es lo que pide WCAG para
     texto grande, y sigue siendo un número discreto en la esquina. */
  color: rgb(var(--fg-rgb) / .38);
  font-variant-numeric: tabular-nums;
}
.loader.is-done { pointer-events: none; display: none; }
/* Escalera de seguridad: nunca se queda en negro. El loader del home se
   funde con GSAP (main.js) en el go, que llega como tarde a los 4,4 s; si
   main.js no llega, el script del <head> hace el go a los 5,5 s. Y esto,
   por si el hilo principal está tan ocupado que ningún temporizador corre
   (un móvil lento evaluando three.min.js): un fundido de opacidad desde
   los 4,8 s, que el compositor anima sin el hilo principal. Sin 'from':
   parte de la opacidad que tenga (la de GSAP si el go ya empezó), así que
   solo puede acelerar un fundido en marcha, nunca volver a oscurecer. En
   una carga normal el loader ya es display: none mucho antes. */
@keyframes loader-safety { to { opacity: 0; visibility: hidden; } }
.loader { animation: loader-safety .9s var(--ease-ui) 4.8s forwards; }
html.no-js .loader { display: none; }
@media (prefers-reduced-motion: reduce) { .loader { display: none; } }

/* ---------- Header ---------- */
.header {
  position: fixed; inset-inline: 0; top: 0; z-index: 100;
  transition: transform .6s var(--ease-enter);
}
.header.is-hidden { transform: translateY(-110%); transition: transform .6s var(--ease-exit); }
/* Teclado: si el foco entra en la cabecera escondida (Tab que vuelve al
   principio, Mayús+Tab), la cabecera baja; si no, el foco quedaba fuera de pantalla. */
.header.is-hidden:focus-within { transform: none; transition: transform .6s var(--ease-enter); }

/* Fondo glass (calcado de erretres): transparente arriba del todo; al
   reaparecer haciendo scroll, tinte translúcido + blur(20px). SIN borde
   inferior, igual que erretres: el borde era una de las dos fuentes de la
   "línea blanca". El blur va en un ::before que sangra 6px por arriba y por
   abajo, porque backdrop-filter pegado exactamente al borde del elemento
   genera un artefacto brillante en Chrome/Safari al recomponer capas
   durante el scroll; la mask desvanece el corte para que no quede una
   línea dura. El tinte NO lleva transition a propósito: si la lleva, al
   cambiar de sección el tinte viejo se queda visible mientras hace el
   fade y se ve como una banda clara sobre fondo oscuro. */
/* Corte inferior DURO, como erretres (su .navbar es blur(20px) sin máscara
   ni degradado). Ellos pueden ponerlo directo porque su header es `sticky`;
   el nuestro es `fixed` para poder ocultarse al bajar, y ahí sí aparece el
   artefacto de borde brillante en el tope. Por eso el blur sigue viviendo
   en un ::before que sangra 6px POR ARRIBA (fuera del viewport, invisible):
   evita el artefacto sin ensuciar el borde de abajo. Sin mask-image: el
   degradado que había aquí es justo lo que se quería quitar. */
.header--blur::before {
  content: ''; position: absolute; inset: -6px 0 0 0; z-index: -1;
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

/* Proporciones de erretres: alto 70px, nav de 16px/400 en bloques con
   padding 9px 18px y radio 4px, hover = fondo translúcido (no subrayado). */
.header__inner {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  min-height: 70px; padding: 0 var(--gutter);
}
.header__logo { display: flex; align-items: center; gap: 10px; }
.header__logo img { height: 25px; width: auto; }
.header__nav { display: flex; align-items: center; gap: 12px; }
.header__link {
  display: flex; align-items: center;
  padding: 9px 18px; border-radius: 4px;
  font-size: 1rem; font-weight: 400; line-height: 1;
  color: var(--text-on-ink);
  background: transparent;
  transition: background-color .2s var(--ease-ui), color .2s var(--ease-ui);
}
.header__link:hover { background: var(--tint-hover); }
/* "page" = esta es la página del enlace; "true" = estás dentro de su sección
   (una página hija de Soluciones: Programas, Shop, Prisma 360, Contenido &
   Redes, Brand Fit). Las dos se ven igual: el lector de pantalla las distingue. */
.header__link[aria-current="page"], .header__link[aria-current="true"] { color: var(--orange); }

/* Ítems con submenú (hoy solo Nosotros; Soluciones es un enlace directo
   desde el 2026-10-02 y sus opciones viven en la propia página). El título
   NO navega: es el botón que abre el panel (antes era un enlace + una flecha
   aparte, y hacer clic en el título te sacaba a una página distinta de la
   única opción del panel). El panel abre con el cursor, con el foco o
   pulsando el título, y su primera opción es la página del propio título
   ("Sobre Prisma"). */
.header__item { position: relative; display: flex; align-items: center; }
.header__item::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 14px; } /* puente para no perder el hover en el hueco */
.header__link--menu { gap: 7px; }
.header__link--menu svg { width: 11px; height: 11px; flex: 0 0 auto; transition: transform .22s var(--ease-snap); }
.header__item:hover .header__link--menu svg,
.header__item.is-open .header__link--menu svg,
.header__item:focus-within .header__link--menu svg { transform: rotate(180deg); }
.header__item.is-active > .header__link { color: var(--orange); }
.header__menu {
  position: absolute; top: calc(100% + 10px); left: 50%; z-index: 5;
  min-width: 210px; padding: 6px;
  background: var(--glass-panel); border: 1px solid var(--line-on-ink); border-radius: 14px;
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: var(--shadow-panel);
  opacity: 0; visibility: hidden; transform: translate(-50%, -6px);
  transition: opacity .2s var(--ease-ui), transform .22s var(--ease-exit), visibility 0s .22s;
}
.header__item:hover .header__menu, .header__item:focus-within .header__menu, .header__item.is-open .header__menu {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
  transition: opacity .2s var(--ease-ui), transform .24s var(--ease-enter), visibility 0s;
}
.header__menu a {
  display: block; padding: 10px 14px; border-radius: 9px; white-space: nowrap;
  font-size: .95rem; line-height: 1; color: var(--text-on-ink-2);
  transition: color .2s var(--ease-ui), background-color .2s var(--ease-ui);
}
.header__menu a:hover { color: var(--text-on-ink); background: var(--tint-soft); }
/* El foco NO se marca solo con un cambio de fondo al 8 %: es casi invisible
   y era la única regla del sitio que anulaba el anillo naranja global
   (WCAG 2.4.7). Se conserva el resalte y se devuelve el anillo, metido hacia
   dentro para que no se salga del panel. */
.header__menu a:focus-visible { color: var(--text-on-ink); background: var(--tint-soft); outline: 2px solid var(--orange); outline-offset: -2px; }
.header__menu a[aria-current="page"], .header__menu a[aria-current="true"] { color: var(--orange); }
.header__item.is-suppressed .header__menu { opacity: 0; visibility: hidden; transform: translate(-50%, -6px); transition: opacity .2s var(--ease-ui), transform .22s var(--ease-exit), visibility 0s .22s; }
.header__item.is-suppressed .header__link--menu svg { transform: none; }

.header .header__logo .logo-color { display: none; }
.header .header__logo .logo-white { display: block; }

/* ---------- Botones ---------- */
/* Lenguaje de botón calcado de erretres: plano, radio 4px, alto 44px,
   16px/500, y hover que invierte relleno -> contorno (en vez de oscurecerse).
   El hover quita el relleno naranja, así el color pesa menos en pantalla.
   El texto sobre naranja va en --ink y NUNCA en blanco: blanco sobre
   var(--orange) da 3.48 y no llega a AA; con --ink da 5.69. */
.btn {
  position: relative; display: inline-flex; align-items: center; gap: 9px;
  padding: 0 24px; height: 44px; border-radius: 4px;
  font-family: var(--f-text); font-weight: 500; font-size: 1rem; line-height: 1;
  border: 1px solid transparent;
  transition: color .2s var(--ease-ui), border-color .2s var(--ease-ui), background-color .2s var(--ease-ui), transform .16s var(--ease-snap);
}
.btn:active { transform: scale(.97); }
.btn__arrow { transition: transform .24s var(--ease-snap); }
.btn:hover .btn__arrow { transform: translateX(4px); }
.btn--primary { background: var(--orange); color: var(--ink); }
.btn--primary:hover { background: transparent; border-color: var(--orange); color: var(--orange); }
.btn--ghost { border-color: var(--line-on-ink); color: var(--text-on-ink); }
.btn--ghost:hover { background: var(--orange); border-color: var(--orange); color: var(--ink); }
.s-paper .btn--ghost, .btn--ghost.on-paper { border-color: var(--line-on-paper); color: var(--text-on-paper); }
.s-paper .btn--ghost:hover { background: var(--orange); border-color: var(--orange); color: var(--ink); }
.btn--big { padding: 0 30px; height: 52px; font-size: 1.02rem; }

/* ---------- Kicker / labels ---------- */
/* Sin la barrita decorativa delante: leía como un em dash. */
.kicker {
  display: inline-flex; align-items: center;
  font-size: .85rem; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--orange);
}
/* Migas como kicker (2026-10-02): en las hijas de Soluciones el kicker de la
   portada es la ruta "Soluciones / Página", con la página actual en naranja.
   Mismo cuerpo que .kicker; el enlace devuelve al hub, que el menú ya no
   despliega. El Shop lo pasa a tinta sobre su hoja blanca (css/shop.css). */
.crumbs {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: .85rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
}
.crumbs a { color: var(--text-on-ink-2); padding-block: 6px; transition: color .2s var(--ease-ui); }
.crumbs a:hover { color: var(--text-on-ink); }
.crumbs a:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; border-radius: 2px; }
.crumbs > span[aria-hidden] { color: rgb(var(--fg-rgb) / .3); }
.crumbs [aria-current] { color: var(--orange); }

/* ---------- Split text (JS llena .line > .line-inner) ----------
   El estado oculto SOLO se aplica cuando el JS confirma que va a animar
   (html.anim). Si el JS falla o no carga, el contenido se ve igual. */
.split-lines .line { display: block; overflow: hidden; padding-bottom: .09em; margin-bottom: -.09em; }
.split-lines em { font-style: normal; color: var(--orange); }
.split-lines .line-inner { display: block; }
html.anim .split-lines .line-inner { transform: translateY(112%); will-change: transform; }

html.anim [data-reveal] { opacity: 0; transform: translateY(40px); will-change: transform, opacity; }
/* La diagonal de la ola de logos continúa en Números (main.js anima x e y) */
html.anim [data-reveal="diag"] { transform: translate(28px, 28px); }
html.anim [data-hero-fade] { opacity: 0; transform: translateY(30px); }

/* ---------- Hero home ---------- */
.hero {
  position: relative; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  overflow: clip;
}
/* El campo de líneas WebGL se DESVANECE por abajo. Sin esto, las líneas
   llegan enteras hasta el borde del hero y la siguiente sección oscura las
   corta en una raya recta: parecía un recorte, no un fondo. La máscara lo
   funde con lo que venga debajo, sea del color que sea. */
.hero__canvas {
  position: absolute; inset: 0;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 16%, #000 58%, transparent 97%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 16%, #000 58%, transparent 97%);
}
.hero__canvas canvas { width: 100%; height: 100%; display: block; }
.hero__fallback {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 90% at 85% 110%, rgb(var(--orange-rgb) / .55), transparent 60%),
    radial-gradient(90% 70% at 10% 100%, rgb(var(--tangerine-rgb) / .3), transparent 55%),
    var(--ink);
}
.hero__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgb(var(--ink-rgb) / .45) 0%, rgb(var(--ink-rgb) / 0) 35%, rgb(var(--ink-rgb) / .1) 70%, rgb(var(--ink-rgb) / .82) 100%);
}
/* width:100% es necesario: .container trae `margin-inline: auto` y, dentro
   de un flex column, los márgenes automáticos en el eje transversal anulan
   el stretch. El bloque quedaba ajustado al contenido y centrado, así que
   el titular no arrancaba en el gutter sino a mitad de pantalla. */
.hero__content { position: relative; z-index: 2; width: 100%; padding-bottom: clamp(48px, 9vh, 110px); }
.hero__title {
  font-size: var(--fs-hero);
  max-width: 16ch;
  color: var(--on-photo);
  text-align: left;
}
.hero__title em { font-style: normal; color: var(--orange); }
.hero__scroll {
  position: absolute; right: var(--gutter); bottom: 26px; z-index: 2;
  display: flex; align-items: center; gap: 10px;
  font-size: .8rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--text-on-ink-2);
}
.hero__scroll i {
  display: block; width: 1px; height: 44px;
  background: linear-gradient(var(--orange), transparent);
  animation: scrollHint 1.8s var(--ease-soft) infinite;
}
@keyframes scrollHint {
  0% { transform: scaleY(0); transform-origin: top; }
  45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* ---------- Hero interno (páginas) ---------- */
.page-hero {
  position: relative; overflow: clip;
  padding: var(--hero-top) 0 clamp(56px, 9vh, 120px);
}
.page-hero__bg {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(70% 60% at 100% 0%, rgb(var(--tangerine-rgb) / .16), transparent 60%),
    radial-gradient(60% 55% at 0% 15%, rgb(var(--orange-rgb) / .16), transparent 55%);
  -webkit-mask-image: linear-gradient(180deg, #000 60%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 60%, transparent 100%);
}
.page-hero--paper .page-hero__bg {
  background:
    linear-gradient(180deg, rgb(var(--orange-rgb) / .12), transparent 55%),
    radial-gradient(75% 60% at 90% 0%, rgb(var(--tangerine-rgb) / .2), transparent 60%);
}
.page-hero .kicker { margin-bottom: 22px; }
.page-hero__title { font-size: var(--fs-hero); max-width: 18ch; }
/* Sin partir en líneas (reducción de movimiento) el <em> también va naranja
   y recto, como en .split-lines em */
.page-hero__title em { font-style: normal; color: var(--orange); }
.page-hero__lead { max-width: 58ch; margin-top: 26px; font-size: var(--fs-lead); }

/* Número gigante decorativo (recortado) */
.giant-num {
  position: absolute; z-index: 0; pointer-events: none; user-select: none;
  font-family: var(--f-display); font-weight: 200; line-height: .8;
  font-size: clamp(10rem, 26vw, 22rem);
  color: transparent; -webkit-text-stroke: 1px rgb(var(--orange-rgb) / .32);
}

/* ---------- Bloques de sección genéricos ---------- */
/* Ritmo vertical: --sect es el HUECO que queremos ver entre dos secciones,
   no el padding de cada una. Como las secciones se apilan, cada una pone la
   mitad arriba y la mitad abajo; así dos seguidas suman exactamente --sect
   en vez de el doble. Antes cada sección ponía --sect completo por lado y
   los huecos salían de 252px a 400px según qué vecina le tocara. */
.section { padding-block: calc(var(--sect) / 2); position: relative; }

/* Excepciones al ritmo: estas dos secciones terminan en contenido a sangre
   (los paneles pegajosos de servicios y los slides fijados del showcase).
   Ese contenido ya trae su propio aire y debe pegarse a la sección
   siguiente, así que no lleva el medio --sect de abajo. */
#servicios > .section { padding-bottom: 0; }
#proyectos { padding-bottom: 0; }
.section__head { display: grid; grid-template-columns: 1fr; gap: 22px; margin-bottom: clamp(40px, 7vh, 80px); }
@media (min-width: 900px) {
  .section__head { grid-template-columns: 1.4fr 1fr; align-items: end; gap: 60px; }
  .section__head > p { max-width: 44ch; justify-self: end; }
}
.section__title { font-size: var(--fs-h2); max-width: 18ch; }

/* ---------- Manifiesto (texto que se enciende palabra a palabra) ---------- */
/* :not(.kicker) porque el kicker también es un <p> dentro de .manifesto y
   esta regla le ganaba en especificidad: salía al doble de tamaño que los
   kickers del resto del sitio. */
/* Este párrafo es AHORA el titular de la sección: el bloque llevaba antes
   un h2 ("Creemos que todo lo que nos rodea...") encima, y quedaban dos
   textos grandes compitiendo. Se quitó el h2, así que el texto que se
   anima palabra a palabra es el único y va en tamaño de titular. */
.manifesto p:not(.kicker) {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  line-height: 1.2; letter-spacing: -0.015em;
  max-width: 28ch;
}
/* Palabra apagada (todavía sin animar) y palabra encendida. El apagado va
   en claro muy tenue: antes era un gris casi negro pensado para el fondo
   claro que tenía esta sección, y al pasar el sitio a oscuro el texto
   quedaba invisible hasta que se animaba. */
.manifesto .w { color: rgb(var(--fg-rgb) / .2); transition: color .3s linear; }
.manifesto .w.is-on { color: inherit; }

/* ---------- Home: el globo se hunde en el negro del manifiesto ----------
   .home-flow sube por encima del globo pegado (z 1, sin fondo propio: cada
   sección trae el suyo). El manifiesto ocupa una pantalla y sus primeros
   30 vh son una marea de tinta: entre el globo que se apaga y el negro que
   sube no hay borde. Las palabras se encienden con el blanco cálido del
   núcleo de los marcadores (un destello, no un gris con temperatura). */
.home-flow { position: relative; z-index: 1; }
.s-ink.manifesto-sec {
  min-height: 100vh; min-height: 100svh;
  display: grid; align-items: center;
  background: linear-gradient(to bottom, rgb(var(--ink-rgb) / 0) 0, var(--ink) 30vh);
}
@keyframes w-lit { from { color: rgb(255 227 214); } }
.manifesto-sec .w.is-on { animation: w-lit .6s var(--ease-ui); }
/* Centrado (pedido del cliente, 2026-09-27): sale del globo, que también va
   centrado, y así las dos piezas quedan sobre el mismo eje. */
.manifesto-sec .manifesto { text-align: center; }
.manifesto-sec .manifesto p:not(.kicker) { margin-inline: auto; text-wrap: balance; }
#numeros { padding-top: calc(var(--sect) / 4); }

/* ---------- Video Prisma Awards (home, entre el manifiesto y el archivo) ----------
   Portada + botón de play; el video se pide recién al pulsar y suena (el
   clic es el gesto). Con el video andando, los controles nativos. */
.hv-sec { padding-top: 0; }
.hv {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--r); background: var(--ink-2);
}
.hv__video, .hv__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hv__poster { transition: opacity .5s var(--ease-ui), transform 1.2s var(--ease-soft); }
.hv__play {
  position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 14px;
  color: var(--text-on-ink); cursor: pointer;
  background: radial-gradient(60% 60% at 50% 50%, rgb(var(--ink-rgb) / .1), rgb(var(--ink-rgb) / .45));
  transition: opacity .35s var(--ease-ui);
}
.hv__icon {
  display: grid; place-items: center; width: clamp(64px, 7vw, 96px); aspect-ratio: 1; border-radius: 50%;
  background: var(--orange); color: var(--ink);
  transition: transform .3s var(--ease-snap);
}
.hv__icon svg { width: 40%; margin-left: 6%; }
.hv__lbl { font-size: .85rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; }
.hv__play:hover .hv__icon, .hv__play:focus-visible .hv__icon { transform: scale(1.08); }
.hv__play:active .hv__icon { transform: scale(.96); }
.hv__play:focus-visible { outline: 2px solid var(--orange); outline-offset: -4px; border-radius: var(--r); }
.hv:hover .hv__poster { transform: scale(1.02); }
.hv.is-playing .hv__poster, .hv.is-playing .hv__play { opacity: 0; pointer-events: none; }
/* En pantalla completa, el video entero sobre negro (sin el recorte del cover) */
.hv__video:fullscreen { object-fit: contain; background: #000; }
.hv__video:-webkit-full-screen { object-fit: contain; background: #000; }
@media (max-width: 640px) { .hv { border-radius: 14px; } }
@media (prefers-reduced-motion: reduce) { .hv__poster, .hv__icon { transition: none; } .hv:hover .hv__poster { transform: none; } }

/* ---------- Servicios (paneles apilados) ---------- */
.svc-stack { position: relative; }
.svc-panel {
  position: sticky; top: 0;
  min-height: 100svh;
  display: flex; align-items: center;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding-block: 80px;
}
/* Los cuatro paneles alternan entre dos tonos oscuros muy cercanos para
   que se note el cambio de panel sin que ninguno "grite". El 04 ya no es
   un banner naranja entero: el naranja vuelve como acento. */
.svc-panel--01 { background: var(--ink-2); color: var(--text-on-ink); }
.svc-panel--02 { background: var(--ink); color: var(--text-on-ink); }
.svc-panel--03 { background: var(--ink-2); color: var(--text-on-ink); }
.svc-panel--04 { background: var(--ink-3); color: var(--text-on-ink); }
.svc-panel--04 .svc-panel__num { color: var(--orange); opacity: 1; }
.svc-panel__grid {
  display: grid; gap: 40px; width: 100%;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 960px) { .svc-panel__grid { grid-template-columns: 1.1fr .9fr; gap: 80px; } }
.svc-panel__num {
  font-family: var(--f-display); font-weight: 200; font-size: clamp(3rem, 5.6vw, 5rem);
  line-height: 1; opacity: .35; margin-bottom: 14px;
}
.svc-panel__title { font-size: var(--fs-h2); margin-bottom: 18px; }
.svc-panel__desc { font-size: var(--fs-lead); max-width: 46ch; opacity: .85; }
.svc-panel__list { display: flex; flex-direction: column; }
.svc-panel__list li {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 18px 4px; font-weight: 500; font-size: 1.1rem;
  border-bottom: 1px solid currentColor;
  opacity: .9;
}
.svc-panel__list li::after { content: '→'; opacity: .5; transition: transform .35s var(--ease-snap), opacity .3s var(--ease-ui); }
.svc-panel__list li:hover::after { transform: translateX(6px); opacity: 1; }
.svc-panel .btn { margin-top: 34px; }
.svc-panel--04 .btn--primary { background: var(--orange); color: var(--ink); }
.svc-panel--04 .btn--primary:hover { background: transparent; border-color: var(--orange); color: var(--orange); }

/* ---------- Proyectos: fila-lista con imagen flotante (home) ---------- */
.works { position: relative; }
.works__list { border-top: 1px solid var(--line-on-ink); }
.work-row {
  position: relative; display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center; gap: clamp(14px, 3vw, 40px);
  padding: clamp(22px, 3.6vh, 38px) 0;
  border-bottom: 1px solid var(--line-on-ink);
  transition: padding .45s var(--ease-soft);
}
.work-row__idx {
  font-family: var(--f-display); font-weight: 200; font-size: .95rem;
  color: var(--text-on-ink-2); min-width: 2.4em;
}
.work-row__name {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.3rem, 2.2vw, 1.9rem); line-height: 1.05;
  transition: transform .45s var(--ease-snap), color .3s var(--ease-ui);
}
.work-row__tags { font-size: .95rem; color: var(--text-on-ink-2); text-align: right; }
.work-row__year { font-variant-numeric: tabular-nums; color: var(--text-on-ink-2); font-size: .95rem; }
.work-row:hover .work-row__name { transform: translateX(10px); color: var(--orange); }
/* imagen flotante que sigue el cursor (JS) */
.work-float {
  position: fixed; z-index: 60; top: 0; left: 0;
  width: min(340px, 30vw); aspect-ratio: 16/10;
  border-radius: 16px; overflow: hidden;
  pointer-events: none; opacity: 0; transform: scale(.9);
  box-shadow: 0 30px 60px rgb(var(--shadow-rgb) / .45);
}
.work-float img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; }
.work-float img.is-active { opacity: 1; }
@media (hover: none), (max-width: 760px) {
  .work-float { display: none; }
  .work-row { grid-template-columns: auto 1fr auto; }
  .work-row__tags { display: none; }
}

/* ---------- Grid de proyectos (página Proyectos) ----------
   Dos columnas de tarjetas grandes en desktop (una en móvil/tablet),
   imagen limpia por defecto, caption revelada al hover
   (siempre visible en táctil). */
.projects-grid {
  display: grid; gap: clamp(18px, 2.6vw, 30px);
  grid-template-columns: repeat(auto-fit, minmax(min(480px, 100%), 1fr));
}
.project-card {
  position: relative; display: block; border-radius: var(--r-lg); overflow: hidden;
  background: var(--ink-2); aspect-ratio: 4/3; isolation: isolate;
}
@media (max-width: 700px) { .project-card { aspect-ratio: 4/3; border-radius: var(--r); } }
.project-card img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform .9s var(--ease-soft);
}
.project-card:hover img { transform: scale(1.045); }
.project-card__veil {
  position: absolute; inset: 0; z-index: 1; opacity: 0;
  background: linear-gradient(180deg, rgb(var(--warm-rgb) / .12) 30%, rgb(var(--warm-rgb) / .85) 100%);
  transition: opacity .4s var(--ease-ui);
}
.project-card__info {
  position: absolute; z-index: 2; inset-inline: clamp(22px, 3vw, 40px); bottom: clamp(20px, 3vh, 32px);
  display: flex; align-items: flex-end; justify-content: space-between; gap: 14px;
  opacity: 0; transform: translateY(16px);
  transition: opacity .4s var(--ease-ui), transform .5s var(--ease-enter);
}
.project-card:hover .project-card__veil,
.project-card:focus-visible .project-card__veil { opacity: 1; }
.project-card:hover .project-card__info,
.project-card:focus-visible .project-card__info { opacity: 1; transform: none; }
.project-card__name { font-family: var(--f-display); font-weight: 500; font-size: clamp(1.4rem, 2.2vw, 2rem); color: var(--on-photo); line-height: 1.05; }
.project-card__meta { font-size: 1rem; color: rgb(var(--on-photo-rgb) / .78); margin-top: 8px; }
.project-card__year { font-size: 1rem; color: rgb(var(--on-photo-rgb) / .65); font-variant-numeric: tabular-nums; }
@media (hover: none) {
  .project-card__veil { opacity: 1; }
  .project-card__info { opacity: 1; transform: none; }
}

/* Filtros */
.filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: clamp(30px, 5vh, 56px); }
.filter {
  padding: 10px 22px; border-radius: 999px; font-weight: 500; font-size: .95rem;
  border: 1px solid var(--line-on-ink); color: var(--text-on-ink-2);
  transition: all .3s var(--ease-ui);
}
.filter:hover { border-color: var(--orange); color: var(--text-on-ink); }
.filter.is-active { background: var(--orange); border-color: var(--orange); color: var(--ink); }

/* ---------- Programas (Servicios, estilo índice tipo Collins) ---------- */
.programs { border-top: 1px solid var(--line-on-paper); }
.s-ink .programs { border-top-color: var(--line-on-ink); }
.program { border-bottom: 1px solid var(--line-on-paper); }
.s-ink .program { border-bottom-color: var(--line-on-ink); }
.program summary {
  list-style: none; cursor: pointer;
  display: grid; align-items: baseline; gap: 14px clamp(16px, 3vw, 44px);
  grid-template-columns: auto 1fr auto;
  padding-block: clamp(20px, 3.4vh, 34px);
}
.program summary::-webkit-details-marker { display: none; }
.program__num {
  font-family: var(--f-display); font-weight: 300; font-size: .95rem;
  letter-spacing: .08em; color: var(--orange); min-width: 3.2em;
}
.program__name {
  font-family: var(--f-display); font-weight: 500; line-height: 1.1;
  font-size: clamp(1.2rem, 1.9vw, 1.6rem); letter-spacing: -0.01em;
  transition: transform .45s var(--ease-snap), color .3s var(--ease-ui);
}
.program summary:hover .program__name { transform: translateX(10px); color: var(--orange); }
.program__plus {
  font-family: var(--f-display); font-weight: 300; font-size: 1.9rem; line-height: 1;
  color: var(--orange);
  transition: transform .45s var(--ease-snap);
}
.program[open] .program__plus { transform: rotate(45deg); }
.program__body {
  display: grid; gap: 26px clamp(24px, 4vw, 70px);
  padding: 4px 0 clamp(30px, 5vh, 50px) 0;
}
@media (min-width: 900px) {
  .program__body { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); padding-left: calc(3.2em + clamp(16px, 3vw, 44px)); }
}
.program__desc { font-size: var(--fs-lead); line-height: 1.5; max-width: 44ch; }
.program__inc h4 {
  font-family: var(--f-text); font-weight: 500; font-size: .82rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--orange);
  margin-bottom: 14px;
}
.program__inc ul { columns: 1; }
@media (min-width: 640px) { .program__inc ul { columns: 2; column-gap: 40px; } }
.program__inc li {
  break-inside: avoid; padding: 8px 0 8px 0; font-size: .98rem;
  border-bottom: 1px solid var(--line-on-paper); opacity: .85;
}
.s-ink .program__inc li { border-bottom-color: var(--line-on-ink); }
.program__body .btn { justify-self: start; align-self: start; }

/* ---------- Clientes marquee ---------- */
.marquee { overflow: clip; padding-block: clamp(30px, 5vh, 54px); }
.marquee__track { display: flex; gap: clamp(40px, 6vw, 90px); width: max-content; will-change: transform; }
.marquee__item { flex: 0 0 auto; display: flex; align-items: center; }
.marquee__item img { height: clamp(40px, 6vw, 64px); width: auto; opacity: .85; transition: opacity .3s var(--ease-ui), transform .4s var(--ease-snap); }
.marquee__item:hover img { opacity: 1; transform: scale(1.06); }

/* ---------- Números / stats ----------
   Jerarquía en tres pisos: cifra grande, etiqueta corta y una frase que
   explica de qué habla la cifra. Sin cajas ni rejilla de bordes: el aire
   y el peso tipográfico separan las columnas. La cifra va en claro (es lo
   dominante) y la etiqueta en naranja, para no repetir seis titulares
   naranjas seguidos. */
.stats {
  display: grid; gap: clamp(34px, 4.4vw, 60px) clamp(24px, 3.4vw, 56px);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: clamp(34px, 6vh, 64px);
}
@media (min-width: 640px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Ocho cifras desde el 2026-10-02: dos filas de cuatro (con tres quedaba
   una fila coja de dos) */
@media (min-width: 1000px) { .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.stat { max-width: 34ch; }
.stat__num {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(2.7rem, 5.2vw, 4.3rem); line-height: .95;
  letter-spacing: -0.035em; color: var(--text-on-ink);
  font-variant-numeric: tabular-nums;
}
.stat__label {
  margin-top: 14px; font-weight: 500; font-size: 1rem; line-height: 1.3;
  letter-spacing: -0.01em; color: var(--orange);
}
.stat__text { margin-top: 8px; font-size: .95rem; line-height: 1.55; color: var(--text-on-ink-2); }

/* ---------- Marquesina de logos (infinita, sin librería) ----------
   Dos listas idénticas, la segunda aria-hidden: al desplazar el conjunto
   -50% el bucle empalma sin salto. La máscara lateral evita el corte seco
   en los bordes. Se detiene al pasar el cursor y con reduced-motion. */
.logo-loop { position: relative; overflow: hidden; padding-block: clamp(18px, 3vh, 34px); }
.logo-loop::before, .logo-loop::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: clamp(48px, 10vw, 140px); z-index: 2; pointer-events: none;
}
.logo-loop::before { left: 0; background: linear-gradient(90deg, var(--ink), rgb(var(--ink-rgb) / 0)); }
.logo-loop::after { right: 0; background: linear-gradient(270deg, var(--ink), rgb(var(--ink-rgb) / 0)); }
.s-paper .logo-loop::before { background: linear-gradient(90deg, var(--paper), rgb(var(--ink-2-rgb) / 0)); }
.s-paper .logo-loop::after { background: linear-gradient(270deg, var(--paper), rgb(var(--ink-2-rgb) / 0)); }
.logo-loop__track { display: flex; width: max-content; animation: logoLoop 46s linear infinite; }
.logo-loop:hover .logo-loop__track { animation-play-state: paused; }
.logo-loop__list { display: flex; align-items: center; }
.logo-loop__list li { flex: 0 0 auto; margin-inline: clamp(22px, 3.4vw, 52px); }
.logo-loop__list img {
  height: clamp(38px, 4.6vw, 60px); width: auto; opacity: .7;
  transition: opacity .3s var(--ease-ui);
}
.logo-loop__list li:hover img { opacity: 1; }
/* Tecnologías y plataformas (nosotros.html, about.tech): icono monocromo +
   nombre en Manrope; los logotipos completos (wordmark) van solos y lo que
   no tiene icono bonito en blanco, solo con el nombre. Se apaga y enciende
   el ítem entero, no solo la imagen. */
.logo-loop--tech .logo-loop__list li { margin-inline: clamp(18px, 2.6vw, 40px); }
.tech { display: inline-flex; align-items: center; gap: .6em; color: var(--text-on-ink); opacity: .66; transition: opacity .3s var(--ease-ui); }
.tech:hover { opacity: 1; }
.logo-loop--tech .logo-loop__list img { height: clamp(22px, 2.1vw, 28px); width: auto; opacity: 1; }
.logo-loop--tech .tech--wordmark img { height: clamp(24px, 2.4vw, 32px); }
/* Dezik: su logotipo es todo mayúsculas gruesas y a la altura de los demás
   se veía el doble de grande (cliente, 2026-10-08): más bajo, al alto de
   las letras de los nombres. */
.logo-loop--tech .tech--wordmark img[src*="dezik-labs"] { height: clamp(15px, 1.35vw, 19px); }
.logo-loop--tech .tech--wordmark img[src*="payphone"] { height: clamp(18px, 1.7vw, 23px); }
.tech span { font-family: var(--f-text); font-weight: 500; font-size: clamp(1rem, 1.3vw, 1.2rem); letter-spacing: -0.01em; line-height: 1; white-space: nowrap; }
.tech--text span { font-size: clamp(1.05rem, 1.4vw, 1.28rem); letter-spacing: -0.02em; }
@keyframes logoLoop { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-50%, 0, 0); } }
@media (prefers-reduced-motion: reduce) { .logo-loop__track { animation: none; } }

/* ---------- Línea de tiempo (Nosotros) ----------
   La barra vertical se rellena con el scroll (--tl-progress lo escribe
   main.js con IntersectionObserver + scroll, no ScrollTrigger: esta página
   tiene secciones pineadas que descuadran las medidas). */
.timeline { position: relative; margin-top: clamp(40px, 7vh, 78px); }
.timeline__rail { position: absolute; left: 7px; top: 6px; bottom: 6px; width: 1px; background: var(--line-on-ink); }
.timeline__rail i { display: block; width: 100%; height: 100%; background: var(--orange); transform-origin: top; transform: scaleY(var(--tl-progress, 0)); transition: transform .18s linear; }
.timeline__item {
  position: relative; padding: 0 0 clamp(34px, 5.4vh, 60px) clamp(34px, 4.4vw, 62px);
  display: grid; gap: 6px;
}
.timeline__item:last-child { padding-bottom: 0; }
.timeline__dot {
  position: absolute; left: 0; top: 6px; width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid var(--line-on-ink); background: var(--ink);
  transition: background-color .4s var(--ease-ui), border-color .4s var(--ease-ui), transform .4s var(--ease-snap);
}
.s-paper .timeline__dot { background: var(--paper); }
.timeline__item.is-on .timeline__dot { background: var(--orange); border-color: var(--orange); transform: scale(1.12); }
.timeline__year {
  font-family: var(--f-display); font-weight: 200; font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1; color: var(--orange); font-variant-numeric: tabular-nums;
}
.timeline__name { font-size: var(--fs-h3); }
.timeline__text { color: var(--text-on-ink-2); max-width: 52ch; }
.s-paper .timeline__text { color: var(--text-on-paper-2); }
@media (min-width: 900px) {
  .timeline__item { grid-template-columns: minmax(120px, .3fr) 1fr; column-gap: clamp(24px, 3vw, 54px); align-items: start; }
  .timeline__year { grid-row: span 2; }
  .timeline__name, .timeline__text { grid-column: 2; }
}

/* ---------- Equipo y partners (tarjetas tipo retrato) ---------- */
.people { display: grid; gap: clamp(18px, 2.2vw, 30px); grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: clamp(34px, 6vh, 64px); }
@media (min-width: 760px) { .people { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1180px) { .people { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.person { display: block; color: inherit; }
.person__shot {
  position: relative; overflow: hidden; border-radius: var(--r);
  aspect-ratio: 3 / 4; background: var(--ink-3);
}
.s-paper .person__shot { background: var(--paper-2); }
.person__shot img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease-enter), filter .45s var(--ease-ui); }
/* Fotos del equipo y de los expertos en blanco y negro (2026-10-08, pedido
   del cliente): vienen de sitios muy distintos y así se leen como una sola
   serie. El original se guarda en color; si un día se quieren a color,
   basta con quitar esta línea. */
.person__shot img { filter: grayscale(1) contrast(1.05); }
.person__shot--empty { display: grid; place-items: center; }
/* Retrato abstracto (js/prism-portrait.js) para quien no tiene foto: un
   prisma que abre la luz en la paleta de la marca, distinto para cada
   nombre. Es una pieza, no un hueco: lleva el mismo marco que una foto. */
.person__shot--art { outline: 1px solid rgb(var(--fg-rgb) / .07); outline-offset: -1px; }
.person__shot--art svg { display: block; width: 100%; height: 100%; transition: transform .9s var(--ease-enter); }
a.person:hover .person__shot--art svg { transform: scale(1.035); }
/* Especialistas: el mismo retrato volteado 180° (la luz cae desde arriba)
   para que se lean como un grupo distinto del equipo. Solo el dibujo: una
   foto subida desde el panel se ve derecha. */
.people--flip .person__shot--art svg { transform: rotate(180deg); }
.people--flip a.person:hover .person__shot--art svg { transform: rotate(180deg) scale(1.035); }
.person__initial { font-family: var(--f-display); font-weight: 200; font-size: clamp(2.4rem, 5vw, 3.6rem); color: var(--text-on-ink-2); }
a.person:hover .person__shot img { transform: scale(1.045); }
.person__name { margin-top: 14px; font-weight: 500; font-size: 1.05rem; line-height: 1.25; letter-spacing: -0.01em; transition: color .25s var(--ease-ui); }
a.person:hover .person__name { color: var(--orange); }
.person__role { margin-top: 3px; font-size: .92rem; color: var(--text-on-ink-2); }
.s-paper .person__role { color: var(--text-on-paper-2); }
.person__go { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; font-size: .86rem; color: var(--orange); }

/* ---------- Proceso 01–04 ---------- */
.process { position: relative; }
.process__rail { display: grid; gap: 1px; background: var(--line-on-paper); border-block: 1px solid var(--line-on-paper); }
@media (min-width: 900px) { .process__rail { grid-template-columns: repeat(4, 1fr); } }
.process__step { background: var(--paper); padding: clamp(28px, 4vh, 48px) clamp(20px, 2.4vw, 40px); }
/* Nosotros va entera sobre tinta (2026-10-01): las etapas toman el mismo
   negro que la sección y los filetes del riel siguen separándolas. */
.s-ink .process__step { background: var(--ink); }
.process__num {
  font-family: var(--f-display); font-weight: 200;
  font-size: clamp(2.8rem, 4.6vw, 4rem); line-height: 1; color: var(--orange);
}
.process__name { font-size: 1.35rem; margin: 14px 0 10px; }
.process__desc { color: var(--text-on-paper-2); font-size: .98rem; }

/* ---------- Bento (detalle proyecto / nosotros) ---------- */
.bento { display: grid; gap: clamp(12px, 1.6vw, 18px); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 900px) { .bento { grid-template-columns: repeat(3, 1fr); } }
.bento__cell { border-radius: var(--r); overflow: hidden; background: var(--ink-2); }
.bento__cell img { width: 100%; height: 100%; object-fit: cover; }
.bento__cell--tall { grid-row: span 2; }
.bento__cell--wide { grid-column: span 2; }

/* ---------- Detalle de proyecto ---------- */
.case-hero { padding: calc(90px + 10vh) 0 clamp(40px, 7vh, 90px); position: relative; overflow: clip; }
.case-hero__title { font-size: var(--fs-hero); }
.case-hero__meta {
  display: grid; gap: 26px; margin-top: clamp(34px, 6vh, 60px);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 900px) { .case-hero__meta { grid-template-columns: repeat(4, 1fr); } }
.case-hero__meta dt { font-size: .82rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text-on-ink-2); margin-bottom: 6px; }
.case-hero__meta dd { font-weight: 500; line-height: 1.3; }
.case-hero__tagline {
  font-size: clamp(1.12rem, 1.9vw, 1.55rem); line-height: 1.4;
  max-width: 44ch; margin-top: 20px; color: var(--text-on-ink);
}
.case-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 26px; }
.case-tag {
  padding: 7px 16px; border-radius: 999px;
  border: 1px solid var(--line-on-ink);
  font-size: .85rem; color: var(--text-on-ink-2);
}
.case-cover { border-radius: var(--r-lg); overflow: hidden; }
/* height:auto es obligatorio: la ficha pone width/height en el <img> para
   reservar sitio (CLS), y el atributo height se comporta como un alto fijo
   en CSS. Sin esto, la portada salía a 1296×1159 en escritorio y 335×1159
   en móvil: estirada un 35 % y un 83 %. */
.case-cover img { width: 100%; height: auto; }

/* Galería: el JS marca .is-wide según la proporción real de cada foto */
.case-gallery {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(10px, 1.4vw, 16px);
}
.case-gallery figure {
  margin: 0; border-radius: var(--r); overflow: hidden;
  background: var(--ink-2); aspect-ratio: 4/3;
}
.case-gallery figure.is-wide { grid-column: 1 / -1; aspect-ratio: 16/9; }
.case-gallery figure.is-tall { aspect-ratio: 3/4; }
.case-gallery figure.is-square { aspect-ratio: 1/1; }
.case-gallery img { width: 100%; height: 100%; object-fit: cover; }

/* Datos duros del proyecto (referencia: fichas de erretres). Número
   enorme con el color de acento del caso y etiqueta pequeña debajo.
   Vive en la apertura, debajo de Cliente/Industria: se alinea con esa
   rejilla en vez de repartirse por todo el ancho, para que se lea como
   parte de la misma composición y no como una sección aparte. */
.case-facts {
  display: grid; gap: clamp(32px, 5vw, 64px);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-block: clamp(40px, 7vh, 84px);
}
/* Alineación según cuántos datos haya. Con 1 o 2 se alinean con la columna
   del texto (no bajo la etiqueta "El desafío"); con 3 ocupan el ancho
   completo. El desplazamiento reproduce la primera columna de .case-block,
   que es `1fr 1.6fr` con 70px de gap: 1fr = (100% - 70px) / 2.6. */
@media (min-width: 900px) {
  .case-facts--1, .case-facts--2 { padding-left: calc((100% - 70px) / 2.6 + 70px); }
  .case-facts--1 { grid-template-columns: minmax(200px, max-content); }
  .case-facts--2 { grid-template-columns: repeat(2, 1fr); }
  .case-facts--3 { grid-template-columns: repeat(3, 1fr); }
}
.case-facts__value {
  display: block;
  font-family: var(--f-display); font-weight: 300;
  font-size: clamp(3.2rem, 7vw, 5.5rem); line-height: 1;
  letter-spacing: -0.03em;
  color: var(--text-on-ink);
}
.case-facts__label {
  display: block; margin-top: 14px;
  font-size: .95rem; line-height: 1.4;
  color: var(--text-on-ink-2); max-width: 22ch;
}
@media (max-width: 700px) {
  .case-gallery { grid-template-columns: 1fr; }
  .case-gallery figure, .case-gallery figure.is-wide, .case-gallery figure.is-tall { grid-column: auto; aspect-ratio: 4/3; }
}

/* Cita destacada del cliente */
.case-quote { max-width: min(90%, 720px); margin-inline: auto; text-align: center; }
.case-quote blockquote {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.3rem, 2.25vw, 2rem); line-height: 1.25;
  letter-spacing: -0.01em; max-width: 24ch; margin-inline: auto;
}
.case-quote blockquote::before { content: '“'; color: var(--orange); }
.case-quote blockquote::after { content: '”'; color: var(--orange); }
.case-quote figcaption {
  margin-top: 22px; font-size: .92rem; color: var(--text-on-ink-2);
  font-family: var(--f-text);
}

/* Créditos */
.case-credits {
  display: grid; gap: 20px 40px; padding-top: clamp(30px, 5vh, 50px);
  border-top: 1px solid var(--line-on-ink);
}
@media (min-width: 760px) { .case-credits { grid-template-columns: 220px 1fr; } }
.case-credits h2 {
  font-family: var(--f-text); font-weight: 500; font-size: .82rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--text-on-ink-2);
}
.case-credits p { color: var(--text-on-ink); max-width: 60ch; }
/* Créditos por persona (projects.json → creditsList): rol arriba, nombre
   debajo, en columnas separadas por un filete; la línea de texto de
   siempre (credits) queda debajo como nota. */
.case-credits__body { display: grid; gap: clamp(22px, 3vh, 32px); }
.case-credits__list { display: grid; gap: clamp(18px, 2.4vh, 26px) clamp(24px, 3vw, 48px); grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); margin: 0; }
.case-credits__item { display: grid; gap: 6px; align-content: start; padding-top: 14px; border-top: 1px solid var(--line-on-ink); }
.case-credits__role { font-size: .9rem; line-height: 1.4; color: var(--text-on-ink-2); }
.case-credits__item dd { margin: 0; }
.case-credits__name { font-size: 1.08rem; font-weight: 500; line-height: 1.3; letter-spacing: -0.01em; color: var(--text-on-ink); }
a.case-credits__name { transition: color .25s var(--ease-ui); }
a.case-credits__name:hover, a.case-credits__name:focus-visible { color: var(--orange); }
.case-credits p.case-credits__note { font-size: .95rem; color: var(--text-on-ink-2); }
.case-body { display: grid; gap: clamp(40px, 8vh, 90px); }

/* Página de proyecto por bloques (projects.json → blocks, panel → Página).
   Fila: cada foto crece en proporción a su ancho/alto, así todas quedan a
   la misma altura sin recortarse. "Pantalla completa" sale del contenedor
   hasta el borde; la sección recorta el sobrante de la barra de scroll. */
.case-section { overflow-x: clip; }
.case-block__text { display: grid; gap: 1em; }
@media (min-width: 900px) { .case-block--solo .case-block__text { grid-column: 2; } }
.pb-img { margin: 0; }
.pb-img img, .pb-row__item img { display: block; width: 100%; height: auto; background: var(--ink-2); }
.pb-img--full img, .pb-img--medium img, .pb-row__item img { border-radius: var(--r); }
.pb-img--medium { width: min(100%, 880px); margin-inline: auto; }
.pb-img--bleed { width: 100vw; margin-inline: calc(50% - 50vw); }
.pb-row { display: flex; align-items: flex-start; gap: clamp(10px, 1.4vw, 16px); }
.pb-row__item { margin: 0; flex: 1 1 0; min-width: 0; }
@media (max-width: 700px) {
  .pb-row { flex-direction: column; }
  .pb-row__item { flex: none !important; width: 100%; }
}
.case-block { display: grid; gap: 20px; }
@media (min-width: 900px) {
  .case-block { grid-template-columns: 1fr 1.6fr; gap: 70px; }
}
.case-block h2 { font-size: var(--fs-h3); color: var(--text-on-ink); }
.case-block p { font-size: var(--fs-lead); line-height: 1.55; max-width: 58ch; }
.case-next { display: block; padding-block: var(--sect); text-align: left; }
.case-next__label { color: var(--text-on-ink-2); margin-bottom: 14px; }
.case-next__name {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.7rem, 3vw, 2.6rem); line-height: 1.05;
  transition: color .35s var(--ease-ui), transform .55s var(--ease-snap);
}
.case-next:hover .case-next__name { color: var(--orange); transform: translateX(14px); }

/* ---------- CTA final ----------
   El resplandor naranja YA NO es el fondo de esta sección. Antes lo era, y
   se cortaba en seco justo donde empezaba el footer: se veía como una
   banda pegada al banner. Ahora nace en el footer y sube hasta aquí
   (.footer::before, más abajo), así que el degradado es el fondo del final
   de la página y no tiene ningún borde. Esta sección no lleva fondo
   propio. */
.cta {
  position: relative;
  background: transparent; color: var(--text-on-ink);
  padding-block: calc(var(--sect) / 2);
}
/* .cta__bg queda en el marcado por compatibilidad, pero ya no pinta nada:
   quitarlo de las 11 páginas no aportaba y el fondo es de la página. */
.cta__bg { display: none; }
.cta__title { position: relative; font-size: var(--fs-hero); max-width: 16ch; }
.cta__title em { font-style: normal; color: var(--orange); }
.cta__sub { position: relative; margin-top: 22px; font-size: var(--fs-lead); max-width: 46ch; color: var(--text-on-ink-2); }
.cta .btn { margin-top: 40px; position: relative; background: var(--orange); color: var(--ink); }
.cta .btn:hover { background: transparent; border-color: var(--orange); color: var(--orange); }

/* ---------- Footer (estructura calcada de rejouice.com) ----------
   Gutter deliberadamente MUY estrecho (no el --gutter del resto del
   sitio): que el wordmark gigante llegue casi al borde es la gracia del
   diseño original. Arriba, dos mitades: nav grande a la izquierda y
   metadatos pequeños a la derecha. Abajo, la fila de contacto y el
   wordmark a sangre. */
/* El footer no lleva fondo propio: lo pone su ::before, que además sangra
   hacia ARRIBA por encima del CTA para que el degradado sea continuo
   entre los dos. Por eso ya no puede recortar (`overflow: clip` se comía
   la sangría); el desbordamiento horizontal del wordmark lo sigue
   conteniendo el `overflow-x: clip` del body.

   z-index 6 nació para la portada Cosmos de la antigua prisma-360.html
   (--z-p360-content, 5), que ya no existe. Se mantiene: cualquier sección
   con z-index propio (el escenario fijo del hub, la hoja del Shop) taparía
   el resplandor si el pie volviera a z-index auto.
   Como el ::before va a z-index -1 DENTRO del contexto del footer, el
   texto del footer siempre queda por encima del degradado. */
.footer {
  position: relative; z-index: 6;
  background: transparent; color: var(--text-on-ink); overflow: visible;
  --footer-gutter: clamp(12px, 1.4vw, 20px);
  /* Sin relleno abajo: el hueco del glifo del wordmark (ver
     .footer__wordmark) ya deja el aire y lo deja DENTRO del footer. Con
     relleno aquí, ese hueco caía fuera y pintaba una franja negra de 19 px
     al final de la página. */
  padding: 15px 0 0;
}
.footer::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  left: 0; right: 0; bottom: 0;
  top: calc(-1 * clamp(340px, 58vh, 720px));   /* la sangría que cubre el CTA */
  background:
    radial-gradient(76% 58% at 84% 96%, rgb(var(--orange-rgb) / .20), transparent 68%),
    radial-gradient(62% 46% at 4% 62%, rgb(var(--orange-rgb) / .09), transparent 62%),
    linear-gradient(180deg, rgb(var(--orange-rgb) / 0) 0%, rgb(var(--orange-rgb) / .05) 55%, rgb(var(--tangerine-rgb) / .11) 100%);
  /* Rampa larga desde arriba: garantiza que el borde superior de la
     sangría nunca se lea como una línea sobre el CTA. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 62%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 62%);
}
.footer__outer { padding-inline: var(--footer-gutter); }

.footer__top {
  display: grid; grid-template-columns: 1fr; gap: 40px;
  padding-top: clamp(40px, 7vh, 76px);
}
@media (min-width: 860px) { .footer__top { grid-template-columns: 1fr 1fr; gap: 4px; } }

/* Dos columnas del mismo peso: el estudio (Inicio … Contacto) y Soluciones
   con sus cuatro caminos. Sin rótulos: la columna ya es el grupo y la
   primera línea de la segunda ("Soluciones") hace de cabecera. Las filas
   de las dos columnas caen en la misma línea base. En móvil se apilan. */
.footer__nav {
  display: grid; grid-template-columns: 1fr; align-content: start;
  row-gap: clamp(22px, 3.2vh, 30px);
}
@media (min-width: 520px) {
  .footer__nav { grid-template-columns: repeat(2, max-content); column-gap: clamp(48px, 7vw, 132px); }
}
.footer__navcol { display: flex; flex-direction: column; align-items: flex-start; }
.footer__nav a {
  font-size: clamp(1.35rem, 2vw, 1.75rem); font-weight: 300;
  letter-spacing: -0.015em; line-height: 1.25;
  color: var(--text-on-ink); transition: color .2s var(--ease-ui);
}
.footer__nav a:hover { color: var(--orange); }

.footer__aside {
  display: flex; flex-direction: column; gap: 24px;
  font-size: .875rem; letter-spacing: -0.01em; line-height: 1.25;
  color: var(--text-on-ink-2);
}
/* En escritorio, dos columnas (2026-10-08): redes y contacto a la izquierda,
   oficinas y la línea legal a la derecha. Apilados en una sola columna, los
   cuatro bloques eran lo que más alto le daba al footer. Las dos filas se
   reparten el alto de la navegación y la de abajo cae en su línea base. */
@media (min-width: 860px) {
  .footer__aside {
    display: grid; grid-template-columns: repeat(2, max-content);
    grid-template-rows: auto auto; grid-auto-flow: column;
    column-gap: clamp(32px, 5vw, 112px); row-gap: 24px;
    align-content: space-between;
  }
  .footer__business, .footer__legal { align-self: end; }
}
.footer__socials { display: flex; flex-direction: column; }
/* Estos enlaces medían 18 px de alto: por debajo del mínimo de 24 px que
   pide WCAG 2.5.8, y muy incómodos de acertar con el pulgar. El relleno
   vertical agranda el área tocable sin separar visualmente las líneas
   (el margen negativo compensa el espaciado que se gana). */
.footer__socials a, .footer__business a, .footer__offices a, .footer__legal a {
  color: var(--text-on-ink); transition: color .2s var(--ease-ui);
  padding-block: 5px; margin-block: -2px;
}
.footer__socials a:hover, .footer__business a:hover, .footer__legal a:hover { color: var(--orange); }
.footer__legal a { color: var(--text-on-ink-2); align-self: flex-start; }
.footer__business, .footer__legal { display: flex; flex-direction: column; gap: 2px; }
.footer__business { gap: 0; }

/* Oficinas: el país en claro y la dirección en gris, como el original. */
.footer__offices { display: flex; flex-direction: column; gap: 12px; }
.footer__offices div { display: flex; flex-direction: column; gap: 2px; }
.footer__offices span:first-child { color: var(--text-on-ink); }

.footer__bottom { margin-top: clamp(48px, 10vh, 120px); }

/* Wordmark a sangre: el tamaño en vw está calibrado para que "See it
   different" ocupe el ancho completo del footer menos el gutter. Si se
   cambia el texto o la separación entre letras, hay que recalibrar el vw:
   con -0.015em, 11.4vw deja el mismo ancho que antes daban -0.045em y
   12.1vw (medido a 1440: 1303 px de 1400 disponibles). */
.footer__wordmark {
  margin-top: clamp(18px, 3.5vh, 40px);
  font-family: var(--f-display); font-weight: 500;
  font-size: 11.4vw; line-height: .82;
  letter-spacing: -0.015em; text-transform: uppercase;
  white-space: nowrap; color: var(--text-on-ink); text-align: center;
  /* line-height .82 recorta la caja de línea por debajo de la caja del
     glifo: ~0,27em de la letra sobresalen del párrafo. Ese sobrante creaba
     alto de scroll por debajo del footer y se veía negro. El relleno lo mete
     dentro de la caja y, al ir en em, escala con el tamaño en vw. */
  padding-bottom: .28em;
}
/* Linterna blanca (main.js pone .is-spot solo con ratón y sin
   reduced-motion): el texto es transparente y se ve su fondo, un degradado
   radial blanco centrado en el cursor. Núcleo de ~1em totalmente blanco que
   se difumina hasta ~3,4em; fuera de la luz el wordmark queda tenue (.12).
   Proporciones sacadas de iventions.com: núcleo ~1,2 veces el alto de la
   letra y borde a ~4 veces. */
.footer__wordmark.is-spot {
  color: transparent;
  background-image: radial-gradient(circle at var(--mx, 50%) var(--my, 50%),
    rgb(255 255 255) 0,
    rgb(255 255 255) calc(var(--lit, 0) * 1em),
    rgb(var(--fg-rgb) / .12) calc(var(--lit, 0) * 3.4em + .01em));
  -webkit-background-clip: text; background-clip: text;
}

/* ---------- Formulario contacto ---------- */
.form { display: grid; gap: 26px; }
.form__row { display: grid; gap: 26px; }
@media (min-width: 760px) { .form__row { grid-template-columns: 1fr 1fr; } }
.field { display: grid; gap: 8px; }
.field label { font-size: .85rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-on-ink-2); font-weight: 500; }
.field input, .field textarea, .field select {
  font: inherit; color: var(--text-on-ink);
  background: transparent; border: 0;
  border-bottom: 1px solid var(--line-on-ink);
  padding: 12px 2px; border-radius: 0;
  transition: border-color .3s var(--ease-ui);
}
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-bottom-color: var(--orange); }
.field textarea { min-height: 120px; resize: vertical; }
.chips { display: flex; flex-wrap: wrap; gap: 10px; }
.chip { position: relative; }
.chip input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.chip span {
  display: inline-block; padding: 10px 22px; border-radius: 999px;
  border: 1px solid var(--line-on-ink); font-weight: 500; font-size: .95rem;
  color: var(--text-on-ink-2); transition: all .3s var(--ease-ui);
}
.chip input:checked + span { background: var(--orange); border-color: var(--orange); color: var(--ink); }
.chip input:focus-visible + span { outline: 2px solid var(--orange); outline-offset: 3px; }
.contact-direct a {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 20px 4px; border-bottom: 1px solid var(--line-on-ink);
  font-family: var(--f-display); font-weight: 500; font-size: clamp(1.1rem, 1.7vw, 1.4rem);
  transition: color .3s var(--ease-ui), padding-left .4s var(--ease-snap);
}
.contact-direct a:hover { color: var(--orange); padding-left: 12px; }
.contact-direct span { font-family: var(--f-text); font-weight: 400; font-size: .95rem; color: var(--text-on-ink-2); }

/* ---------- Menú móvil ---------- */
.burger { display: none; position: relative; z-index: 130; width: 44px; height: 44px; }
.burger i {
  position: absolute; left: 10px; right: 10px; height: 2px;
  background: currentColor; transition: transform .4s var(--ease-snap), opacity .3s var(--ease-ui);
}
.burger i:nth-child(1) { top: 16px; }
.burger i:nth-child(2) { top: 26px; }
.burger.is-open i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.burger.is-open i:nth-child(2) { transform: translateY(-5px) rotate(-45deg); }
.mobile-menu {
  position: fixed; inset: 0; z-index: 120;
  background: var(--ink); color: var(--text-on-ink);
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 var(--gutter);
  clip-path: inset(0 0 100% 0);
  visibility: hidden;
  transition: clip-path .7s var(--ease-exit), visibility 0s .7s;
}
.mobile-menu.is-open { clip-path: inset(0); visibility: visible; transition: clip-path .7s var(--ease-enter); }
/* Con el menú abierto el header (logo y hamburguesa en X) va por encima del
   menú: si no, la X quedaba tapada y el menú solo se cerraba eligiendo un
   enlace. Sin su fondo de cristal, que sobre la tinta del menú haría banda. */
html.menu-open .header { z-index: 130; transform: none; }
html.menu-open .header--blur::before { opacity: 0; }
.mobile-menu a {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.9rem, 7vw, 3rem); line-height: 1.22;
  color: var(--text-on-ink);
}
.mobile-menu a:hover, .mobile-menu a[aria-current="page"], .mobile-menu a[aria-current="true"] { color: var(--orange); }
/* El padre de un grupo ya no es un enlace: es el rótulo del grupo (igual
   que en escritorio, donde el título abre el panel en vez de navegar).
   Quien quiera la página del padre entra por "Sobre Prisma", que es el
   primer hijo. */
.mobile-menu__group {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.9rem, 7vw, 3rem); line-height: 1.22;
  color: var(--text-on-ink);
}
/* padding-block para llegar al mínimo de 24 px de área tocable (WCAG 2.5.8):
   con solo la altura de línea se quedaban en 23 px. Los márgenes negativos
   mantienen el ritmo vertical que tenía la lista. */
.mobile-menu a.mobile-menu__sub {
  font-size: clamp(1.2rem, 4.2vw, 1.7rem); font-weight: 400; color: var(--text-on-ink-2);
  padding-left: 1.2em; padding-block: 6px; margin-top: -.3em; margin-bottom: 0;
}
.mobile-menu a.mobile-menu__sub[aria-current="page"], .mobile-menu a.mobile-menu__sub[aria-current="true"] { color: var(--orange); }
.mobile-menu a.mobile-menu__sub + a.mobile-menu__sub { margin-top: -.45em; }
.mobile-menu__meta { margin-top: 8vh; color: var(--text-on-ink-2); font-size: .95rem; }
@media (max-width: 860px) {
  .header__nav { display: none; }
  .burger { display: block; }
}

/* ---------- Showcase: slides de proyecto apilados (home) ---------- */
.showcase { position: relative; }
.show-slide {
  position: relative; height: 100svh; width: 100%;
  display: flex; align-items: flex-end;
  overflow: clip; background: var(--ink-2);
}
.show-slide__bg { position: absolute; inset: -8% 0; }
.show-slide__bg img { width: 100%; height: 100%; object-fit: cover; }
.show-slide__veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgb(var(--warm-rgb) / .35) 0%, rgb(var(--warm-rgb) / 0) 35%, rgb(var(--warm-rgb) / .82) 100%);
}
.show-slide__tint { position: absolute; inset: 0; opacity: .18; mix-blend-mode: color; }
/* Home: la primera portada nace de la tinta en la que se hunde el archivo
   (y llega desde la profundidad: home.js le quita la escala al entrar), y
   la última se funde a tinta antes de la ola de logos. Solo la primera y
   la última: entre slides, foto que cubre foto es el lenguaje del showcase.
   Con clase y no con :first-child: el pin de ScrollTrigger mete cada slide
   pineado en su propio .pin-spacer, y ahí TODOS serían :first-child (y
   :last-child). La última no se pinea: sigue siendo hija directa. */
.home-flow .showcase > .show-slide:first-child .show-slide__veil,
.home-flow .show-slide.is-first .show-slide__veil {
  background: linear-gradient(180deg, var(--ink) 0%, rgb(var(--warm-rgb) / 0) 24%, rgb(var(--warm-rgb) / .82) 100%);
}
.home-flow .showcase > .show-slide:last-child:not(.is-first) .show-slide__veil {
  background: linear-gradient(180deg, rgb(var(--warm-rgb) / .35) 0%, rgb(var(--warm-rgb) / 0) 35%, rgb(var(--warm-rgb) / .82) 72%, var(--ink) 100%);
}
html.anim .home-flow .show-slide.is-first .show-slide__bg img { transform: scale(1.06); transition: transform 1.2s var(--ease-enter); }
html.anim .home-flow .show-slide.is-first.is-in .show-slide__bg img { transform: none; }
.show-slide__content {
  position: relative; z-index: 2; width: 100%;
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 20px 40px;
  justify-content: space-between;
  padding-bottom: clamp(34px, 7vh, 70px);
}
.show-slide__name {
  font-family: var(--f-display); font-weight: 500; color: var(--on-photo);
  font-size: clamp(1.6rem, 2.6vw, 2.3rem); line-height: 1.08; max-width: 16ch;
}
.show-slide__meta { color: rgb(var(--on-photo-rgb) / .8); margin-top: 12px; font-size: 1.02rem; }
.show-slide__idx {
  position: absolute; top: clamp(90px, 14vh, 140px); right: var(--gutter); z-index: 2;
  font-family: var(--f-display); font-weight: 200;
  font-size: clamp(2.4rem, 5vw, 4rem); line-height: 1; color: rgb(var(--on-photo-rgb) / .5);
}
.show-slide__go {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 30px; border-radius: 999px;
  background: rgb(var(--on-photo-rgb) / .12); color: var(--on-photo); font-weight: 500;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  transition: background .35s var(--ease-ui), color .35s var(--ease-ui), transform .35s var(--ease-snap);
}
.show-slide__go:hover { background: var(--on-photo); color: var(--ink); transform: translateY(-3px); }

/* ---------- Clientes: ola de logos (desktop) / grid (móvil) ---------- */
.clients-wave { position: relative; height: 100svh; overflow: clip; }
/* Fija mientras cruza la cinta (home.js le da a #clientes el alto del
   recorrido). Sticky y no el pin de ScrollTrigger: sin CLS y sin tirones. */
.clients-wave.is-sticky { position: sticky; top: 0; }
.clients-wave__head {
  position: absolute; left: var(--gutter); top: clamp(90px, 16vh, 160px); z-index: 1;
  max-width: 40ch;
}
.clients-wave__title {
  font-size: var(--fs-h2); max-width: 13ch;
  font-weight: 500; letter-spacing: -0.02em; line-height: 1.08;
}
/* Las tarjetas pasan POR DELANTE del titular: superficie opaca y elevada
   para que se lean como tarjetas flotando, no como logos transparentes.
   Escala pequeña y discreta, como los logos de la referencia (tryand.co). */
.client-card {
  position: absolute; top: 0; left: 0; z-index: 5;
  width: clamp(96px, 10vw, 150px); aspect-ratio: 1;
  background: var(--ink-card); border-radius: 18px;
  display: grid; place-items: center; padding: clamp(14px, 1.6vw, 24px);
  box-shadow: 0 14px 34px rgb(var(--shadow-rgb) / .55), 0 3px 10px rgb(var(--shadow-rgb) / .4);
  will-change: transform, opacity;
}
.client-card::before {
  content: ''; position: absolute; inset: 0; border-radius: 18px; padding: 1px;
  background: linear-gradient(135deg, rgb(var(--on-photo-rgb) / .28), rgb(var(--on-photo-rgb) / .07));
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
.client-card img { width: 100%; height: auto; opacity: .92; }
.client-card--wide img { width: 100%; }
.clients-grid { display: none; }
/* La ola termina con las últimas tarjetas saliendo por arriba a la izquierda
   mientras la sección sube: la parte de abajo queda en negro. Con la ola
   activa (home.js pone .has-wave) la sección siguiente sube por debajo de
   esas tarjetas en vez de esperar a que la ola se vaya entera: el titular de
   Números asoma antes (pedido del cliente, 2026-09-27). Es position:
   relative para pintarse sobre el fondo de la ola pero debajo de las
   tarjetas (z 5). */
#clientes.has-wave { margin-bottom: -42vh; }
#clientes.has-wave + section {
  position: relative;
  /* su parte de arriba es transparente justo donde se solapa con la ola: si
     fuera tinta opaca cortaba con un borde recto las tarjetas que todavía
     van saliendo (la ola pineada forma su propio contexto de apilado) */
  background: linear-gradient(to bottom, rgb(var(--ink-rgb) / 0) 0, rgb(var(--ink-rgb) / 0) 30vh, var(--ink) 42vh);
}
@media (max-width: 860px), (hover: none) {
  .clients-wave { display: none; }
  .clients-grid {
    /* minmax(0, 1fr) y no 1fr: el logo ancho (750x216) empujaba su columna
       por su ancho mínimo y la página desbordaba 9 px en horizontal a 390 */
    display: grid; gap: 14px; grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .clients-grid .cell {
    background: var(--ink-2); border: 1px solid var(--line-on-ink);
    border-radius: 20px; display: grid; place-items: center;
    aspect-ratio: 16/10; padding: 26px; min-width: 0;
  }
  .clients-grid .cell img { max-height: 60px; width: auto; max-width: 80%; opacity: .9; }
}

/* ---------- Equipo (Nosotros) ---------- */
.team-shot {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 16/8; background: var(--ink-2);
}
.team-shot img {
  position: absolute; inset: -8% 0; width: 100%; height: 116%; object-fit: cover;
}
@media (max-width: 700px) { .team-shot { aspect-ratio: 4/3; } }

/* ---------- Utilidades ---------- */
.mt-1 { margin-top: 14px; } .mt-2 { margin-top: 28px; } .mt-3 { margin-top: 48px; }
.tar { text-align: right; }
.hidden { display: none !important; }

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  /* Los retrasos también a cero: con solo la duración acortada, un componente
     con transition-delay seguía esperando su turno (un panel visible medio
     segundo de más, un relevo que tardaba en aparecer). */
  *, *::before, *::after { animation-duration: .001s !important; transition-duration: .001s !important; animation-delay: 0s !important; transition-delay: 0s !important; }
}


/* ---------- Formulario de contacto: aviso, error y confirmación ----------
   El formulario va a la bandeja del panel (/api/forms). El aviso de que lo
   escrito se guarda aunque no se envíe es obligatorio: no se quita. */
.form__privacy { font-size: .82rem; line-height: 1.45; max-width: 60ch; }
/* "No guardar hasta que lo envíe" (js/stats.js pone .no-drafts en <html>). */
.no-drafts [data-drafts-on], html:not(.no-drafts) [data-drafts-off] { display: none; }
.linkish {
  font: inherit; color: var(--text-on-ink); background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  transition: color .2s var(--ease-ui), text-decoration-color .2s var(--ease-ui);
}
.linkish:hover { color: var(--orange); text-decoration-color: currentColor; }
.linkish:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; border-radius: 2px; }
.form__error { color: #FF8A6B; font-size: .92rem; }
[data-form-ok] { color: var(--orange); font-size: 1rem; outline: none; }

/* ---------- Seguir bajando → página siguiente (js/next-page.js, 2026-10-08) ----------
   Píldora fija abajo que aparece al tocar fondo; su barra se llena si la
   persona sigue bajando. En Soluciones abre Hablemos. Capa aparte: no
   toca ninguna animación de las páginas. */
.np {
  position: fixed; left: 50%; bottom: max(18px, env(safe-area-inset-bottom)); z-index: 250;
  display: grid; justify-items: center; gap: 4px; min-width: 190px; padding: 12px 26px 15px;
  border-radius: 999px; border: 1px solid var(--line-on-ink); background: rgb(var(--ink-rgb) / .86);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: var(--text-on-ink); cursor: pointer; overflow: hidden;
  opacity: 0; transform: translate(-50%, 16px); pointer-events: none;
  transition: opacity .35s var(--ease-ui), transform .5s var(--ease-enter), border-color .3s var(--ease-ui);
}
.np.is-on { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.np:hover, .np:focus-visible, .np.is-filling { border-color: rgb(var(--orange-rgb) / .6); }
.np:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; }
.np__k { font-size: .68rem; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; color: var(--text-on-ink-2); }
.np__n { font-size: 1.05rem; font-weight: 500; letter-spacing: -.01em; }
.np__a { display: inline-block; color: var(--orange); transition: transform .3s var(--ease-snap); }
.np:hover .np__a { transform: translateX(3px); }
.np__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgb(var(--fg-rgb) / .08); }
.np__bar i { display: block; height: 100%; background: var(--orange); transform-origin: left; transform: scaleX(0); transition: transform .12s linear; }
.np-veil { position: fixed; inset: 0; z-index: 400; background: var(--ink); opacity: 0; pointer-events: none; transition: opacity .4s var(--ease-exit); }
html.np-leaving .np-veil { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) { .np, .np__bar i, .np-veil { transition: none; } }

/* ---------- Botón de descarga de un programa (Apps y la página de cada programa) ----------
   Con enlace, un botón con el logo del sistema; sin enlace todavía
   (js/descargas.js vacío), apagado y con "Pronto". */
.dl-btn {
  display: inline-flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 20px;
  border-radius: 999px; border: 1px solid rgb(var(--fg-rgb) / .36); color: var(--text-on-ink);
  font-size: .95rem; font-weight: 500; white-space: nowrap;
  transition: background-color .2s var(--ease-ui), border-color .2s var(--ease-ui), color .2s var(--ease-ui), transform .16s var(--ease-snap);
}
.dl-btn svg { width: 18px; height: 18px; flex: none; }
.dl-btn:not(.is-soon):hover { border-color: var(--orange); }
.dl-btn:not(.is-soon):active { transform: scale(.97); }
.dl-btn--primary:not(.is-soon) { background: var(--orange); border-color: var(--orange); color: var(--ink); }   /* sobre naranja, texto en tinta */
.dl-btn.is-soon { cursor: default; color: var(--text-on-ink-2); border-style: dashed; border-color: rgb(var(--fg-rgb) / .3); }
.dl-btn__soon { font-size: .7rem; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--orange); }

