/* ============================================================================
   SPEACH — BASE. Dueño: A-BASE.
   Tipografía, tokens, reset, utilidades, header, menú, botones, campos,
   chips, filtros, footer y componentes heredados retokenizados.
   Aquí NO vive nada de loader, reveals, splitter ni secciones nuevas:
   eso es de motion.css y components.css.
   ============================================================================ */

/* ------------------------------------------------------------------ FUENTES --
   Locales, sin red. `swap` para que el texto se lea desde el primer frame.     */
@font-face{
  font-family:'Outfit'; font-style:normal; font-weight:100 900; font-display:swap;
  src:url('/assets/fonts/Outfit-full.woff2') format('woff2');
}
/* DM Serif Display en sus DOS cortes. El romano es la voz del logotipo —el
   wordmark «Speach.» es serif, no Outfit— y desde el rediseño lleva también
   todos los titulares de display y los numerales editoriales. La itálica
   sigue siendo el acento dentro de frase (.serif-it).                         */
@font-face{
  font-family:'DM Serif Display'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/assets/fonts/DMSerifDisplay-400.woff2') format('woff2');
}
@font-face{
  font-family:'DM Serif Display'; font-style:italic; font-weight:400; font-display:swap;
  src:url('/assets/fonts/DMSerifDisplay-italic-400.woff2') format('woff2');
}
/* CoFo Meteor V0.2 SemiBold: LA fuente de marca. OJO: los archivos actuales
   son el corte demo SIN español (faltan ¿ ¡ á é í ó ú ñ ü — medido por
   glifo en Chrome), así que sólo habla donde la marca se escribe a sí misma:
   «Speach.» puro ASCII — wordmark del hero, telón y logotipo del header. Los
   titulares siguen en DM Serif hasta tener el corte completo (PENDIENTES
   §3quater). El unicode-range es el candado: si un acento llegara a un
   contexto de marca, cae al respaldo en vez de pintar un tofu.                */
@font-face{
  font-family:'CoFo Meteor'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('/assets/fonts/CoFoMeteorV02-SemiBold.woff2') format('woff2'),
      url('/assets/fonts/CoFoMeteorV02-SemiBold.woff') format('woff');
  unicode-range:U+0020-007E,U+2013-2014,U+2018-201D,U+2192;
}
/* Su respaldo con métricas ajustadas, mismo método que los dos de abajo
   (measureText a 100 px en Chrome): Meteor 2131.6 px / Georgia 2856.7 px
   -> 74.6%; asc 87, desc 15. Meteor es condensada: sin el size-adjust el
   «Speach.» de respaldo desbordaba un 34% más ancho.                          */
@font-face{
  font-family:'Georgia Meteor';
  src:local('Georgia'),local('Times New Roman'),local('Tinos');
  size-adjust:74.6%; ascent-override:116.6%; descent-override:20.1%; line-gap-override:0%;
}

/* Anton: la voz del cartel. Grotesca condensada ultra-negra —el registro de
   la referencia «built for growth»— y sólo vive ahí: el titular gigante del
   hero del home. La marca sigue siendo CoFo + DM Serif; esto no es una voz
   nueva del sistema, es el grito de la portada. Va SÓLO el corte latin (12 KB):
   el español entero —acentos, ñ, ¿ ¡— cabe en U+00xx, así que el latin-ext de
   Google (21 KB más) sería peso muerto en el presupuesto de arranque. El
   unicode-range es el candado, igual que en Meteor.                          */
@font-face{
  font-family:'Anton'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/assets/fonts/Anton-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* Su respaldo, mismo método (measureText a 100 px en Chrome sobre «EL ARTE DE
   CONSTRUIR MARCAS.»): Anton 1174.7 px / Impact 1245 px -> 94.4 %; asc 118,
   desc 33, ya divididos por el size-adjust. Impact es el único condensado
   negro que está en todos los Mac y Windows; Haettenschweiler y Arial Narrow
   quedan detrás por si acaso. Con esto el titular no se mueve un pixel cuando
   entra la webfont.                                                           */
@font-face{
  font-family:'Impact Anton';
  src:local('Impact'),local('Haettenschweiler'),local('Arial Narrow Bold'),local('Oswald');
  size-adjust:94.4%; ascent-override:125%; descent-override:35%; line-gap-override:0%;
}

/* Respaldos con métricas ajustadas: mientras la webfont carga, el texto ocupa
   exactamente el mismo espacio, así el `swap` no mueve una sola línea (CLS 0).
   Medido en Chrome con measureText a 100 px sobre las fuentes reales:
   Outfit 3461.6 px / Helvetica Neue 3534.2 px -> 97.9 %; asc 100, desc 26.
   DM Serif 3429.2 px / Georgia 3470.8 px      -> 98.8 %; asc 104, desc 34.
   Se redefinen los mismos nombres que ya están en --font y --serif: no se
   inventa una familia nueva ni se toca el bloque de tokens.                    */
@font-face{
  font-family:'Helvetica Neue';
  src:local('Helvetica Neue'),local('Arial'),local('Liberation Sans'),local('Arimo');
  size-adjust:97.9%; ascent-override:102.1%; descent-override:26.5%; line-gap-override:0%;
}
@font-face{
  font-family:'Georgia';
  src:local('Georgia'),local('Times New Roman'),local('Tinos');
  size-adjust:98.8%; ascent-override:105.3%; descent-override:34.4%; line-gap-override:0%;
}

/* ============================================================================
   SPEACH — TOKENS. Fuente única de verdad. No duplicar en otro archivo.
   ============================================================================ */
:root{

  /* ---------------------------------------------------------------- COLOR --
     Escala fucsia (hue 301). #F23CEE se conserva exacto como --pk-500.        */
  --pk-50:#FFEDFD;   /* fondo tenue, relleno de chip, hover de fila            */
  --pk-100:#FFD4FB;  /* superficie acento, resaltado                          */
  --pk-200:#FEAEF9;  /* bordes decorativos, tramas                            */
  --pk-300:#FC80F6;  /* TEXTO fucsia sobre tinta — 6.95:1 peor caso ✓AA       */
  --pk-400:#F65DF1;  /* texto secundario sobre tinta — 5.64:1 ✓AA             */
  --pk-500:#F23CEE;  /* EL COLOR. Relleno, borde, el punto. 3.15:1 sobre      */
                     /* blanco: NUNCA texto de cuerpo sobre claro.            */
  --pk-600:#E216E2;  /* hover de relleno acento                               */
  --pk-700:#B210B5;  /* TEXTO fucsia sobre blanco — 5.78:1 ✓AA                */
  --pk-800:#830A87;  /* texto fucsia enfático, :active                        */
  --pk-900:#59065D;  /* tinta con carga de marca, sombras teñidas             */

  /* Escala neutra tintada de magenta (hue 301, croma muy bajo).
     Invisible aislada, coherente en conjunto: el gris vibra con el fucsia.    */
  --n-0:#FFFFFF;
  --n-50:#FCFAFC;
  --n-100:#F8F4F8;
  --n-200:#EEEAEE;   /* línea decorativa (sustituye a #ececec)                */
  --n-300:#DDD7DD;
  --n-400:#B8ADB8;
  --n-500:#948794;   /* borde de control en claro — 3.41:1 ✓ 1.4.11           */
  --n-600:#736473;   /* texto silenciado en claro — 5.53:1 ✓AA                */
  --n-700:#534653;   /* texto secundario en claro — 8.87:1 ✓AAA               */
  --n-800:#382C38;
  --n-900:#251B25;
  --n-950:#181018;
  --ink-950:#14101B; /* la tinta de marca. 18.76:1 sobre blanco               */

  /* Soporte 1 — Durazno. Calidez humana: equipo, proceso, 2ª serie de datos.  */
  --pc-300:#FFBE99;  /* 11.68:1 sobre tinta */
  --pc-400:#FBA174;  /*  9.33:1 sobre tinta */
  --pc-500:#F47F4E;
  --pc-600:#E65019;
  --pc-700:#AC3915;  /*  6.27:1 sobre blanco ✓AA */

  /* Soporte 2 — Agua. EXCLUSIVO de /desarrollo-web/ (página en tinta).
     Fuera de esa página no aparece nunca. Esa restricción es lo que hace
     que la página de dev se sienta un lugar distinto.                        */
  --aq-300:#7BF4E4;
  --aq-400:#47EBDA;  /* 12.65:1 sobre tinta */
  --aq-500:#11D0C3;  /*  9.68:1 sobre tinta ·  7.88:1 sobre --surface-2 ink   */
  --aq-600:#08A09B;
  --aq-700:#057676;  /*  5.44:1 sobre blanco ✓AA (único uso en claro)         */

  /* Estados semánticos. El error NUNCA es rosa (el rosa es la marca).
     El éxito nunca se comunica sólo con color: color + icono + texto.        */
  --ok:#0E7A52;        --ok-ink:#4ADE80;    --ok-bg:#E7F8F0;   --ok-bg-ink:#0E2A1E;
  --wa:#9A5B00;        --wa-ink:#FCD34D;    --wa-bg:#FEF6E7;   --wa-bg-ink:#2B1F05;
  --er:#C42A20;        --er-ink:#FF7A70;    --er-bg:#FDECEA;   --er-bg-ink:#2E1210;

  /* -------------------------------------------------- TOKENS SEMÁNTICOS ----
     TODO componente usa SÓLO estos. Un componente que escribe #fff o
     var(--n-0) directamente está roto en modo tinta: es un bug bloqueante.    */
  --bg:          var(--n-0);
  --surface:     var(--n-50);      /* superficie elevada 1 */
  --surface-2:   var(--n-100);     /* superficie elevada 2 / campos */
  --fg:          var(--ink-950);   /* 18.76:1 */
  --fg-2:        var(--n-700);     /*  8.87:1 */
  --fg-muted:    var(--n-600);     /*  5.53:1 sobre bg · 5.08:1 sobre surface-2 ✓AA */
  --line:        var(--n-200);     /* decorativa */
  --line-strong: var(--n-300);
  --line-ctl:    var(--n-500);     /*  3.41:1 ✓ 1.4.11 */
  --accent:      var(--pk-500);    /* rellenos, bordes, el punto */
  --accent-fg:   var(--pk-700);    /* TEXTO fucsia — 5.78:1 ✓AA */
  --on-accent:   var(--ink-950);   /* texto sobre relleno fucsia — 5.94:1 ✓AA */
  --disabled-bg: var(--n-200);
  --disabled-fg: #6E626E;          /*  4.85:1 sobre --disabled-bg ✓AA */
  --focus-ring:  var(--ink-950);
  --focus-halo:  var(--n-0);
  --grain:       .045;
  --img-bright:  1;
  --sb-thumb:    var(--ink-950);   /* scrollbar: tinta en claro, B/N puro */

  /* --------------------------------------------------------- GRADIENTES ----
     Texto sobre gradiente: SIEMPRE tinta, y sólo display ≥24px
     (peor stop #B21FA8 = 3.26:1). Para párrafo, velo rgba(255,255,255,.72).   */
  --grad-cielo: linear-gradient(180deg,#7A0E7F 0%,#B21FA8 22%,#F23CEE 52%,#FF9BE8 78%,#FFEDFD 100%);
  --grad-horizonte: linear-gradient(90deg,#F23CEE 0%,#FF9BE8 45%,#FBA174 100%);
  --grad-tinta: radial-gradient(120% 90% at 50% 115%,#3A0C3E 0%,#1E1826 45%,#14101B 100%);
  --grad-borde: linear-gradient(90deg,transparent,#F23CEE 30%,#FBA174 70%,transparent);

  /* ------------------------------------------------------------ SOMBRAS ----
     Teñidas de magenta, nunca negras. En tinta NO existen: la elevación
     se comunica con superficie más clara + --sh-inset.                        */
  --sh-1: 0 1px 2px rgba(20,16,27,.06), 0 2px 8px -2px rgba(89,6,93,.08);
  --sh-2: 0 4px 12px -4px rgba(20,16,27,.10), 0 12px 32px -12px rgba(89,6,93,.14);
  --sh-3: 0 8px 24px -8px rgba(20,16,27,.12), 0 28px 60px -24px rgba(89,6,93,.22);
  --sh-pk: 0 10px 34px -10px rgba(226,22,226,.42);
  --sh-inset: inset 0 0 0 1px rgba(255,255,255,.08);

  /* ------------------------------------------------------- TIPOGRAFÍA ------ */
  --font: 'Outfit','Helvetica Neue',Arial,sans-serif;
  --serif:'DM Serif Display',Georgia,serif;
  /* La voz del wordmark es CoFo Meteor, la fuente real de marca. Los
     titulares editoriales («¿Tienes algo que decir?») siguen en DM Serif:
     el corte demo de Meteor no trae español (§PENDIENTES 3quater).          */
  --brand-font:'CoFo Meteor','Georgia Meteor',serif;
  /* La voz de cartel: sólo el titular gigante del hero del home.             */
  --poster-font:'Anton','Impact Anton',Impact,sans-serif;
  --mono: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  --t-mega:    clamp(3.25rem, 12vw,  10rem);   /* SÓLO loader y H1 del home  */
  --t-display: clamp(2.75rem, 8.5vw, 6.5rem);  /* H1 de página, "Hablemos."  */
  --t-h1:      clamp(2.25rem, 5.5vw, 4rem);
  --t-h2:      clamp(1.75rem, 3.6vw, 2.75rem);
  --t-h3:      clamp(1.35rem, 2.2vw, 1.75rem);
  --t-h4:      clamp(1.05rem, 1.5vw, 1.25rem);
  --t-lead:    clamp(1.08rem, 1.5vw, 1.375rem);
  --t-body:    clamp(1rem, .95rem + .2vw, 1.0625rem);
  --t-body-s:  .9375rem;
  --t-ui:      .9375rem;
  --t-caption: .8125rem;   /* piso absoluto del sitio: nada por debajo de 13px */
  --t-eyebrow: .75rem;     /* excepción única: va en MAYÚSCULAS + tracking .16em */
  --t-num:     clamp(2.75rem, 6vw, 5rem);
  --t-mono-s:  .875rem;

  --lh-display:.90;  --lh-tight:1.06;  --lh-ui:1.2;  --lh-body:1.62;  --lh-lead:1.50;
  --ls-mega:-.045em; --ls-display:-.038em; --ls-h1:-.030em; --ls-h2:-.022em;
  --ls-h3:-.015em;   --ls-ui:-.004em;      --ls-eyebrow:.16em;
  --wght-display:800; --wght-h:700; --wght-h3:600; --wght-ui:600; --wght-body:400;

  --maxw-text: 68ch;   /* cuerpo   */
  --maxw-lead: 58ch;   /* entrada  */
  --maxw-disp: 20ch;   /* display  */

  /* ----------------------------------------------------------- ESPACIO ----- */
  --s-1:4px;  --s-2:8px;  --s-3:12px; --s-4:16px; --s-5:24px; --s-6:32px;
  --s-7:48px; --s-8:64px; --s-9:96px; --s-10:128px; --s-11:160px;

  --pad:      clamp(18px, 4.5vw, 60px);      /* margen lateral de página      */
  --gutter:   clamp(14px, 1.6vw, 28px);
  --maxw:     1360px;
  --maxw-wide:1600px;
  --sec-y:       clamp(64px, 9vw, 160px);
  --sec-y-tight: clamp(40px, 5vw, 80px);
  --sec-y-loose: clamp(96px, 14vw, 240px);
  --hd-h: 68px;                               /* alto del header, para scroll-margin */

  /* ------------------------------------------------------------ RADIOS ----- */
  --r-xs:6px; --r-sm:10px; --r-md:16px; --r-lg:24px; --r-xl:32px; --r-full:999px;
  /* LA firma: tres esquinas suaves + cola abajo-izquierda (globo de diálogo). */
  --r-bubble:    var(--r-lg) var(--r-lg) var(--r-lg) var(--r-xs);
  --r-bubble-lg: var(--r-xl) var(--r-xl) var(--r-xl) var(--r-sm);

  /* --------------------------------------------------------- MOVIMIENTO ---- */
  --t-0:   0ms;    --t-1:  90ms;  --t-2: 180ms;  --t-3: 300ms;
  --t-4: 460ms;    --t-5: 640ms;  --t-6: 880ms;  --t-7:1200ms;  --t-8:1600ms;
  /* Deriva ambiental: bucles de decoración (la ballena, el durazno). Nunca
     para transiciones de UI — para eso está la escala de arriba.             */
  --t-nado: 16s;   --t-flota: 22s;

  --e-out:   cubic-bezier(.22,1,.36,1);      /* DEFAULT: todo lo que entra    */
  --e-expo:  cubic-bezier(.16,1,.30,1);      /* cortinas, telón, líneas       */
  --e-inout: cubic-bezier(.65,0,.35,1);      /* movimientos simétricos        */
  --e-in:    cubic-bezier(.55,0,1,.45);      /* lo que SALE de pantalla       */
  --e-snap:  cubic-bezier(.70,0,.20,1);      /* wipes, clip-path, cierres     */
  --e-back:  cubic-bezier(.34,1.56,.64,1);   /* overshoot: SÓLO el punto y el
                                                check de copiado             */
  --e-lin:   linear;                          /* marquee, barra, scroll-driven */

  --m-0:4px; --m-1:8px; --m-2:16px; --m-3:28px; --m-4:56px;
  --m-line:105%;   /* máscara tipográfica: el 5% extra cubre g, j, p, y       */
  --m-px:8%;       /* amplitud de parallax por defecto. Cap duro: 10%          */

  --s-press:.97;   --s-zoom:1.06;   --s-pop:1.12;

  --st-0:25ms; --st-1:55ms; --st-2:95ms; --st-3:150ms;
  --st: var(--st-1);
  --st-cap: 8;     /* a partir del 8º fragmento el delay se congela           */

  /* CRISTAL. El tema glass de la casa: superficies que FLOTAN sobre arte o
     contenido (header, chips sobre foto, menú overlay).
     Traslúcido + blur + saturación; el respaldo sin backdrop-filter es el
     fondo sólido de siempre — el cristal es mejora progresiva, nunca un
     requisito de legibilidad. El blur queda RESERVADO a estas superficies.   */
  --glass-bg:   color-mix(in srgb, var(--bg) 82%, transparent);
  --glass-ink:  color-mix(in srgb, var(--ink-950) 80%, transparent);
  --glass-line: color-mix(in srgb, var(--fg) 14%, transparent);
  --fx-glass:    blur(14px) saturate(1.5);
  --fx-glass-lg: blur(26px) saturate(1.4);   /* sólo el menú overlay          */

  /* ------------------------------------------------------------ Z-INDEX ---- */
  /* --z-fondo es el único negativo: la capa de la criatura cae bajo todo el
     contenido y sobre el lienzo. Funciona porque html no declara background
     y el de body se propaga al canvas; si algún día html lo declara, la
     criatura desaparece. */
  --z-fondo:-1;
  --z-base:0; --z-raised:1; --z-nav-local:5; --z-sticky:40; --z-header:100;
  --z-menu:900; --z-chip:960; --z-grain:9990; --z-loader:9999;
}

/* Peso variable interpolable. Sin @property no interpola: es obligatorio.     */
@property --wght { syntax:'<number>';     inherits:false; initial-value:800; }
@property --p    { syntax:'<percentage>'; inherits:false; initial-value:50%;  }
@property --pn   { syntax:'<number>';     inherits:false; initial-value:.5;   }
@property --pf   { syntax:'<number>';     inherits:false; initial-value:0;    }

/* El sitio es claro por decisión editorial. Sin esto, Chrome/Android
   auto-oscurece los controles nativos y destruye toda la matemática de arriba. */
:root{ color-scheme: light; }

/* --------------------------------------------------------- MODO TINTA -------
   No hay toggle de usuario: es una decisión editorial por sección. Redefine
   SÓLO tokens semánticos, por eso funciona sin tocar un solo componente.      */
[data-mode="ink"]{
  --bg:          var(--ink-950);
  --surface:     #1E1826;
  --surface-2:   #2A2233;
  --fg:          var(--n-0);        /* 18.76:1 sobre tinta · 15.27:1 sobre surface-2 */
  --fg-2:        var(--n-300);      /* 10.79:1 peor caso ✓AAA */
  --fg-muted:    #A99BA9;           /*  5.78:1 sobre surface-2 · 6.10:1 sobre el stop
                                       #3A0C3E de --grad-tinta ✓AA               */
  --line:        #2E2438;
  --line-strong: #3D3049;
  --line-ctl:    #8A798A;           /*  3.77:1 sobre surface-2 ✓ 1.4.11 */
  --accent:      var(--pk-500);
  --accent-fg:   var(--pk-300);     /*  6.95:1 peor caso ✓AA */
  --on-accent:   var(--ink-950);
  --disabled-bg: #2A2233;
  --disabled-fg: #A99BA9;
  --focus-ring:  var(--n-0);
  --focus-halo:  var(--ink-950);
  --grain:       .09;
  --img-bright:  .92;               /* las imágenes no queman sobre negro */
  --sb-thumb:    var(--n-300);      /* blanco suave, espejo del tinta-sobre-blanco */
  --sh-1:none; --sh-2:none; --sh-3:none;   /* en tinta la sombra no se ve */
  background: var(--grad-tinta);
  color: var(--fg);
  color-scheme: dark;
}

/* ------------------------------------------------------------------- RESET -- */
*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0 }
html{
  scroll-behavior:smooth; -webkit-text-size-adjust:100%;
  /* .bleed usa 100vw: sin gutter estable el ancho de la barra desborda.
     Y NADA de overflow-x:hidden en body: rompería position:sticky.            */
  scrollbar-gutter:stable;
}
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto } }
body{
  font-family:var(--font); font-size:var(--t-body); font-weight:var(--wght-body);
  line-height:var(--lh-body); background:var(--bg); color:var(--fg);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
img,svg,video,canvas{ display:block; max-width:100% }
img,video{ height:auto }
a{ color:inherit; text-decoration:none }
ul,ol{ list-style:none }
button,input,select,textarea{ font:inherit; color:inherit; letter-spacing:inherit }
button{ background:none; border:0; cursor:pointer }
:where(h1,h2,h3,h4,h5,h6){ font-weight:var(--wght-h); line-height:var(--lh-tight);
  letter-spacing:var(--ls-h2); text-wrap:balance }
:where(p,li){ text-wrap:pretty }
strong,b{ font-weight:700 }
hr{ border:0; border-top:1px solid var(--line) }
::selection{ background:var(--accent); color:var(--on-accent) }
/* Bloqueante para los filtros: sin !important cualquier .work-card{display:flex}
   gana por especificidad y [hidden] deja de ocultar nada.                     */
[hidden]{ display:none !important }
/* Anclas: el header sticky no puede tapar el destino.                         */
:target{ scroll-margin-block-start:calc(var(--hd-h) + var(--s-5)) }

/* -------------------------------------------------------------- SCROLLBAR --
   La barra también es interfaz: una píldora de tinta que corre sobre un riel
   de pelo —la misma --line de todas las reglas del sitio— y que sólo se pone
   fucsia al tacto. B/N en reposo, EL COLOR al agarrar: la gramática de marca.
   Zona de golpe de 12px con píldora visible de 6px (borde transparente +
   background-clip); al hover engorda a 8px, como la nativa de macOS.
   OJO Chrome ≥121: declarar scrollbar-width/scrollbar-color en un elemento
   ANULA todo ::-webkit-scrollbar en ese elemento. Por eso las propiedades
   estándar viven SÓLO en el @supports de respaldo (Firefox), y .rail-track
   (components.css) tampoco las declara fuera del suyo.                        */
::-webkit-scrollbar{ width:12px; height:12px }
::-webkit-scrollbar-button{ display:none; width:0; height:0 }
::-webkit-scrollbar-corner{ background:transparent }
::-webkit-scrollbar-track:vertical{
  background:linear-gradient(to right,
    transparent calc(50% - .5px), var(--line) 0,
    var(--line) calc(50% + .5px), transparent 0);
}
::-webkit-scrollbar-track:horizontal{
  background:linear-gradient(to bottom,
    transparent calc(50% - .5px), var(--line) 0,
    var(--line) calc(50% + .5px), transparent 0);
}
::-webkit-scrollbar-thumb{
  background-color:var(--sb-thumb); background-clip:padding-box;
  border:3px solid transparent; border-radius:var(--r-full);
}
::-webkit-scrollbar-thumb:hover{ background-color:var(--accent); border-width:2px }
::-webkit-scrollbar-thumb:active{ background-color:var(--pk-600); border-width:2px }
/* Respaldo estándar (Firefox): sin riel ni engorde, pero misma píldora fina.
   scrollbar-color hereda el valor COMPUTADO —la var se resuelve en html—,
   así que se re-declara en [data-mode="ink"] para que las secciones en tinta
   (y sus scrollers internos, como .rail-track) resuelvan su propio token.     */
@supports not selector(::-webkit-scrollbar){
  html{ scrollbar-color:var(--sb-thumb) transparent }
  [data-mode="ink"]{ scrollbar-color:var(--sb-thumb) transparent }
}

/* ------------------------------------------------------- ANILLO DE FOCO -----
   Una sola regla, global, doble y agnóstica del fondo: los dos colores se
   invierten juntos con [data-mode], así sobrevive a blanco, fucsia, tinta e
   imagen. Nadie vuelve a escribir outline:none en este proyecto.              */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px var(--focus-halo);
  border-radius: 4px;
}

/* ------------------------------------------------- TIPOGRAFÍA Y UTILIDADES --
   LOS ROLES DE DISPLAY SON SERIF. La voz del logotipo (DM Serif Display
   romano) manda en todo lo grande: wordmark, titulares de sección, cifras.
   Outfit se queda con el cuerpo, la UI y los subtítulos: el contraste entre
   las dos familias es el sistema. El serif va SIEMPRE en 400 —no existe otro
   peso— y con tracking casi neutro: apretarlo como al sans lo rompe.          */
.h-mega,.h-display,.h-1,.h-2{ font-family:var(--serif); font-weight:400; font-synthesis:none }
.h-mega{ font-size:var(--t-mega); line-height:.96; letter-spacing:-.014em }
.h-display{ font-size:var(--t-display); line-height:.98; letter-spacing:-.012em }
.h-1{ font-size:var(--t-h1); line-height:1.04; letter-spacing:-.010em }
.h-2{ font-size:calc(var(--t-h2)*1.08); line-height:1.08; letter-spacing:-.008em }
.h-3{ font-size:var(--t-h3); font-weight:var(--wght-h3); line-height:var(--lh-ui); letter-spacing:var(--ls-h3) }
.h-4{ font-size:var(--t-h4); font-weight:var(--wght-h3); line-height:var(--lh-ui); letter-spacing:var(--ls-ui) }
.lead{ font-size:var(--t-lead); line-height:var(--lh-lead); color:var(--fg-2) }
.body{ font-size:var(--t-body); line-height:var(--lh-body) }
.body-s{ font-size:var(--t-body-s); line-height:var(--lh-body) }
.caption{ font-size:var(--t-caption); line-height:var(--lh-ui); color:var(--fg-muted) }
.eyebrow{ font-size:var(--t-eyebrow); font-weight:var(--wght-ui); text-transform:uppercase;
  letter-spacing:var(--ls-eyebrow); color:var(--fg-muted) }
.upper{ text-transform:uppercase; letter-spacing:var(--ls-eyebrow) }
.mono{ font-family:var(--mono); font-size:var(--t-mono-s); letter-spacing:0 }
/* El punto es la marca: es el carácter '.', nunca un círculo dibujado.        */
.dot{ color:var(--accent) }
.serif-it{ font-family:var(--serif); font-style:italic; font-weight:400;
  font-size:1em; letter-spacing:-.005em; padding-right:.04em }
.maxw-text{ max-width:var(--maxw-text) } .maxw-lead{ max-width:var(--maxw-lead) }
.maxw-disp{ max-width:var(--maxw-disp) }
.muted{ color:var(--fg-muted) }

/* Ritmo vertical por "owl": un solo lugar decide el aire entre bloques.       */
.flow > * + *{ margin-block-start:var(--flow,var(--s-5)) }

.wrap,.wrap-wide{ width:100%; margin-inline:auto; padding-inline:var(--pad) }
.wrap{ max-width:var(--maxw) } .wrap-wide{ max-width:var(--maxw-wide) }
.bleed{ margin-inline:calc(50% - 50vw); width:100vw; max-width:100vw }

.grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--gutter) }
@media (min-width:768px){ .grid{ grid-template-columns:repeat(8,1fr) } }
@media (min-width:1024px){ .grid{ grid-template-columns:repeat(12,1fr) } }

.sec{ padding-block:var(--sec-y) }
.sec-tight{ padding-block:var(--sec-y-tight) }
.sec-loose{ padding-block:var(--sec-y-loose) }
.sec-head{ display:flex; justify-content:space-between; align-items:flex-end;
  gap:var(--s-5); flex-wrap:wrap; margin-bottom:var(--s-7) }

.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 }
/* Skip link: invisible hasta que recibe foco.                                 */
a.sr-only:focus-visible{ position:fixed; top:var(--s-3); left:var(--s-3); z-index:var(--z-loader);
  width:auto; height:auto; margin:0; padding:var(--s-3) var(--s-5); clip:auto; clip-path:none;
  background:var(--bg); color:var(--fg); border-radius:var(--r-full); font-weight:var(--wght-ui) }
/* Único convenio: lo que sólo tiene sentido con JS. Para lo inverso,
   html:not(.js) … — la clase .no-js no existe en este proyecto.               */
html:not(.js) .js-only{ display:none }

/* Dato pendiente de confirmar. Visible en desarrollo, bloqueante para publicar. */
.ph[data-ph]{ border-bottom:2px dotted var(--accent); cursor:help }

/* Separador de 1 px que se dibuja al revelarse (la clase .in la pone el motor). */
.linea{ position:relative }
.linea::after{ content:''; position:absolute; inset:auto 0 0 0; height:1px;
  background:var(--line); transform:scaleX(0); transform-origin:0 50%;
  transition:transform var(--t-6) var(--e-out) }
.linea.in::after{ transform:scaleX(1) }
.linea.acento::after{ background:var(--grad-borde); height:1.5px }

/* Trama de puntos. Densidad por --trama-size: 6px densa · 8px normal · 14px aireada. */
.trama{ background-image:radial-gradient(var(--pk-200) 1px,transparent 1.3px);
  background-size:var(--trama-size,8px) var(--trama-size,8px);
  -webkit-mask-image:linear-gradient(160deg,#000 10%,transparent 70%);
  mask-image:linear-gradient(160deg,#000 10%,transparent 70%) }

/* Texto en contorno. Sólo de --t-h1 para arriba: por debajo se rompe.         */
.outline{ color:transparent; -webkit-text-stroke:1.2px currentColor }
@supports (-webkit-hyphens:none){ .outline{ -webkit-text-stroke-width:1px } }

/* Retratos: blanco y negro editorial que recupera el color al hover o al
   foco. El velo fucsia de antes teñía las caras y abarataba la página: el
   B/N limpio es lo que hace que el fucsia de alrededor se vea caro.           */
.duo{ position:relative; isolation:isolate }
.duo img{ filter:grayscale(1) contrast(1.06) brightness(1.03);
  transition:filter var(--t-5) var(--e-out), transform var(--t-5) var(--e-out) }
.duo:hover img,.duo:focus-within img{ filter:none; transform:scale(1.03) }
/* Sin puntero: el equipo tiene cara siempre.                                  */
@media (hover:none){ .duo img{ filter:none } }

/* -------------------------------------------------------- HEADER Y MENÚ ----- */
/* BARRA GLASS (2026-07-31). Arriba del todo la barra es INVISIBLE: fondo
   transparente, la página respira entera por debajo. Al primer scroll llega
   .stuck (centinela de speach.js) y el cristal se enciende: blur + velo del
   papel + canto de 1px. Como el contenedor cubre todo el ancho, NO intercepta
   el puntero: pointer-events se devuelve pieza por pieza, si no, una franja
   invisible de 68px se comería los clics del contenido de arriba.
   El modo tinta (data-mode="ink" que pone motion.js) sigue llegando: cristal
   y piezas se pintan con --fg/--bg, así que se invierten solos.               */
/* fixed, no sticky: la barra FLOTA sobre el contenido desde el primer píxel
   —transparente deja ver el hero debajo, no una franja de papel propia.       */
.hd{
  position:fixed; inset:0 0 auto; z-index:var(--z-header);
  background:none; border:0; pointer-events:none;
}
/* EL CRISTAL ES UN GLOBO (rediseño 2026-08-02): al pegarse, el header no
   enciende una barra de lado a lado sino una CÁPSULA flotante con el radio
   de la casa —tres esquinas redondas y la cuarta en punta, abajo a la
   izquierda: la misma cola del globo de diálogo del CTA y de las burbujas
   del contenido. El header entero viaja dentro de una burbuja dicha.       */
.hd::before{
  content:''; position:absolute; z-index:-1; pointer-events:none;
  inset:8px clamp(12px,1.6vw,24px) 4px;
  border-radius:var(--r-bubble-lg);
  background:color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter:blur(18px) saturate(1.6);
  backdrop-filter:blur(18px) saturate(1.6);
  border:1px solid color-mix(in srgb, var(--fg) 18%, transparent);
  box-shadow:var(--sh-2);
  opacity:0; scale:.98; transform-origin:12% 100%;
  transition:opacity var(--t-3) var(--e-out), scale var(--t-4) var(--e-back);
}
.hd.stuck::before{ opacity:1; scale:1 }
@media (prefers-reduced-motion:reduce){ .hd::before{ transition:opacity var(--t-3) var(--e-out); scale:1 } }
html.rm .hd::before{ transition:opacity var(--t-3) var(--e-out); scale:1 }
/* AUTOOCULTA (2026-08-02): bajando, la barra se retira por el techo; al primer
   gesto hacia arriba vuelve. La clase .hd-fuera la pone speach.js con
   histéresis (nunca en los primeros píxeles de la página, donde la barra es
   invisible de todas formas). Los dos sentidos NO se mueven igual: irse usa
   --e-in —lo que sale de pantalla— y es más corto, porque quitarse de en medio
   debe pasar desapercibido; volver usa --e-out y dura más, para que se lea como
   un gesto y no como un parpadeo. -101% se lleva también el canto de 1px del
   cristal. Se anima translate (compositor puro): ni un reflow por cuadro.      */
.hd{ transition:translate var(--t-4) var(--e-out) }
.hd.hd-fuera{ translate:0 -101%; transition:translate var(--t-3) var(--e-in) }
/* Con movimiento reducido la barra no se esconde (speach.js ni pone la clase);
   si el usuario enciende «menos movimiento» con la barra fuera, vuelve sin
   transición: mejor un salto que un deslizamiento que no pidió.                */
@media (prefers-reduced-motion:reduce){ .hd,.hd.hd-fuera{ transition:none } }
html.rm .hd,html.rm .hd.hd-fuera{ transition:none }
/* Sin max-width: la barra usa el ancho entero con un margen lateral generoso
   y SIMÉTRICO — la misma orilla para el logotipo que para el «Hablemos.»
   (2026-07-31). Despegada del techo en reposo; al pegarse (.stuck) recupera
   la talla compacta. position:relative ancla el centrado absoluto de los
   apartados.                                                                  */
.hd-in{ position:relative; min-height:var(--hd-h);
  padding:clamp(18px,2.6vh,30px) clamp(24px,3.4vw,60px);
  display:flex; align-items:center; gap:var(--s-5);
  transition:padding var(--t-3) var(--e-out) }
.hd.stuck .hd-in{ padding-block:var(--s-2) }
.hd-in > *{ pointer-events:auto }
/* LOS APARTADOS (rediseño 2026-08-02): fuera las versales de kiosco — la
   fila habla en la voz editorial del sitio: DM Serif en caja alta y baja,
   centrada EN PANTALLA (absoluta sobre .hd-in). El hover es «decir» la
   palabra: pasa a la itálica del acento y gana su punto fucsia, que se
   estampa con un pop (el mismo gesto del menú overlay: una sola gramática
   en todo el sitio). El punto SIEMPRE ocupa su hueco —sólo conmuta
   opacity/scale— para que los hermanos no salten de sitio. El apartado
   activo (aria-current) se queda con la frase dicha: itálica y punto
   puestos — estás aquí. Y la fila conversa: mientras un apartado habla,
   los demás bajan la voz. :active aplasta el respingo — se siente el clic. */
.hd-nav{ position:absolute; left:50%; top:50%; translate:-50% -50%;
  display:flex; align-items:center; gap:var(--s-6) }
.hd-nav a{ position:relative; padding:8px 2px;
  font-family:var(--serif); font-size:1.1875rem; font-weight:400;
  letter-spacing:0; line-height:1.2; color:var(--fg-2); font-synthesis:none;
  transition:color var(--t-2) var(--e-out), translate var(--t-2) var(--e-out) }
.hd-nav a::after{ content:'.'; display:inline-block; color:var(--accent);
  opacity:0; scale:.3; transform-origin:50% 85%;
  transition:opacity var(--t-2) var(--e-out), scale var(--t-3) var(--e-back) }
.hd-nav a:hover,.hd-nav a:focus-visible{
  color:var(--fg); font-style:italic; translate:0 -1px }
.hd-nav a:hover::after,.hd-nav a:focus-visible::after{ opacity:1; scale:1 }
.hd-nav a:active{ translate:0 1px }
.hd-nav a[aria-current]{ color:var(--fg); font-style:italic }
.hd-nav a[aria-current]::after{ opacity:1; scale:1 }
.hd-nav:has(a:hover,a:focus-visible) a:not(:hover,:focus-visible){
  color:var(--fg-muted) }
@media (max-width:819px){ .hd-nav{ display:none } }
@media (prefers-reduced-motion:reduce){
  .hd-nav a,.hd-nav a::after{ transition:color var(--t-2) var(--e-out) }
  .hd-nav a:hover,.hd-nav a:focus-visible,.hd-nav a:active{ translate:0 0 }
}
html.rm .hd-nav a,html.rm .hd-nav a::after{ transition:color var(--t-2) var(--e-out) }
html.rm .hd-nav a:is(:hover,:focus-visible,:active){ translate:0 0 }
/* EL LOGOTIPO COMPLETO (2026-07-31): la marca en la esquina vuelve a
   deletrearse — «SPEACH.» en texto, la voz del wordmark. Como es texto
   hereda el color del documento y en modo tinta se invierte solo. También
   vive fuera del header (sala del menú, pie).                                 */
.brand{
  display:inline-flex; align-items:center; flex:0 0 auto;
  font-family:var(--brand-font); font-size:27px; font-weight:400;
  text-transform:uppercase;
  letter-spacing:0; line-height:1; color:var(--fg); font-synthesis:none;
  padding-bottom:.08em;
}
.brand .dot{ letter-spacing:0 }
/* En la barra el logotipo crece (2026-07-31: un paso más — es la marca la
   que abre la esquina); en el pie y demás salas conserva su talla. El
   2026-08-02 bajó un punto de talla: con la nav en serif la esquina no
   necesita gritar tanto.                                                      */
.hd .brand{ font-size:clamp(31px,2.4vw,38px) }
/* El punto está VIVO (2026-08-02): al pasar por el logotipo, brinca y
   aterriza con squash — un punto que se acaba de estampar. inline-block
   para poder transformarlo; el keyframe termina donde empezó, así que
   soltar el hover a mitad de brinco no deja nada torcido.                     */
.brand .dot{ display:inline-block; transform-origin:50% 90% }
.brand:hover .dot,.brand:focus-visible .dot{
  animation:hd-hop var(--t-5) var(--e-inout) }
@keyframes hd-hop{
  0%{ translate:0 0; scale:1 }
  38%{ translate:0 -.24em; scale:.92 1.1 }
  72%{ translate:0 .02em; scale:1.16 .84 }
  100%{ translate:0 0; scale:1 }
}
@media (prefers-reduced-motion:reduce){
  .brand:hover .dot,.brand:focus-visible .dot{ animation:none } }
html.rm .brand:hover .dot,html.rm .brand:focus-visible .dot{ animation:none }

/* ---- CTA «Hablemos.»: tinta, y el punto hace la ola.
   Hereda de .pill el relleno de tinta (ese es su reposo: nada de rosa
   plano; el único color es el punto). Al hover el punto se desborda: un
   círculo fucsia inunda la píldora desde donde vive el punto (la
   inundación del menú, en miniatura) mientras la etiqueta rueda de
   «Hablemos.» a «¿Empezamos?» (.btn-roll).                                    */
.cta-talk{ position:relative; overflow:hidden; isolation:isolate }
.cta-talk::before{ content:''; position:absolute; z-index:-1;
  right:22px; top:50%; width:12px; height:12px; margin-top:-6px;
  border-radius:var(--r-full); background:var(--accent);
  transform:scale(0); transition:transform var(--t-4) var(--e-out) }
.cta-talk:hover,.cta-talk:focus-visible{
  color:var(--on-accent); border-color:var(--accent) }
.cta-talk:hover::before,.cta-talk:focus-visible::before{ transform:scale(30) }
/* El punto tipográfico cede su fucsia a la ola y se vuelve tinta.             */
.cta-talk .dot{ transition:color var(--t-2) var(--e-out) }
.cta-talk:hover .dot,.cta-talk:focus-visible .dot{ color:var(--on-accent) }
@media (prefers-reduced-motion:reduce){
  .cta-talk::before{ transition:none }
}
html.rm .cta-talk::before{ transition:none }

/* ---- EL GLOBO DE DIÁLOGO: «Hablemos» en el header.
   Rediseño 2026-08-02: el globo ESTÁ ESCRIBIENDO. Fantasma como antes
   (sólo su filete, la burbuja de la marca con la cola en punta), pero
   ahora vive inclinado −2° —un globo recién dicho, no un botón puesto—
   y dentro, tras la palabra, laten tres puntos fucsia: el indicador de
   «escribiendo…» de cualquier chat. La marca te está escribiendo a ti.
   Al hover el globo se endereza con resorte, el fucsia inunda desde
   donde laten los puntos y la etiqueta rueda (.btn-roll) de «Hablemos» a
   la itálica «¿Empezamos?»: la conversación avanza. data-magnet
   (motion.js) lo vuelve magnético: se deja jalar por el puntero.
   No hereda de .pill a propósito: aquélla es la píldora del contenido;
   ésta es una pieza del header y se manda sola.                              */
.hd-cta{
  position:relative; isolation:isolate; overflow:hidden;
  display:inline-flex; align-items:center; justify-content:center;
  margin-left:auto; flex:0 0 auto;
  min-height:42px; padding:9px 20px 10px;
  border:1.5px solid color-mix(in srgb, var(--fg) 32%, transparent);
  border-radius:var(--r-bubble);
  background:transparent; color:var(--fg);
  font-family:var(--serif); font-size:1.0625rem; font-weight:400;
  letter-spacing:0; font-synthesis:none;
  rotate:-2deg; transform-origin:12% 100%;
  transition:rotate var(--t-4) var(--e-back), color var(--t-2) var(--e-out),
    border-color var(--t-2) var(--e-out);
}
/* La ola: nace donde laten los puntos (esquina derecha) y se come la
   burbuja. z-index:-1 con isolation la deja bajo la etiqueta y sobre el fondo. */
.hd-cta::before{ content:''; position:absolute; z-index:-1;
  right:16px; top:50%; width:10px; height:10px; margin-top:-5px;
  border-radius:var(--r-full); background:var(--accent);
  transform:scale(0); transition:transform var(--t-4) var(--e-out) }
.hd-cta:hover,.hd-cta:focus-visible{
  rotate:0deg; color:var(--on-accent); border-color:var(--accent) }
.hd-cta:hover::before,.hd-cta:focus-visible::before{ transform:scale(32) }
.hd-cta:active{ scale:var(--s-press) }
/* El rodillo: las dos frases comparten celda; overflow:hidden del propio
   [data-roll] (.btn-roll §components) recorta la que no habla. line-height
   holgado para que la p de «¿Empezamos?» no pierda la pierna al rodar.        */
.hd-cta [data-roll]{ line-height:1.3 }
.hd-cta-b{ font-style:italic }
/* «Escribiendo…»: tres puntos que laten en ola, con pausa entre ciclos
   (el 55% del keyframe en reposo). Al inundarse el globo se vuelven tinta.
   Sin JS o con movimiento reducido no laten: quedan como puntos suspensivos. */
.hd-tip{ display:inline-flex; align-items:center; gap:3px;
  margin-left:7px; translate:0 .18em }
.hd-tip i{ width:5px; height:5px; border-radius:var(--r-full);
  background:var(--accent);
  transition:background-color var(--t-2) var(--e-out) }
.hd-cta:hover .hd-tip i,.hd-cta:focus-visible .hd-tip i{
  background:var(--on-accent) }
html.js:not(.rm) .hd-tip i{
  animation:hd-tipea 1700ms var(--e-inout) infinite }
html.js:not(.rm) .hd-tip i:nth-child(2){ animation-delay:130ms }
html.js:not(.rm) .hd-tip i:nth-child(3){ animation-delay:260ms }
@keyframes hd-tipea{
  0%,45%,100%{ opacity:.35; translate:0 0 }
  18%{ opacity:1; translate:0 -3px }
}
/* Movimiento reducido: la inclinación es diseño (no se mueve), así que se
   queda — lo que se apaga es el resorte del enderezado, el latido de los
   puntos y la llegada. El globo vive torcido en paz.                          */
@media (prefers-reduced-motion:reduce){
  .hd-cta,.hd-cta::before{ transition:color var(--t-2) var(--e-out) }
  .hd-cta:hover,.hd-cta:focus-visible{ rotate:-2deg }
  html.js:not(.rm) .hd-tip i{ animation:none }
}
html.rm .hd-cta{ transition:color var(--t-2) var(--e-out) }
html.rm .hd-cta:hover,html.rm .hd-cta:focus-visible{ rotate:-2deg }
html.rm .hd-cta::before{ transition:none }

/* LA LLEGADA (2026-08-02): el header entra como llegan los mensajes — cada
   pieza brota con un pop corto (--e-back), escalonada de izquierda a
   derecha, el globo al final desde su cola. Sólo con JS y movimiento
   completo: sin JS nada nace invisible, y en la primera visita corre bajo
   el telón (la obertura ya la hace el vuelo del logotipo). El logotipo NO
   lleva llegada propia: lo trae el telón, o ya está puesto.                   */
@keyframes hd-llega{
  from{ opacity:0; transform:translateY(14px) scale(.82) }
}
html.js:not(.rm) .hd-nav a{
  animation:hd-llega var(--t-5) var(--e-back) both;
  animation-delay:calc(140ms + var(--st-2)*var(--i,1)) }
.hd-nav a:nth-child(1){ --i:1 } .hd-nav a:nth-child(2){ --i:2 }
.hd-nav a:nth-child(3){ --i:3 } .hd-nav a:nth-child(4){ --i:4 }
.hd-nav a:nth-child(n+5){ --i:5 }
html.js:not(.rm) .hd-cta{
  animation:hd-llega var(--t-5) var(--e-back) both;
  animation-delay:calc(140ms + var(--st-2)*6) }

/* ---- Menú overlay: LA INUNDACIÓN.
   Cerrado va con [hidden]: fuera del orden de tabulación y fuera del árbol
   de accesibilidad, sin depender de ninguna clase.
   Coreografía de apertura, todo nacido del punto del wordmark:
     1. speach.js escribe --dot-x/--dot-y (centro del núcleo) por CSSOM — la
        CSP bloquea style= inline, no la manipulación por propiedades.
     2. .mnav-veil (fucsia puro) inunda por clip-path circular con --e-inout.
     3. .mnav-room (la sala en tinta) repite la misma inundación 120ms detrás:
        el borde fucsia va SIEMPRE de avanzada, como marea, y la sala oscura
        llena por detrás. Dos capas, cero blur animado.
     4. Los items suben por máscara (overflow:clip del li), escalonados por
        :nth-child — nada de style="--i:n", la CSP manda (§ st-1).
   El cierre es el mismo viaje al revés: la sala se DRENA hacia el punto con
   --e-in y el velo la persigue; speach.js espera el animationend del velo
   antes de poner [hidden].
   La sala trae data-mode="ink" en el HTML: los tokens de §[data-mode] hacen
   todo el tema oscuro sin una regla extra.                                    */
html:not(.js) .mnav{ display:none }
/* background:none: §[data-mode="ink"] pinta --grad-tinta sobre el elemento
   con el atributo, pero aquí el que se viste es .mnav-room (el que se
   recorta); el contenedor debe dejar ver la página bajo la inundación.        */
.mnav{ position:fixed; inset:0; z-index:var(--z-menu); overflow:clip;
  --dot-x:34px; --dot-y:34px; color:var(--fg); background:none }
.mnav-veil{ position:absolute; inset:0; background:var(--accent);
  clip-path:circle(0px at var(--dot-x) var(--dot-y)); will-change:clip-path }
.mnav-room{ position:absolute; inset:0; overflow-y:auto; overscroll-behavior:contain;
  display:grid; grid-template-rows:auto 1fr auto; gap:var(--s-4);
  padding:var(--s-3) var(--pad) var(--s-5);
  background:var(--grad-tinta);
  clip-path:circle(0px at var(--dot-x) var(--dot-y)); will-change:clip-path }
.mnav:not([hidden]) .mnav-veil{ animation:mn-inunda var(--t-6) var(--e-inout) both }
.mnav:not([hidden]) .mnav-room{ animation:mn-inunda var(--t-6) var(--e-inout) 120ms both }
@keyframes mn-inunda{ to{ clip-path:circle(150% at var(--dot-x) var(--dot-y)) } }
/* Drenado: va DESPUÉS de las reglas de apertura para ganar en cascada.        */
.mnav.is-closing .mnav-room{ animation:mn-drena var(--t-4) var(--e-in) both }
.mnav.is-closing .mnav-veil{ animation:mn-drena var(--t-4) var(--e-in) 100ms both }
@keyframes mn-drena{ from{ clip-path:circle(150% at var(--dot-x) var(--dot-y)) }
  to{ clip-path:circle(0px at var(--dot-x) var(--dot-y)) } }

/* La cabecera de la sala repite el wordmark para que la marca no desaparezca
   bajo la inundación; es decorativa (el diálogo ya se llama «Menú»).          */
.mnav-top{ display:flex; align-items:center; justify-content:space-between;
  min-height:var(--hd-h) }
.mnav-close{ display:inline-flex; align-items:center; gap:var(--s-2);
  min-height:44px; padding-inline:var(--s-3); font-size:var(--t-ui);
  font-weight:var(--wght-ui); color:var(--fg-2) }
.mnav-close:hover{ color:var(--fg) }

.mnav-body{ display:grid; align-content:center; gap:var(--s-6); min-width:0 }
.mnav-list{ display:flex; flex-direction:column; justify-content:center; min-width:0 }
/* El li es la máscara del item: el <a> sube a través de él al abrir.          */
.mnav-list > li{ overflow:clip }
.mnav-item{ display:flex; align-items:baseline; gap:var(--s-4); padding-block:.12em;
  font-family:var(--serif); font-weight:400; line-height:1.15;
  font-size:clamp(1.7rem, min(6vh - .55rem, 9.5vw), 3.4rem);
  letter-spacing:-.008em; font-synthesis:none; color:var(--fg);
  transition:transform var(--t-3) var(--e-out), color var(--t-2) var(--e-out) }
.mnav-item:hover,.mnav-item:focus-visible{ transform:translateX(var(--m-1)) }
/* Conversación entre items: el que habla, en voz alta; el resto baja la voz.  */
.mnav-list:has(.mnav-item:hover,.mnav-item:focus-visible)
  .mnav-item:not(:hover,:focus-visible){ color:var(--fg-muted) }
/* El punto viaja: cada item hoverado «se dice» — pasa a la itálica del acento
   y gana su propio punto fucsia. En la página actual el punto vive fijo:
   estás aquí, la frase ya está dicha.                                         */
.mnav-word::after{ content:'.'; color:var(--accent); opacity:0;
  transition:opacity var(--t-2) var(--e-out) }
.mnav-item:hover .mnav-word,.mnav-item:focus-visible .mnav-word{ font-style:italic }
.mnav-item:hover .mnav-word::after,.mnav-item:focus-visible .mnav-word::after,
.mnav-item[aria-current] .mnav-word::after{ opacity:1 }
.mnav-item[aria-current] .mnav-num{ color:var(--pk-300) }
.mnav-num{ font-size:var(--t-caption); font-weight:var(--wght-ui); color:var(--fg-muted);
  font-variant-numeric:tabular-nums; transition:color var(--t-2) var(--e-out) }
.mnav-item:hover .mnav-num,.mnav-item:focus-visible .mnav-num{ color:var(--pk-300) }

/* Visor: la imagen de cada destino, en el B/N del deck, sólo donde hay
   pantalla y puntero de verdad. speach.js marca .is-on; el fundido y el
   ken-burns son de aquí. data-pointer-xy (motion.js) escribe --mx/--my y la
   imagen deriva unos px tras el puntero — translate va aparte de transform,
   así no pelea con el scale del fundido.                                      */
.mnav-view{ display:none }
@media (min-width:1024px) and (hover:hover){
  .mnav-body{ grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
    align-items:center }
  .mnav-view{ display:block; position:relative; overflow:clip;
    aspect-ratio:4/5; width:min(100%, 26rem); max-height:60vh;
    justify-self:center; border-radius:var(--r-md) }
  .mnav-view img{ position:absolute; inset:0; width:100%; height:100%;
    object-fit:cover; opacity:0; transform:scale(1.07);
    filter:grayscale(1) contrast(1.06) brightness(1.03);
    translate:calc((var(--mx,50%) - 50%)/-16) calc((var(--my,50%) - 50%)/-16);
    transition:opacity var(--t-4) var(--e-out), transform var(--t-7) var(--e-out) }
  .mnav-view img.is-on{ opacity:1; transform:scale(1) }
}

.mnav-foot{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:var(--s-4); padding-top:var(--s-5); border-top:1px solid var(--line);
  font-size:var(--t-body-s); color:var(--fg-muted) }

/* Entrada escalonada. --li por :nth-child (la CSP bloquearía style="--li:n"). */
.mnav-list > li:nth-child(1){ --li:1 } .mnav-list > li:nth-child(2){ --li:2 }
.mnav-list > li:nth-child(3){ --li:3 } .mnav-list > li:nth-child(4){ --li:4 }
.mnav-list > li:nth-child(5){ --li:5 } .mnav-list > li:nth-child(6){ --li:6 }
.mnav-list > li:nth-child(7){ --li:7 } .mnav-list > li:nth-child(8){ --li:8 }
.mnav-list > li:nth-child(n+9){ --li:9 }
.mnav:not([hidden]) .mnav-list > li > a{
  animation:mn-sube var(--t-5) var(--e-out) both;
  animation-delay:calc(300ms + var(--st-1)*var(--li,1)) }
@keyframes mn-sube{ from{ transform:translateY(108%) } to{ transform:none } }
.mnav:not([hidden]) :is(.mnav-top,.mnav-foot,.mnav-view){
  animation:mn-fundido var(--t-6) var(--e-out) 380ms both }
@keyframes mn-fundido{ from{ opacity:0 } to{ opacity:1 } }

/* Movimiento reducido: sin inundación, sin marea, sin subidas — el menú es un
   fundido corto y el cierre otro. El velo no llega a existir.                 */
@media (prefers-reduced-motion:reduce){
  .mnav-veil{ display:none }
  .mnav-room{ clip-path:none }
  .mnav:not([hidden]) .mnav-room{ animation:mn-fundido var(--t-2) linear both }
  .mnav.is-closing .mnav-room{ animation:mn-fundido-sale var(--t-2) linear both }
  .mnav:not([hidden]) .mnav-list > li > a{ animation:none }
  .mnav:not([hidden]) :is(.mnav-top,.mnav-foot,.mnav-view){ animation:none }
  .mnav-view img{ translate:none }
}
@keyframes mn-fundido-sale{ from{ opacity:1 } to{ opacity:0 } }
/* Con el overlay abierto el fondo no se desplaza.                             */
html.menu-open,html.menu-open body{ overflow:hidden }
/* --------------------------------------- HERO «EL CONMUTADOR» (sólo el home) --
   Rediseño 2026-08-03 (sustituye a «LA PANTALLA», que se fue entera). El hero
   ya no es un cartel: es un INSTRUMENTO. Un fader que el visitante arrastra de
   «lo que dices» a «lo que entienden» y, mientras lo arrastra, una cabeza
   lectora fucsia barre el tablero: cada columna de letras VOLTEA como un panel
   de aeropuerto hasta recomponer la frase, y la tarjeta de la campaña real —a
   la derecha— pasa de gris apagado a color vivo bajo esa misma cabeza. Cinco
   canales, cinco marcas de verdad. La tesis del sitio («no hacemos logos,
   hacemos que te entiendan») convertida en control deslizante.

   POR QUÉ LA REJILLA ES FIJA: las dos frases del canal se reparten en la MISMA
   matriz de ROWS×--cols paneles, así que cada casilla tiene su letra de «dice»
   y su letra de «entienden». Como el umbral de volteo es la COLUMNA y no la
   posición en el texto, el frente de volteo es una recta vertical — y por eso
   la cabeza lectora puede ir clavada encima, y el mando del fader justo arriba
   en la misma abscisa: se ve que el pulgar arrastra la línea que voltea las
   letras. El alto de la letra sale de --cw (ancho real de un panel, lo mide
   conmutador.js): con la barra de scroll de por medio 100vw miente.

   TODO SE MUEVE CON --cp (0→1, lo escribe el módulo por CSSOM cada cuadro).
   Nada de `left` ni `width` animados: la cabeza, el mando y el borde de la
   tarjeta son cajas al 100% del ancho movidas con `translate` porcentual — un
   porcentaje de su propio ancho es exactamente --cp × el ancho del panel, y
   eso lo resuelve la compositora sin tocar el layout.

   SIN JS el hero es la lista .cnm-src: las cinco traducciones legibles, que es
   el contenido de verdad. Nada nace invisible.                                */
.cnm{ position:relative; overflow:clip; min-height:100svh;
  display:grid; align-content:center; --cp:0;
  padding-block:calc(var(--hd-h) + clamp(14px,4vh,52px)) clamp(24px,5vh,64px) }

/* La sala: retícula de consola apenas insinuada y un foco que viaja con la
   cabeza lectora (translate, no background-position: el foco es grande y
   repintarlo por cuadro se nota).                                            */
.cnm-red{ position:absolute; inset:0; z-index:var(--z-base); pointer-events:none;
  background:
    repeating-linear-gradient(to right,
      color-mix(in srgb, var(--fg) 5%, transparent) 0 1px, transparent 1px 72px),
    repeating-linear-gradient(to bottom,
      color-mix(in srgb, var(--fg) 5%, transparent) 0 1px, transparent 1px 72px);
  -webkit-mask-image:radial-gradient(115% 85% at 50% 42%, #000 18%, transparent 76%);
          mask-image:radial-gradient(115% 85% at 50% 42%, #000 18%, transparent 76%) }
.cnm-foco{ position:absolute; z-index:var(--z-base); top:0; bottom:0; pointer-events:none;
  left:50%; width:min(84vw,980px); margin-left:min(-42vw,-490px);
  background:radial-gradient(48% 40% at 50% 50%,
    color-mix(in srgb, var(--accent) 26%, transparent), transparent 72%);
  translate:calc((var(--cp) - .5) * 100vw) 0;
  opacity:calc(.22 + var(--cp) * .78) }

/* Dos columnas y punto. La izquierda es su propia rejilla: si la tesis, el
   panel y los canales fueran filas hermanas, la tarjeta —que es más alta que
   las tres juntas— les repartiría su sobrante en los huecos.                */
.cnm-in{ position:relative; z-index:var(--z-nav-local);
  display:grid; align-items:center;
  gap:clamp(28px,4vw,76px);
  grid-template-columns:minmax(0,1fr) clamp(184px,19vw,264px) }
.cnm-izq{ display:grid; align-content:center; gap:clamp(20px,3.4vh,40px) }

/* Antes de que el módulo monte —y si nunca monta— manda la lista.            */
.cnm:not(.cnm-on) :is(.cnm-panel,.cnm-carta,.cnm-bajo){ display:none }
.cnm:not(.cnm-on) .cnm-in{ grid-template-columns:minmax(0,1fr) }
.cnm:not(.cnm-on) .cnm-canal{ display:none }
.cnm-on .cnm-src{ display:none }

/* ------------------------------------------------------------- LA TESIS ---- */
.cnm-top{ display:flex; align-items:flex-end; justify-content:space-between;
  gap:var(--s-5); flex-wrap:wrap }
.cnm-tesis{ margin:0; max-width:26ch;
  font-family:var(--serif); font-size:var(--t-h3); line-height:var(--lh-tight);
  letter-spacing:var(--ls-h3); color:var(--fg-2) }
.cnm-tesis em{ color:var(--fg) }
.cnm-canal{ margin:0; font-family:var(--mono); font-size:var(--t-caption);
  letter-spacing:.12em; color:var(--fg-muted); white-space:nowrap }
.cnm-n{ color:var(--accent-fg) }

/* ---------------------------------------------------- EL PANEL Y SU CABEZA -- */
.cnm-panel{ position:relative }
.cnm-cabeza{ position:absolute; left:0; top:0; bottom:0; width:100%;
  z-index:var(--z-raised); pointer-events:none; translate:calc(var(--cp) * 100%) 0 }
.cnm-cabeza::before{ content:''; position:absolute; left:0; top:0; bottom:0; width:2px;
  translate:-1px 0; border-radius:1px;
  background:linear-gradient(to bottom, transparent,
    var(--accent) 14%, var(--accent) 88%, transparent);
  box-shadow:0 0 20px 2px color-mix(in srgb, var(--accent) 55%, transparent);
  opacity:.3; transition:opacity var(--t-3) var(--e-out) }
.cnm.is-drag .cnm-cabeza::before{ opacity:1 }

/* ------------------------------------------------------------- EL FADER ---- */
.cnm-fader{ display:grid; gap:clamp(6px,1vh,12px) }
.cnm-eti{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--s-4);
  font-size:var(--t-eyebrow); font-weight:var(--wght-ui);
  text-transform:uppercase; letter-spacing:var(--ls-eyebrow); color:var(--fg) }
/* Las dos voces se turnan el foco: la que manda es la que se lee.            */
/* El suelo es .45 y no menos: por debajo, la etiqueta apagada (12 px en
   versales) se cae del 4.5:1 de la §1.4.3. */
.cnm-lbl-a{ opacity:calc(.45 + (1 - var(--cp)) * .55) }
.cnm-lbl-b{ opacity:calc(.45 + var(--cp) * .55) }
.cnm-lbl-b::after{ content:'.'; color:var(--accent) }
.cnm-guia{ font-family:var(--mono); text-transform:none; letter-spacing:.04em;
  color:var(--fg-muted); opacity:.9; transition:opacity var(--t-4) var(--e-out) }
.cnm.is-mano .cnm-guia{ opacity:0 }

/* El riel es un botón real: enfocable, con teclado y con 36 px de alto de
   zona sensible aunque la línea pintada sea de 2 px.                         */
.cnm-track{ position:relative; display:block; width:100%; height:36px;
  padding:0; border:0; background:none; cursor:ew-resize; touch-action:none;
  border-radius:var(--r-xs) }
.cnm-track::before{ content:''; position:absolute; left:0; right:0; top:50%; height:2px;
  translate:0 -50%; border-radius:1px;
  background:color-mix(in srgb, var(--fg) 17%, transparent) }
.cnm-riel{ position:absolute; left:0; top:50%; width:100%; height:2px; translate:0 -50%;
  border-radius:1px; background:var(--accent);
  transform-origin:0 50%; transform:scaleX(var(--cp)) }
/* Escala del instrumento: ocho marcas, sin números — se leen, no se cuentan. */
.cnm-tics{ position:absolute; left:0; right:0; bottom:3px; height:5px; pointer-events:none;
  background:repeating-linear-gradient(to right,
    color-mix(in srgb, var(--fg) 26%, transparent) 0 1px,
    transparent 1px calc(100% / 8)) }

.cnm-carro{ position:absolute; inset:0; pointer-events:none;
  translate:calc(var(--cp) * 100%) 0 }
.cnm-knob{ position:absolute; left:0; top:50%; translate:-50% -50%;
  width:clamp(13px,1.1vw,17px); height:clamp(26px,2.4vw,34px); border-radius:5px;
  background:var(--fg);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 65%, transparent),
             0 10px 24px color-mix(in srgb, var(--pk-900) 55%, transparent);
  transition:scale var(--t-2) var(--e-out), box-shadow var(--t-2) var(--e-out) }
/* La muesca del mando: sin ella el rectángulo blanco no se lee como pieza.   */
.cnm-knob::before{ content:''; position:absolute; left:3px; right:3px; top:50%; height:1px;
  translate:0 -50%; background:color-mix(in srgb, var(--ink-950) 45%, transparent) }
.cnm.is-drag .cnm-knob{ scale:1.14;
  box-shadow:0 0 0 2px var(--accent),
             0 10px 30px color-mix(in srgb, var(--accent) 45%, transparent) }
/* El foco lo pinta el anillo global de la casa sobre el riel entero: es el
   control, no el mando, lo que se enfoca. */
/* Late hasta que alguien lo toca: es el único gesto que hay que descubrir.   */
@keyframes cnm-late{
  0%{ box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent) }
  70%,100%{ box-shadow:0 0 0 16px transparent } }
html.js:not(.rm) .cnm:not(.is-mano) .cnm-knob::after{ content:''; position:absolute;
  inset:0; border-radius:inherit; animation:cnm-late 2.4s var(--e-out) infinite }
.cnm-pct{ position:absolute; left:0; top:calc(100% + 3px); translate:-50% 0;
  font-family:var(--mono); font-size:var(--t-caption); letter-spacing:.04em;
  color:var(--accent-fg); white-space:nowrap;
  opacity:.85; transition:opacity var(--t-2) var(--e-out) }
.cnm.is-drag .cnm-pct{ opacity:1 }

/* ----------------------------------------------------------- EL TABLERO ---- */
.cnm-board{ position:relative; margin-top:clamp(16px,3vh,34px);
  display:grid; gap:calc(var(--cw,52px) * .05); cursor:pointer }
.cnm-fila{ display:grid; grid-template-columns:repeat(var(--cols,16), minmax(0,1fr)) }
.cnm-c{ position:relative; display:grid; place-items:center;
  height:calc(var(--cw,52px) * 1.12); font-size:calc(var(--cw,52px) * 1.02);
  font-weight:700; line-height:1; letter-spacing:0; font-synthesis:none;
  color:color-mix(in srgb, var(--fg) 40%, transparent);
  perspective:600px;
  transition:color var(--t-3) var(--e-out) }
.cnm-c.on{ color:var(--fg) }
.cnm-c > i{ display:block; font-style:normal; transform-origin:50% 50% }
/* La costura del panel. Discreta en reposo; se enciende en fucsia justo en la
   casilla que está volteando — el ruido visual del tablero de vuelos.        */
.cnm-c::after{ content:''; position:absolute; left:14%; right:14%; top:50%; height:1px;
  translate:0 -.5px; background:color-mix(in srgb, var(--fg) 30%, transparent);
  opacity:.42; transition:background-color var(--t-2) linear, opacity var(--t-2) linear }
.cnm-c.vac::after{ opacity:0 }
.cnm-c.f::after{ background:var(--accent); opacity:1 }
/* Tres vueltas de 300 ms. conmutador.js cambia el glifo en los tres instantes
   en que la lámina está de canto (45 / 133 / 220 ms = 15 / 44 / 73 %): el
   cambio nunca se ve ocurrir, que es justo el truco del panel mecánico.      */
@keyframes cnm-flap{
  0%{ transform:rotateX(0deg) }
  15%{ transform:rotateX(-82deg) }
  30%{ transform:rotateX(0deg) }
  44%{ transform:rotateX(-82deg) }
  58%{ transform:rotateX(0deg) }
  73%{ transform:rotateX(-82deg) }
  88%,100%{ transform:rotateX(0deg) } }
html.js:not(.rm) .cnm-c.f > i{ animation:cnm-flap 300ms var(--e-inout) }

/* ---------------------------------------------------------- LOS CANALES ---- */
.cnm-bajo{ display:flex; flex-wrap:wrap; align-items:center;
  gap:var(--s-3) var(--s-5) }
.cnm-strip{ display:flex; flex-wrap:wrap; gap:var(--s-2); list-style:none; margin:0; padding:0 }
.cnm-ch{ display:inline-flex; align-items:center; gap:8px; min-height:44px; padding:8px 16px;
  border-radius:var(--r-full); background:transparent; color:var(--fg-muted);
  border:1px solid color-mix(in srgb, var(--fg) 16%, transparent);
  font-family:var(--mono); font-size:var(--t-caption); letter-spacing:.08em;
  transition:color var(--t-2) var(--e-out), border-color var(--t-2) var(--e-out),
             background-color var(--t-2) var(--e-out), transform var(--t-2) var(--e-out) }
.cnm-ch > span{ font-family:var(--font); font-weight:var(--wght-ui);
  font-size:var(--t-body-s); letter-spacing:var(--ls-ui) }
.cnm-ch:hover{ color:var(--fg); border-color:color-mix(in srgb, var(--fg) 42%, transparent);
  transform:translateY(-2px) }
.cnm-ch[aria-pressed="true"]{ background:var(--accent); border-color:var(--accent);
  color:var(--on-accent) }

/* ---------------------------------------------------------- LA TARJETA ----
   El caso real en su formato real: vertical, como salió a la calle. El velo
   es lo NO traducido —gris, apagado, con línea de barrido— y se recorta con
   la misma --cp, así que la cabeza lectora del tablero y el corte de la
   tarjeta son la misma línea recorriendo el hero.                            */
.cnm-carta{ display:grid; gap:var(--s-4) }
.cnm-pila{ position:relative; aspect-ratio:9/16; border-radius:var(--r-md);
  overflow:clip; isolation:isolate; background:var(--surface);
  box-shadow:0 34px 80px color-mix(in srgb, var(--ink-950) 72%, transparent) }
.cnm-im,.cnm-vid{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0; transition:opacity var(--t-5) var(--e-out) }
.cnm-im.on{ opacity:1 }
.cnm-vid{ z-index:1 }
.cnm.is-vivo .cnm-vid{ opacity:1 }
.cnm-velo{ position:absolute; inset:0; z-index:2; pointer-events:none;
  clip-path:inset(0 0 0 calc(var(--cp) * 100%));
  background:
    repeating-linear-gradient(to bottom,
      color-mix(in srgb, var(--ink-950) 30%, transparent) 0 2px, transparent 2px 5px),
    color-mix(in srgb, var(--ink-950) 40%, transparent);
  -webkit-backdrop-filter:grayscale(1) contrast(.7) brightness(.66);
          backdrop-filter:grayscale(1) contrast(.7) brightness(.66) }
@supports not ((backdrop-filter:grayscale(1)) or (-webkit-backdrop-filter:grayscale(1))){
  .cnm-velo{ background:color-mix(in srgb, var(--ink-950) 76%, transparent) }
}
.cnm-corte{ position:absolute; inset:0; z-index:3; width:100%; pointer-events:none;
  translate:calc(var(--cp) * 100%) 0 }
.cnm-corte::before{ content:''; position:absolute; left:0; top:0; bottom:0; width:2px;
  translate:-1px 0; background:var(--accent);
  box-shadow:0 0 18px 3px color-mix(in srgb, var(--accent) 65%, transparent);
  opacity:calc(1 - var(--cp)) }

.cnm-firma{ position:absolute; left:var(--pad); bottom:clamp(16px,3vh,36px);
  z-index:var(--z-nav-local); margin:0;
  font-family:var(--mono); font-size:var(--t-caption); letter-spacing:.08em;
  color:var(--fg-muted) }
.cnm-pie{ display:grid; gap:var(--s-2); justify-items:start }
.cnm-credito{ display:grid; gap:1px; text-decoration:none }
.cnm-marca{ font-family:var(--serif); font-size:var(--t-h4); color:var(--fg);
  transition:color var(--t-2) var(--e-out) }
.cnm-credito:hover .cnm-marca{ color:var(--accent-fg) }
.cnm-giro{ font-size:var(--t-caption); color:var(--fg-muted) }
.cnm-cta{ align-self:start }
.cnm.is-full .cnm-cta{ background:var(--accent); border-color:var(--accent);
  color:var(--on-accent) }
.cnm-eso{ font-family:var(--serif); font-style:italic; font-size:var(--t-body);
  color:var(--fg-2) }
html.js .cnm-eso{ opacity:0; translate:0 6px;
  transition:opacity var(--t-4) var(--e-out), translate var(--t-4) var(--e-out) }
html.js .cnm.is-full .cnm-eso{ opacity:1; translate:none }

/* ----------------------------------------------------- EL HERO SIN JAVASCRIPT
   No es un mensaje de error ni un cartel de repuesto: son las cinco
   traducciones, que es exactamente lo que el instrumento enseña.             */
.cnm-src{ grid-column:1/-1; list-style:none; margin:0; padding:0;
  display:grid; gap:clamp(16px,2.6vh,30px) }
.cnm-src > li{ display:grid; gap:4px; max-width:34ch }
.cnm-dice{ font-size:var(--t-h4); color:var(--fg-muted) }
.cnm-dice::before{ content:'Dices: '; color:var(--fg-muted); opacity:.7 }
.cnm-oyen{ font-size:var(--t-h2); font-weight:var(--wght-h); line-height:var(--lh-tight);
  letter-spacing:var(--ls-h2); color:var(--fg) }

/* ----------------------------------------------------------- LA SALIDA -----
   El instrumento se retira hacia arriba fundiéndose mientras el capítulo 01
   lo tapa: la superficie es continua, no hay corte.                          */
@supports (animation-timeline: scroll()){
  html.js:not(.rm) .cnm-in{
    animation:cnm-se-va var(--e-lin) both;
    animation-timeline:scroll(root block); animation-range:0svh 94svh }
  html.js:not(.rm) .cnm-foco{
    animation:cnm-se-apaga var(--e-lin) both;
    animation-timeline:scroll(root block); animation-range:0svh 94svh }
}
@keyframes cnm-se-va{ to{ translate:0 -11svh; opacity:0 } }
@keyframes cnm-se-apaga{ to{ opacity:0 } }

@media (max-width:900px){
  .cnm-in{ grid-template-columns:minmax(0,1fr) }
  .cnm-carta{ grid-template-columns:clamp(96px,26vw,148px) minmax(0,1fr);
    align-items:center; gap:var(--s-4) }
  .cnm-tesis{ font-size:var(--t-h4) }
}
@media (max-width:560px){
  .cnm-guia{ display:none }
  .cnm-ch{ padding:8px 12px }
  .cnm-ch > span{ font-size:var(--t-caption) }
}

/* Movimiento reducido: el fader SIGUE funcionando —es un control, no un
   adorno—. Se van el aleteo, el latido del mando y la salida por scroll.     */
@media (prefers-reduced-motion:reduce){
  .cnm-c > i,.cnm-knob::after,.cnm-in,.cnm-foco{ animation:none }
}
html.rm :is(.cnm-c > i,.cnm-knob::after,.cnm-in,.cnm-foco){ animation:none }

/* LA ESTELA. Mover el puntero por el hero va sembrando la familia de objetos
   del sitio (la ballena, el megáfono, la mariposa…) como stickers troquelados:
   borde blanco, sombra teñida de --pk-900 y un pop de rebote suave.
   Brota uno cada ~120px de recorrido (motion.js §estela) y muere solo a los
   --t-7; si nace cerca de la esfera, la deriva de salida apunta a su centro y
   el encogimiento aprieta: el líquido se lo traga. El motor sólo escribe los
   custom props; la vida entera del sticker es de este bloque.
   La capa entra ANTES del wrap en el DOM con el MISMO z-raised: por orden de
   documento pinta bajo el wordmark, y por z-index sobre la esfera. Tiene que
   ser POR ENCIMA del video: su caja anima siempre (stacking context) y eso
   aísla el multiply — las esquinas del clip son blanco OPACO, no transparencia,
   y un sticker por debajo desaparecería tras un borde invisible. Al frente el
   tragado se lee igual: se encoge hacia el centro del vidrio mientras muere.   */
.trail-capa{ position:absolute; inset:0; overflow:clip; pointer-events:none;
  z-index:var(--z-raised) }
.trail-stk{ position:absolute; left:0; top:0; width:var(--stk-w,140px); height:auto;
  opacity:0;
  filter:drop-shadow(2px 0 0 var(--n-0)) drop-shadow(-2px 0 0 var(--n-0))
         drop-shadow(0 2px 0 var(--n-0)) drop-shadow(0 -2px 0 var(--n-0))
         drop-shadow(0 14px 22px rgba(89,6,93,.22)) }
.trail-stk.go{ will-change:transform,opacity;
  animation:stk-vive var(--t-7) var(--e-out) var(--stk-d,0ms) both }
/* Un solo keyframe con tres actos: pop suave, reposo, y salida con deriva.
   El back de la entrada es más tibio que --e-back: su 1.56 a esta escala
   (nacer a .2 y clavar en 192ms) se sentía como un golpe; aquí el sticker
   nace a media talla y asienta en ~290ms con un rebote apenas. --stk-d lo
   escribe motion.js cuando un mismo frame siembra varios: entran en cascada.
   Todos los pasos repiten la MISMA lista de funciones
   (translate·translate·rotate·scale): así el navegador interpola en la
   compositora y el -50% centra al sticker en su punto.                        */
@keyframes stk-vive{
  0%{ opacity:0; animation-timing-function:cubic-bezier(.3,1.22,.46,1);
      transform:translate(var(--stk-x),var(--stk-y)) translate(-50%,-50%)
        rotate(var(--stk-r)) scale(.55) }
  12%{ opacity:1 }
  24%{ animation-timing-function:var(--e-inout);
       transform:translate(var(--stk-x),var(--stk-y)) translate(-50%,-50%)
         rotate(var(--stk-r)) scale(1) }
  58%{ opacity:1; animation-timing-function:var(--e-in);
       transform:translate(var(--stk-x),var(--stk-y)) translate(-50%,-50%)
         rotate(var(--stk-r)) scale(1) }
  100%{ opacity:0;
        transform:translate(calc(var(--stk-x) + var(--stk-dx,0px)),calc(var(--stk-y) + var(--stk-dy,-26px)))
          translate(-50%,-50%) rotate(calc(var(--stk-r) + var(--stk-dr,8deg))) scale(var(--stk-se,.7)) }
}
html.rm .trail-capa{ display:none }

/* -------------------------------------------- BOTONES, PÍLDORAS Y LINKS ----- */
.pill{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--s-2);
  min-height:44px; padding:12px 24px; border-radius:var(--r-full);
  font-size:var(--t-ui); font-weight:var(--wght-ui); letter-spacing:var(--ls-ui);
  background:var(--fg); color:var(--bg); border:1.5px solid var(--fg);
  transition:transform var(--t-2) var(--e-out), background-color var(--t-2) var(--e-out),
             color var(--t-2) var(--e-out), border-color var(--t-2) var(--e-out);
}
.pill:hover{ transform:translateY(-2px) }
.pill:active{ transform:scale(var(--s-press)) }
.pill.ghost{ background:transparent; color:var(--fg) }
.pill.ghost:hover{ background:var(--fg); color:var(--bg) }
/* Relleno fucsia con etiqueta tinta: 5.94:1. Blanco sobre --pk-500 (3.15:1)
   está prohibido por §1.4.                                                    */
.pill.accent{ background:var(--accent); color:var(--on-accent); border-color:var(--accent) }
.pill.accent:hover{ background:var(--pk-600); border-color:var(--pk-600) }
/* .sm cambia el relleno y el cuerpo, nunca el alto: 38 px incumplía el
   objetivo táctil de 44 px de §8.1·5 en cada botón que la usara.             */
.pill.sm{ min-height:44px; padding:8px 16px; font-size:var(--t-caption) }
.pill.lg{ padding:16px 32px; font-size:var(--t-h4) }
.pill[disabled],.pill[aria-disabled="true"]{ background:var(--disabled-bg); color:var(--disabled-fg);
  border-color:var(--disabled-bg); pointer-events:none }

/* Etiqueta que rota al hover: dos copias apiladas, la 2ª aria-hidden.         */
.btn-roll [data-roll]{ display:inline-grid; overflow:hidden }
.btn-roll [data-roll] > *{ grid-area:1/1; transition:transform var(--t-3) var(--e-out) }
.btn-roll [data-roll] > *:last-child{ transform:translateY(100%) }
.btn-roll:hover [data-roll] > *:first-child,
.btn-roll:focus-visible [data-roll] > *:first-child{ transform:translateY(-100%) }
.btn-roll:hover [data-roll] > *:last-child,
.btn-roll:focus-visible [data-roll] > *:last-child{ transform:none }

/* Subrayado que entra por la izquierda y sale por la derecha.                 */
.txt-link,.lnk{ position:relative; display:inline-flex; align-items:center; gap:var(--s-2);
  font-weight:var(--wght-ui); transition:gap var(--t-3) var(--e-out), color var(--t-2) var(--e-out) }
.txt-link::after,.lnk::after{ content:''; position:absolute; inset:auto 0 -3px 0; height:1.5px;
  background:currentColor; transform:scaleX(0); transform-origin:100% 50%;
  transition:transform var(--t-3) var(--e-out) }
.txt-link::after{ transform:scaleX(1); transform-origin:0 50%; height:2px }
.txt-link:hover,.lnk:hover{ color:var(--accent-fg) }
.txt-link:hover,.txt-link:focus-visible{ gap:var(--s-3) }
.lnk:hover::after,.lnk:focus-visible::after{ transform:scaleX(1); transform-origin:0 50% }

.round-btn{ display:inline-grid; place-items:center; width:54px; height:54px;
  border-radius:var(--r-full); border:1.5px solid var(--fg); color:var(--fg);
  background:transparent; transition:transform var(--t-2) var(--e-out),
  background-color var(--t-2) var(--e-out), color var(--t-2) var(--e-out) }
.round-btn:hover{ background:var(--fg); color:var(--bg); transform:translateY(-2px) }

/* Iconos del sprite. Compensación óptica de grosor por tamaño (§7.3).         */
.ico{ width:var(--ico,24px); height:var(--ico,24px); fill:none; stroke:currentColor;
  stroke-width:1.75; flex:none }
.ico--16{ --ico:16px; stroke-width:2 } .ico--24{ --ico:24px }
.ico--32{ --ico:32px; stroke-width:1.5 } .ico--48{ --ico:48px; stroke-width:1.25 }

/* Chip sobre imagen: tinta sobre foto, valores fijos por diseño (el chip vive
   sobre arte, no sobre el fondo de la sección). El reposo es tinta OPACA —el
   contraste no depende del cristal—; con soporte de backdrop-filter pasa a
   vidrio de tinta con el filo de luz de --sh-inset. Peor caso medido: blanco
   sobre tinta al 80% sobre el cielo rosa del cierre ≈ 6.5:1 ✓AA.              */
.chip{ display:inline-flex; align-items:center; gap:var(--s-1);
  background:var(--ink-950); color:var(--n-0); border-radius:var(--r-full);
  padding:6px 13px; font-size:var(--t-caption); font-weight:var(--wght-ui);
  text-transform:uppercase; letter-spacing:.08em }
@supports ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .chip{ background:var(--glass-ink); box-shadow:var(--sh-inset);
    -webkit-backdrop-filter:var(--fx-glass); backdrop-filter:var(--fx-glass) }
}

/* ------------------------------------------------------- CHIPS DE FILTRO ---- */
.filters{ display:flex; flex-wrap:wrap; gap:var(--s-2) var(--s-3) }
.filters button{ min-height:44px; padding:8px 16px; border-radius:var(--r-full);
  border:1.5px solid var(--line-strong); color:var(--fg-2);
  font-size:var(--t-body-s); font-weight:var(--wght-ui);
  transition:border-color var(--t-2) var(--e-out), background-color var(--t-2) var(--e-out),
             color var(--t-2) var(--e-out) }
.filters button:hover{ border-color:var(--fg) }
/* El estado activo vive en aria-pressed, nunca en una clase.                  */
.filters button[aria-pressed="true"]{ background:var(--fg); border-color:var(--fg); color:var(--bg) }

/* --- CAMPOS: línea inferior + etiqueta flotante real ------------------------ */
.field{ position:relative; padding-top:var(--s-5) }
.field input,.field textarea,.field select{
  width:100%; min-height:44px; padding:var(--s-3) 2px;
  background:transparent; color:var(--fg); border:0;
  border-bottom:1.5px solid var(--line-ctl);
  font-size:var(--t-body); border-radius:0;
  transition:border-color var(--t-2) var(--e-out);
}
.field textarea{ min-height:120px; resize:vertical; field-sizing:content }
.field select{ appearance:none; cursor:pointer }
.field input:hover,.field textarea:hover,.field select:hover{ border-bottom-color:var(--fg-2) }
.field :focus-visible{ outline-offset:2px }
.field-label{ position:absolute; left:2px; top:var(--s-5); padding-top:var(--s-3);
  color:var(--fg-muted); font-size:var(--t-body); pointer-events:none;
  transform-origin:0 0; transition:transform var(--t-2) var(--e-out), color var(--t-2) var(--e-out) }
/* :has() nos hace independientes del orden de label/campo en el HTML.         */
.field:has(:focus) .field-label,
.field:has(input:not(:placeholder-shown)) .field-label,
.field:has(textarea:not(:placeholder-shown)) .field-label,
.field:has(select:not([data-empty])) .field-label{ transform:translateY(-1.5em) scale(.78) }
.field:has(:focus) .field-label{ color:var(--accent-fg) }
.field:has(:focus) input,.field:has(:focus) textarea,.field:has(:focus) select{ border-bottom-color:var(--accent) }
.field-hint{ margin-top:var(--s-2); font-size:var(--t-caption); color:var(--fg-muted) }
.field-err{ display:flex; align-items:center; gap:var(--s-2); margin-top:var(--s-2);
  font-size:var(--t-caption); font-weight:var(--wght-ui); color:var(--er) }
.field-err .ico{ --ico:16px; flex:none }
[data-mode="ink"] .field-err{ color:var(--er-ink) }
.field:has([aria-invalid="true"]) input,.field:has([aria-invalid="true"]) textarea,
.field:has([aria-invalid="true"]) select{ border-bottom-color:var(--er) }
/* Casillas y radios nativos, con el fucsia de marca.                          */
.check{ display:flex; align-items:flex-start; gap:var(--s-3); font-size:var(--t-body-s);
  line-height:var(--lh-lead); cursor:pointer }
.check input{ accent-color:var(--accent); width:20px; height:20px; margin-top:2px; flex:none }

/* ------------------------------------------------------------------ FOOTER -- */
.ft{ padding-block:var(--sec-y) var(--s-6); border-top:1px solid var(--line) }
.ft-grid{ display:flex; justify-content:space-between; align-items:flex-end; gap:var(--s-6);
  flex-wrap:wrap }
/* Nombres de sección del footer: uno de los cinco permisos de la serif itálica. */
.ft-grid h2,.ft-grid h3{ font-family:var(--serif); font-style:italic; font-weight:400 }
.ft-social{ display:flex; flex-wrap:wrap; gap:var(--s-5) }
.ft-social a{ display:inline-flex; align-items:center; min-height:44px;
  font-size:var(--t-ui); font-weight:var(--wght-ui); color:var(--fg-muted);
  transition:color var(--t-2) var(--e-out) }
/* Objetivo táctil de §8.1·5. Los enlaces sueltos de listas de navegación
   medían 26 px de alto; con inline-flex el min-height sí manda.               */
.ft .flow > li > .lnk,.mnav-foot a,.ft-bottom a{ min-height:44px }
.ft-social a:hover{ color:var(--fg) }
.ft-bottom{ display:flex; justify-content:space-between; align-items:center; gap:var(--s-4);
  flex-wrap:wrap; margin-top:var(--s-8); padding-top:var(--s-5); border-top:1px solid var(--line);
  font-size:var(--t-caption); color:var(--fg-muted) }

/* --- COMPONENTES HEREDADOS, retokenizados. Los usa el HTML que este build no
   reescribe editorialmente (§5.6, D11). ------------------------------------- */
.card,.val-card{ border:1px solid var(--line); border-radius:var(--r-md);
  padding:clamp(20px,2.4vw,30px); background:var(--bg);
  transition:border-color var(--t-3) var(--e-out), transform var(--t-3) var(--e-out) }
.val-card:hover{ border-color:var(--accent); transform:translateY(-4px) }
.val-card h3{ font-size:var(--t-h4); margin-bottom:var(--s-2) }
.val-card p{ color:var(--fg-2) }

/* Caso: marco-burbuja, chip arriba-izquierda, meta debajo del marco.          */
.work-card{ display:block }
.work-card .frame{ position:relative; overflow:hidden; border-radius:var(--r-bubble);
  aspect-ratio:16/11; background:var(--surface-2) }
.work-card .frame img{ width:100%; height:100%; object-fit:cover;
  filter:brightness(var(--img-bright)); transition:transform var(--t-7) var(--e-out) }
.work-card:hover .frame img{ transform:scale(var(--s-zoom)) }
.work-card .chip{ position:absolute; top:var(--s-4); left:var(--s-4); z-index:var(--z-raised) }
.work-card .meta{ padding-top:var(--s-4) }
.work-card .meta h3{ font-family:var(--serif); font-size:calc(var(--t-h3)*1.1); font-weight:400; font-synthesis:none;
  letter-spacing:var(--ls-h3); transition:color var(--t-2) var(--e-out) }
.work-card .meta p{ margin-top:2px; color:var(--fg-muted) }
.work-card:hover .meta h3{ color:var(--accent-fg) }

/* Marquee: aquí sólo el marco y la tipografía. La animación es de motion.css. */
.marquee{ overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent) }
.marquee-row{ display:inline-flex; white-space:nowrap }
/* Las marcas desfilan en serif itálica: un desfile de firmas, no una lista.   */
.marquee-row span{ display:inline-flex; align-items:center; padding-inline:clamp(24px,3.4vw,56px);
  font-family:var(--serif); font-style:italic; font-weight:400;
  font-size:clamp(1.3rem,2.4vw,2.1rem); letter-spacing:-.006em; color:var(--fg-2) }

/* Miembro del equipo. Ojo: la clase .ph de este bloque es el marco del
   retrato heredado, no el marcador de dato pendiente (que va con data-ph).    */
.member .ph{ overflow:hidden; aspect-ratio:1; margin-bottom:var(--s-4); border-radius:var(--r-bubble) }
.member .ph img{ width:100%; height:100%; object-fit:cover; filter:brightness(var(--img-bright)) }
.member h3{ font-size:var(--t-h3) }
.member .role{ margin-bottom:var(--s-2); font-size:var(--t-caption);
  font-weight:var(--wght-ui); color:var(--accent-fg) }
.member .bio{ font-size:var(--t-body-s); color:var(--fg-muted) }

/* Caso (detalle) */
.pj-top{ display:grid; grid-template-columns:1.5fr 1fr; gap:clamp(24px,3vw,48px); align-items:start }
@media (max-width:900px){ .pj-top{ grid-template-columns:1fr } }
.pj-hero{ position:relative; overflow:hidden; border-radius:var(--r-bubble); aspect-ratio:4/3 }
.pj-hero img{ width:100%; height:100%; object-fit:cover; filter:brightness(var(--img-bright)) }
.pj-hero .back{ position:absolute; top:var(--s-4); left:var(--s-4); z-index:var(--z-raised);
  display:inline-flex; align-items:center; gap:var(--s-2); min-height:44px;
  padding:10px 18px; border-radius:var(--r-full);
  background:var(--bg); color:var(--fg); font-weight:var(--wght-ui);
  transition:transform var(--t-2) var(--e-out) }
.pj-hero .back:hover{ transform:translateX(-3px) }
.pj-side .logo-chip{ display:grid; place-items:center; width:66px; height:66px;
  margin-bottom:var(--s-5); border-radius:var(--r-md);
  font-family:var(--serif); font-style:italic; font-size:var(--t-h3); color:var(--on-accent) }
.pj-side h1{ margin-bottom:var(--s-4); font-size:var(--t-h1);
  font-weight:var(--wght-display); letter-spacing:var(--ls-h1) }
.pj-side .desc{ color:var(--fg-2); font-size:var(--t-lead) }
.pj-side .meta-row{ display:grid; grid-template-columns:100px 1fr; gap:var(--s-3);
  padding-block:var(--s-4); border-top:1px solid var(--line) }
.pj-side .meta-row:first-of-type{ margin-top:var(--s-5) }
.pj-side .meta-row .k{ color:var(--fg-muted); font-size:var(--t-body-s) }
.pj-side .meta-row .v{ font-weight:var(--wght-ui) }
.pj-quote{ max-width:24ch; font-family:var(--serif); font-style:italic;
  font-size:clamp(1.4rem,3vw,2.2rem); line-height:1.3; color:var(--accent-fg) }
.pj-stack{ display:grid; gap:clamp(16px,2vw,28px) }
.pj-stack .band{ overflow:hidden; border-radius:var(--r-bubble) }
.pj-stack .band img{ width:100%; filter:brightness(var(--img-bright)) }
.pj-body{ max-width:var(--maxw-text) }
.pj-body p + p{ margin-top:1.1em }
.pj-nav{ display:flex; justify-content:space-between; gap:var(--s-4);
  margin-top:var(--s-3); padding-top:var(--s-6); border-top:1px solid var(--line) }

/* Cifra suelta */
.stat h3,.stat .n{ font-size:var(--t-num); font-weight:var(--wght-display);
  line-height:1; letter-spacing:var(--ls-h1); font-variant-numeric:tabular-nums }
.stat h3 .dot,.stat h3 .pk,.stat .pk{ color:var(--accent) }
.stat p{ max-width:30ch; margin-top:var(--s-2); color:var(--fg-2) }

/* Contacto */
.contact-grid{ display:grid; grid-template-columns:1.1fr .9fr; gap:clamp(30px,5vw,80px); align-items:start }
@media (max-width:860px){ .contact-grid{ grid-template-columns:1fr } }
.big-mail{ display:inline-block; font-size:clamp(1.6rem,3.4vw,2.6rem);
  font-weight:var(--wght-display); letter-spacing:var(--ls-h1);
  border-bottom:3px solid var(--accent); transition:color var(--t-2) var(--e-out) }
.big-mail:hover{ color:var(--accent-fg) }

/* Rejillas y escala tipográfica heredadas de la primera versión del sitio.
   Se conservan mientras existan páginas que aún no se reescriben; los roles
   de display hablan en serif, como todo el sitio desde el rediseño.           */
.h-giant,.h-xl,.h-lg{ font-family:var(--serif); font-weight:400; font-synthesis:none }
.h-giant{ font-size:var(--t-mega); line-height:.96; letter-spacing:-.014em }
.h-xl{ font-size:var(--t-display); line-height:.98; letter-spacing:-.012em }
.h-lg{ font-size:calc(var(--t-h2)*1.08); line-height:1.08; letter-spacing:-.008em }
.h-md{ font-size:var(--t-h3); font-weight:var(--wght-h3); line-height:var(--lh-ui); letter-spacing:var(--ls-h3) }
.grid-2{ display:grid; grid-template-columns:repeat(2,1fr); gap:clamp(24px,4vw,60px) }
@media (max-width:820px){ .grid-2{ grid-template-columns:1fr } }
.grid-auto{ display:grid; gap:clamp(16px,2vw,26px);
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr)) }
.work-grid{ display:grid; gap:clamp(20px,3vw,42px) clamp(18px,2.4vw,34px);
  grid-template-columns:repeat(2,1fr) }
@media (max-width:720px){ .work-grid{ grid-template-columns:1fr } }
.mt-1{ margin-top:clamp(12px,2vw,20px) } .mt-2{ margin-top:clamp(20px,3vw,36px) }
.mt-3{ margin-top:clamp(34px,5vw,64px) }
.mb-1{ margin-bottom:clamp(12px,2vw,20px) } .mb-2{ margin-bottom:clamp(20px,3vw,36px) }
.mb-3{ margin-bottom:clamp(34px,5vw,64px) }
.maxw-20{ max-width:20ch } .maxw-40{ max-width:40ch } .maxw-55{ max-width:55ch }

/* Texto que sólo tiene sentido con puntero: en táctil no hay "pasar el cursor",
   así que la instrucción desaparece y la frase sigue leyéndose entera. */
.solo-puntero{display:none}
@media (hover:hover) and (pointer:fine){.solo-puntero{display:inline}}
