/* Paleta de Epistemis — generada desde web/site.config.mjs. No editar a mano. */
:root{--primary:#1f6feb; --primary-ink:#1557c0; --accent:#0d9488; --on-primary:#ffffff;}
@media (prefers-color-scheme:dark){:root{--primary:#4c8ef8; --primary-ink:#8fbaff; --accent:#2dd4bf; --on-primary:#06122a;}}

/* Fuentes de la marca — generadas desde web/site.config.mjs. No editar a mano. */
@font-face{font-family:'Inter';font-style:normal;font-weight:400 800;font-display:swap;src:url('fonts/interVar-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 800;font-display:swap;src:url('fonts/interVar-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:500 700;font-display:swap;src:url('fonts/newsreaderVar-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:500 700;font-display:swap;src:url('fonts/newsreaderVar-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}
:root{--sans:'Inter',system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;--display:'Newsreader','Iowan Old Style',Georgia,serif;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

/* ====================================================================
   Sistema de diseño del sitio público — v2
   --------------------------------------------------------------------
   Un solo archivo para los tres sitios del grupo (Fitorex, Epistemis y
   Somatryx) y los dos idiomas. El generador inyecta DELANTE de este
   fichero la paleta y las fuentes de cada marca, y DETRÁS sus neutros y
   sus tokens propios. El resultado: tres sitios que se reconocen como
   del mismo estudio sin parecer el mismo sitio.

   Dos restricciones mandan sobre todo lo que hay aquí, y conviene
   entenderlas antes de tocar una línea:

     1. La CSP lleva `style-src 'self'` SIN `'unsafe-inline'`. Eso no
        bloquea solo los `<style>`: en CSP 3 `style-src-attr` hereda de
        `style-src`, así que un `style="…"` suelto en una página se
        descarta en producción y en local no se nota. Por eso NO hay ni
        un atributo `style` en las páginas y por eso existen las
        utilidades del final del archivo.

     2. `script-src 'none'` en casi todas las rutas. No hay JavaScript
        que anime nada. Todo el movimiento de este archivo —revelados al
        entrar en pantalla, cabecera que se encoge, barra de progreso,
        marquesina, carruseles con su indicador— es CSS puro, con
        animaciones ligadas al scroll (`animation-timeline`). Donde el
        navegador no las soporta no hay animación y el contenido se ve,
        que es lo único que no se negocia.

   Compatibilidad: este archivo lo consumen ~4.600 páginas ya generadas
   (780 de Fitorex, 3.780 de Epistemis, 20 de Somatryx). Ninguna clase que
   existiera antes se ha eliminado; todas siguen funcionando, reskinadas.
   ==================================================================== */

/* ==================================================================
   1 · TOKENS
   ================================================================== */
:root{
  color-scheme:light;

  /* --- Tipografía ---
     --sans, --display y --mono los inyecta el generador delante de este
     archivo junto con sus @font-face, porque la familia cambia con la
     marca (ver web/fonts.mjs). Aquí solo se usan. */

  /* --- Neutros y superficies ---
     La marca (--primary, --accent, --on-primary) va inyectada justo
     encima; los neutros de abajo son los de Fitorex y cada marca puede
     sobreescribirlos con `palette.light.neutrals`. */
  --bg:#f6f8f4; --surface:#ffffff; --surface-2:#eef2ea; --surface-3:#e3ebdb;
  /* `--muted` se oscureció de #6b7a63 a #64725d: el original daba 4,28:1 sobre el
     fondo y 4,04:1 sobre la superficie alterna, por debajo del 4,5:1 que pide la AA
     para texto normal. Es el color de los pies de foto, las etiquetas de las cifras y
     los enlaces del pie: texto pequeño y, encima, el más difícil de leer. */
  --ink:#0d1508; --text:#414d3a; --muted:#64725d; --border:#dde4d6;

  /* Tintes derivados del primario. Todo lo que «lleva color de marca»
     sin ser color plano sale de aquí, así que cambiar --primary cambia
     el sitio entero de forma coherente. */
  --tint:color-mix(in srgb, var(--primary) 12%, transparent);
  --tint-2:color-mix(in srgb, var(--primary) 6%, transparent);
  --tint-3:color-mix(in srgb, var(--primary) 22%, transparent);
  --edge:color-mix(in srgb, var(--primary) 32%, var(--border));

  /* Línea de luz superior de las superficies. Es el truco que separa una
     tarjeta «plana con borde» de una tarjeta con material: un pelo de luz
     en el canto de arriba, como el bisel de un objeto real. En claro es
     blanco puro; en oscuro, un blanco al 8 %. */
  --hairline:color-mix(in srgb, #ffffff 92%, transparent);

  /* Banda invertida: la sección que se pone siempre oscura, llueva o
     truene, para partir el ritmo de la página. Es el recurso de Apple y
     de Nike y funciona igual de bien en los tres sitios. */
  --invert-bg:#0b0f09;
  --invert-surface:#151b12;
  --invert-ink:#ffffff;
  --invert-text:#b9c4b2;
  --invert-border:#26301f;
  /* El primario DENTRO de la banda invertida. Tiene que declararse aparte porque el
     primario de marca está elegido para contrastar con el fondo normal, y la banda
     invertida es justo el fondo contrario:

       · en Somatryx el primario claro es #111 — negro sobre la banda negra: invisible;
       · en Fitorex el verde oscuro #4f8f06 sobre negro se queda en 2,4:1.

     La regla práctica es que cada marca ponga aquí el primario de SU OTRO tema. */
  --invert-primary:var(--primary);
  --invert-primary-ink:var(--primary-ink);

  /* Degradado del texto destacado del titular. Cada marca puede
     redefinirlo (Somatryx lo pone monocromo). */
  --grad:linear-gradient(102deg, var(--primary-ink), var(--accent));

  /* --- Forma --- */
  --radius-xl:30px; --radius:20px; --radius-sm:13px; --radius-xs:9px; --radius-pill:999px;

  /* --- Elevación ---
     Cuatro niveles y no más. Cada uno combina un contacto corto (la
     sombra que pega el objeto al fondo) con una difusa larga y muy
     abierta (la que le da altura). Una sola sombra siempre parece
     pegatina. */
  --shadow-sm:0 1px 2px rgba(13,21,8,.05);
  --shadow:0 1px 2px rgba(13,21,8,.05), 0 14px 34px -16px rgba(13,21,8,.20);
  --shadow-lg:0 2px 5px rgba(13,21,8,.06), 0 32px 66px -26px rgba(13,21,8,.30);
  --shadow-xl:0 4px 10px rgba(13,21,8,.07), 0 50px 100px -40px rgba(13,21,8,.38);

  /* --- Retícula --- */
  --wrap:1140px; --wrap-wide:1320px; --wrap-text:720px;
  --gut:22px;
  --head-h:66px;

  /* --- Espaciado ---
     Escala de 8 con dos medios pasos abajo, donde se nota. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:44px; --s8:60px; --s9:80px; --s10:112px;

  /* --- Movimiento ---
     Tres curvas y nada más:
       --ease-out    salida exponencial: arranca rápido y frena mucho.
                     Es la de iOS y la que hace que algo «aterrice».
       --ease-spring rebota un pelo al final. Solo para lo que aparece.
       --ease-inout  simétrica, para lo que va y vuelve (menús). */
  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-spring:cubic-bezier(.34,1.42,.64,1);
  --ease-inout:cubic-bezier(.65,0,.35,1);
  --dur-1:.14s; --dur-2:.22s; --dur-3:.4s; --dur-4:.7s; --dur-5:1s;

  /* --- Capas --- */
  --z-bar:30; --z-head:50; --z-sheet:60; --z-skip:100;

  /* --- Personalidad de marca ---
     Estos cuatro los sobreescribe cada marca desde `site.tokens`
     (web/site.config.mjs). Son los que hacen que el mismo CSS suene
     atlético en Fitorex, clínico en Epistemis y de casa matriz en
     Somatryx sin duplicar una sola regla.

       --case-display  MAYÚSCULAS en los antetítulos (Fitorex, Somatryx)
                       o caja normal (Epistemis, que es una marca académica
                       y en versalitas serias parece un pie de foto)
       --track-display espaciado de las letras del titular grande
       --glow          cuánta luz de color hay detrás de la portada
       --grain         cuánto grano tienen las bandas destacadas */
  --case-display:uppercase;
  --track-display:.14em;
  --glow:1;
  --grain:.055;
  /* Familia y espaciado de los TITULARES. Por defecto la de cuerpo, que es lo que
     quieren Fitorex y Somatryx: una grotesca apretada y muy pesada, que es el registro
     de Apple, Nike o Linear.

     Epistemis pone aquí `var(--display)` y sus titulares pasan a la serif. No es un
     capricho: es una marca académica, y una serif en titular la coloca junto a un
     manual en vez de junto a una app de consumo. Una serif necesita además menos
     espaciado negativo que una grotesca — de ahí el segundo mando. */
  --h-font:var(--sans);
  --h-track:-.035em;
  /* ANCHURA del titular. Solo hace algo si la familia de la marca es variable
     y trae eje `wdth` (Archivo en Fitorex, Instrument Sans en Somatryx); con
     una fuente estática el navegador lo ignora y no pasa nada.

     Es el mando que más separa a las tres marcas y el que no tenía sistema
     hasta ahora: la grotesca ANCHA es el registro de Adidas y de Nike —ocupa
     el ancho de la columna y pesa—, y la CONDENSADA es el de Gymshark, que
     mete cuatro palabras donde caben dos. Con una sola familia variable se
     tienen los dos sin descargar dos archivos.

     --h-stretch      titulares
     --track-stretch  antetítulos, marquesina y cifras (el registro pequeño) */
  --h-stretch:100%;
  --track-stretch:100%;
  /* Y el peso. No es cosmético: si la marca sirve una serif que solo trae 500 y 600 y
     el titular pide 800, el navegador engorda la 600 por software y el resultado es una
     letra sucia y con las gracias empastadas. El peso tiene que caber en lo que se ha
     descargado de verdad. */
  --h-weight:800;

  /* Textura de grano. Es un SVG con ruido fractal en un data-URI: lo
     permite `img-src 'self' data:` (los `background-image` cuelgan de
     img-src, no de style-src) y pesa 300 bytes contra los 40 KB de un
     PNG de ruido. Nunca va fijo a la ventana: solo dentro de las bandas
     que lo piden, porque una capa a pantalla completa cuesta compositor
     en cada scroll. */
  --grain-url:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");

  /* --- Escala tipográfica ---
     Fluida: un solo juego que crece con la ventana, en vez de tres
     saltos bruscos en tres media queries. --t-display es la nueva y solo
     la usan las portadas; --t-hero es la de siempre, subida de tope
     porque 4,2 rem en un monitor de 27" se queda pequeño. */
  --t-display:clamp(2.75rem,1.15rem + 6.6vw,6.6rem);
  --t-hero:clamp(2.3rem,1.35rem + 4.2vw,4.9rem);
  --t-h2:clamp(1.75rem,1.28rem + 1.95vw,2.85rem);
  --t-h3:clamp(1.14rem,1.05rem + .42vw,1.4rem);
  --t-lede:clamp(1.08rem,1rem + .55vw,1.35rem);
  --t-body:1.0325rem;
  --t-sm:.925rem;
  --t-xs:.83rem;
}

@media (prefers-color-scheme:dark){
  :root{
    color-scheme:dark;
    --bg:#080c06; --surface:#111a0e; --surface-2:#16210f; --surface-3:#1d2a15;
    --ink:#ecf5e4; --text:#adbba4; --muted:#82907a; --border:#26331d;
    --hairline:color-mix(in srgb, #ffffff 9%, transparent);
    --shadow-sm:0 1px 2px rgba(0,0,0,.5);
    --shadow:0 1px 2px rgba(0,0,0,.45), 0 18px 44px -20px rgba(0,0,0,.85);
    --shadow-lg:0 2px 6px rgba(0,0,0,.55), 0 36px 76px -30px rgba(0,0,0,.95);
    --shadow-xl:0 4px 12px rgba(0,0,0,.6), 0 56px 110px -44px rgba(0,0,0,1);
    /* En oscuro la banda invertida no puede ser «más oscura»: se
       invierte al revés y se pone clara, que es lo que la sigue
       separando del resto de la página. */
    --invert-bg:#f4f6f2;
    --invert-surface:#ffffff;
    --invert-ink:#0b0f09;
    --invert-text:#4b5646;
    --invert-border:#dbe2d6;
    --grain:.03;
  }
}

/* ==================================================================
   2 · BASE
   ================================================================== */
*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  scroll-padding-top:calc(var(--head-h) + 18px);
  /* `clip` y no `hidden`. La diferencia importa aquí por dos motivos concretos:
       · la hoja del menú móvil se aparca fuera de pantalla con
         `transform:translateX(100%)`, y con `hidden` eso ensancha el documento
         360 px — en un teléfono la página se arrastraba de lado sin motivo;
       · `hidden` convierte al elemento en contenedor de scroll, y eso rompe
         `position:sticky` en sus descendientes (la cabecera, la barra de filtros
         de la biblioteca y la columna lateral de las fichas). `clip` recorta sin
         crear scroll.
     El `hidden` de `body` se queda debajo como respaldo para Safari 15, que no
     conoce `clip` y descarta la línea. */
  overflow-x:clip;
}
body{
  margin:0; background:var(--bg); color:var(--text);
  font:400 var(--t-body)/1.68 var(--sans);
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
  overflow-x:hidden; overflow-x:clip;
  /* Las cifras nunca bailan de ancho al cambiar: en una página llena de
     números un «1» estrecho descoloca la columna entera. */
  font-variant-numeric:tabular-nums lining-nums;
}
/* El atributo `hidden` gana SIEMPRE. La regla `[hidden]{display:none}` que trae el
   navegador es una hoja de USUARIO-AGENTE, así que cualquier `display:` que escribamos
   nosotros —aunque sea de una sola clase— la pisa sin necesidad de más especificidad.
   Pasó de verdad: `.panel-loading{display:grid}` dejaba el «Cargando tus datos…» clavado
   encima del formulario de acceso del panel, con su `hidden` puesto y todo. Se arregla
   una vez aquí en lugar de acordarse en cada clase que se oculte desde JavaScript. */
[hidden]{display:none!important}
img,svg,video{max-width:100%; height:auto; display:block}
a{color:var(--primary-ink); text-underline-offset:3px; text-decoration-thickness:1.5px}
a:hover{text-decoration:underline}

h1,h2,h3,h4{color:var(--ink); font-family:var(--h-font); font-stretch:var(--h-stretch); line-height:1.14; letter-spacing:-.022em; margin:0; text-wrap:balance}
h1{font-size:var(--t-hero); font-weight:var(--h-weight); letter-spacing:var(--h-track); line-height:1.04}
h2{font-size:var(--t-h2); font-weight:var(--h-weight); letter-spacing:calc(var(--h-track) + .005em); line-height:1.08}
h3{font-size:var(--t-h3); font-weight:700}
h4{font-size:1.0325rem; font-weight:700}
p{margin:0 0 1em; text-wrap:pretty}
p:last-child{margin-bottom:0}
strong,b{color:var(--ink); font-weight:640}
em{font-style:italic}
small{font-size:var(--t-xs)}
code{font:500 .88em/1 var(--mono); background:var(--surface-2); border:1px solid var(--border); border-radius:6px; padding:.15em .42em}
hr{border:none; border-top:1px solid var(--border); margin:var(--s6) 0}
::selection{background:var(--tint-3); color:var(--ink)}

.wrap{max-width:var(--wrap); margin:0 auto; padding:0 var(--gut)}
.wrap-wide{max-width:var(--wrap-wide); margin:0 auto; padding:0 var(--gut)}
.wrap-text{max-width:var(--wrap-text); margin:0 auto}
.lede{font-size:var(--t-lede); line-height:1.58; color:var(--text)}
.muted{color:var(--muted)}
.center{text-align:center}
.sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0}

.skip{
  position:absolute; left:-9999px; top:0; z-index:var(--z-skip);
  background:var(--primary); color:var(--on-primary); padding:12px 18px;
  border-radius:0 0 10px 0; font-weight:650; text-decoration:none;
}
.skip:focus{left:0}
:focus-visible{outline:2.5px solid var(--primary); outline-offset:3px; border-radius:5px}

/* ==================================================================
   3 · MATERIAL
   ------------------------------------------------------------------
   Tres mezcladores que se aplican por composición y no por herencia.
   Están arriba del todo porque los usan casi todos los bloques de
   abajo, y así se lee una vez qué significa «superficie» en este sitio.
   ================================================================== */

/* Superficie base: fondo, borde de un pelo y la línea de luz del canto.
   El `::before` en vez de un `box-shadow: inset` para que no se lo coma
   un `overflow:hidden` ni pinte por encima del contenido. */
.surface,
.card,.plat,.plan,.tile,.steps li,.stats li,.pcard,.kpi,.lib-card,
.log article,.exanim,.facts,.calc,.login-card,.gloss article,.prevnext a,
.faq details,.callout,.table-wrap,.bento>*,.spec div,.pull,.timeline li{
  position:relative;
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
}
/* La línea de luz va en ::after y no en ::before para no pelearse con
   los ::before que ya tienen contenido propio: el contador de los pasos
   numerados y el punto de la línea de tiempo. */
:where(.card,.plat,.plan,.tile,.stats li,.pcard,.kpi,.log article,.calc,
       .login-card,.gloss article,.bento>*,.spec div,.pull,.lib-card)::after{
  content:""; position:absolute; inset:0; border-radius:inherit;
  pointer-events:none; z-index:0;
  box-shadow:inset 0 1px 0 var(--hairline);
}
/* Los que llevan contenido propio en ::after se quedan fuera del truco. */
.phone::after,.crumbs li+li::before{box-shadow:none}

/* Cristal: la cabecera y la barra de filtros. `saturate` antes de `blur`
   porque el desenfoque a secas lava el color de lo que hay debajo. */
.glass{
  background:color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter:saturate(180%) blur(16px);
  -webkit-backdrop-filter:saturate(180%) blur(16px);
}

/* Grano. Solo dentro de bandas concretas. */
.grainy{position:relative; isolation:isolate}
.grainy::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background-image:var(--grain-url); background-size:160px 160px;
  opacity:var(--grain); mix-blend-mode:overlay;
}

/* Malla de color: dos o tres manchas muy diluidas del primario y del
   acento. Pesa cero, escala a cualquier pantalla y en modo oscuro se
   apaga sola porque sale de las mismas variables. */
.mesh{position:relative; isolation:isolate}
.mesh::after{
  content:""; position:absolute; inset:-40% -10% auto; height:150%; z-index:-2; pointer-events:none;
  background:
    radial-gradient(52% 44% at 18% 6%,  color-mix(in srgb, var(--primary) calc(20% * var(--glow)), transparent), transparent 68%),
    radial-gradient(46% 40% at 84% 0%,  color-mix(in srgb, var(--accent)  calc(17% * var(--glow)), transparent), transparent 66%),
    radial-gradient(40% 36% at 52% 30%, color-mix(in srgb, var(--primary) calc(8%  * var(--glow)), transparent), transparent 70%);
}

/* ==================================================================
   4 · ICONOS
   ================================================================== */
.ic{width:24px; height:24px; flex:none}
.ic-sm{width:18px; height:18px}
.ic-lg{width:30px; height:30px}
/* Cuadro tintado del icono: da peso visual sin recurrir al color plano. */
.ic-box{
  width:46px; height:46px; border-radius:14px; display:grid; place-items:center;
  margin-bottom:var(--s4); position:relative; z-index:1;
  background:var(--tint); color:var(--primary-ink);
  border:1px solid var(--tint-3);
  transition:transform var(--dur-2) var(--ease-spring), background var(--dur-2) ease;
}
.card:hover .ic-box,.tile:hover .ic-box{transform:translateY(-2px) rotate(-3deg)}

/* ==================================================================
   5 · CABECERA
   ================================================================== */
.site-head{
  position:sticky; top:0; z-index:var(--z-head);
  background:color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter:saturate(180%) blur(16px); -webkit-backdrop-filter:saturate(180%) blur(16px);
  border-bottom:1px solid transparent;
  transition:border-color var(--dur-2) ease;
}
/* La línea inferior y la sombra solo aparecen cuando la página está
   desplazada: con la página arriba del todo, una raya bajo la cabecera
   parte el diseño sin motivo. Ligado al scroll, sin JavaScript.

   Solo de 941 px para arriba, y esa condición NO es estética: ver el
   bloque de móvil de más abajo. */
@media (min-width:941px){
  @supports (animation-timeline:scroll()){
    .site-head{
      animation:head-settle linear both;
      animation-timeline:scroll();
      animation-range:0 130px;
    }
    @keyframes head-settle{
      to{
        border-bottom-color:var(--border);
        box-shadow:0 10px 30px -22px rgba(0,0,0,.5);
        background:color-mix(in srgb, var(--bg) 88%, transparent);
      }
    }
  }
  @supports not (animation-timeline:scroll()){ .site-head{border-bottom-color:var(--border)} }
}

/* ---------- por qué la cabecera pierde el cristal en móvil ----------
   `backdrop-filter` convierte al elemento en BLOQUE CONTENEDOR de sus
   descendientes `position:fixed`. La hoja del menú móvil es uno de
   ellos, así que con el cristal puesto dejaba de posicionarse respecto a
   la ventana y pasaba a hacerlo respecto a la cabecera: el menú medía
   84 px de alto —la altura de la barra— en vez de la pantalla entera, y
   sus nueve entradas se aplastaban dentro hasta 30 px cada una.

   Es un fallo que no se ve en el HTML, no da error en consola y solo
   aparece en un teléfono. La cabecera de móvil se queda opaca, que
   además cuesta menos compositor en el dispositivo que peor lo lleva. */
@media (max-width:940px){
  .site-head{
    background:var(--bg);
    backdrop-filter:none; -webkit-backdrop-filter:none;
    border-bottom-color:var(--border);
  }
}

/* Barra de progreso de lectura. Un pelo de color que crece con el
   scroll: en las guías largas y en las páginas legales es la única
   pista de cuánto queda. Puramente decorativa, así que va oculta a los
   lectores de pantalla desde el HTML. */
.head-progress{
  position:absolute; left:0; bottom:-1px; height:2px; width:100%;
  transform-origin:0 50%; transform:scaleX(0);
  background:linear-gradient(90deg, var(--primary), var(--accent));
}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .head-progress{animation:progress linear both; animation-timeline:scroll(); animation-range:0 100%}
    @keyframes progress{to{transform:scaleX(1)}}
  }
}

.head-inner{display:flex; align-items:center; gap:var(--s4); min-height:var(--head-h)}
.brand{
  display:flex; align-items:center; gap:10px; font-weight:800; font-size:1.075rem;
  color:var(--ink); text-decoration:none; flex:none; letter-spacing:-.025em;
}
.brand img{border-radius:10px; transition:transform var(--dur-2) var(--ease-spring)}
.brand:hover{text-decoration:none}
.brand:hover img{transform:rotate(-6deg) scale(1.06)}

/* ---------- marca dibujada con máscara ----------
   Para las marcas con wordmark propio (una tipografía que el sitio no
   lleva), el logo se pinta con `mask-image` + `currentColor` en vez de
   con un <img>.

   El motivo es el tema: el original es tinta negra sobre papel blanco.
   Como <img> harían falta dos archivos y acertar con el
   `prefers-color-scheme` en los dos. Con máscara el PNG solo aporta la
   FORMA y el color lo pone el texto de al lado, así que la marca sigue
   al tema sola y siempre contrasta. */
.brand-mark,.brand-word{
  display:block; background:currentColor; flex:none;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-position:center; mask-position:center;
}
/* Proporciones tomadas del original: monograma 247×376, wordmark 1044×61. */
.brand-mark{
  width:19px; height:29px;
  -webkit-mask-image:url('/assets/logo-mark.png'); mask-image:url('/assets/logo-mark.png');
}
.brand-word{
  width:188px; height:11px; margin-top:2px;
  -webkit-mask-image:url('/assets/logo-word.png'); mask-image:url('/assets/logo-word.png');
}
.brand-lock{gap:13px}
@media (max-width:420px){
  .brand-mark{width:16px; height:24px}
  .brand-word{width:145px; height:8.5px}
}
.foot-brand .brand-mark{width:23px; height:35px}
.foot-brand .brand-word{width:210px; height:12.3px}

/* ---------- navegación ---------- */
.site-nav{margin-left:auto; display:flex; align-items:center; gap:2px}
.site-nav a{
  position:relative; color:var(--text); text-decoration:none; font-size:.9rem; font-weight:530;
  padding:8px 13px; border-radius:10px; white-space:nowrap;
  transition:color var(--dur-1) ease, background var(--dur-1) ease;
}
.site-nav a:hover{color:var(--ink); background:var(--surface-2); text-decoration:none}
.site-nav a[aria-current="page"]{color:var(--primary-ink); background:var(--tint)}
/* Subrayado de precisión bajo el enlace activo: 2 px que arrancan desde
   el centro. Es el detalle que separa una barra de enlaces de una
   navegación. */
.site-nav a[aria-current="page"]::after{
  content:""; position:absolute; left:13px; right:13px; bottom:3px; height:2px;
  border-radius:2px; background:var(--primary);
  animation:underline var(--dur-3) var(--ease-out) both;
}
@keyframes underline{from{transform:scaleX(0)}to{transform:scaleX(1)}}

.nav-lang{
  margin-left:var(--s2); font-weight:700!important; font-size:.78rem!important; letter-spacing:.05em;
  border:1px solid var(--border); color:var(--muted)!important; padding:6px 10px!important;
}
.nav-lang:hover{color:var(--ink)!important; border-color:var(--edge)}
.nav-login{color:var(--ink)!important; font-weight:620!important}
/* Botón principal de la cabecera, con barrido de luz al pasar por
   encima. El barrido es un pseudoelemento inclinado que cruza el botón:
   no hay imagen ni script, y en reduced-motion se queda quieto. */
.nav-cta{
  position:relative; overflow:hidden;
  background:var(--primary)!important; color:var(--on-primary)!important;
  margin-left:6px; font-weight:660!important; padding:9px 17px!important;
  box-shadow:0 8px 20px -10px var(--primary);
  transition:box-shadow var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
}
.nav-cta:hover{transform:translateY(-1px); box-shadow:0 12px 26px -10px var(--primary)}
.nav-cta::before{
  content:""; position:absolute; top:0; bottom:0; left:-140%; width:60%;
  background:linear-gradient(100deg, transparent, color-mix(in srgb, #fff 45%, transparent), transparent);
  transform:skewX(-18deg); pointer-events:none;
}
@media (prefers-reduced-motion:no-preference){
  .nav-cta:hover::before{animation:sheen .85s var(--ease-out)}
  @keyframes sheen{to{left:150%}}
}

/* ---------- menú móvil ----------
   Hoja a pantalla completa, no un desplegable. Con seis entradas más
   idioma, acceso y descarga, un acordeón bajo la cabecera obliga a
   apuntar a objetivos de 30 px; una hoja da un objetivo de 56 px por
   fila y sitio para separar la navegación de las acciones.

   Todo con un checkbox: la etiqueta del hamburguesa lo marca, el velo
   de fondo lo desmarca. Cero JavaScript, y el foco del teclado sigue el
   orden natural del documento. */
/* El checkbox va invisible pero NO `display:none` ni `hidden`: así sigue en el
   árbol de accesibilidad y se puede abrir y cerrar el menú con Tab + Espacio.
   Con `hidden` —que es como estaba— el menú solo se abría con el ratón. */
.navtoggle{position:absolute; opacity:0; width:1px; height:1px; margin:0; pointer-events:none}
.burger{
  display:none; margin-left:auto; padding:11px; cursor:pointer; border-radius:11px;
  transition:background var(--dur-1) ease;
}
.burger:hover{background:var(--surface-2)}
/* El foco del teclado vive en el checkbox, que es invisible: hay que pintarlo en el
   hamburguesa o quien navega con Tab no sabe dónde está. */
.navtoggle:focus-visible ~ .burger{outline:2.5px solid var(--primary); outline-offset:2px}
.burger span{
  display:block; width:21px; height:2px; background:var(--ink); border-radius:2px;
  transition:transform var(--dur-3) var(--ease-out), opacity var(--dur-2) ease;
}
.burger span+span{margin-top:5px}
/* El hamburguesa se convierte en aspa cuando el menú está abierto. */
.navtoggle:checked ~ .burger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.navtoggle:checked ~ .burger span:nth-child(2){opacity:0; transform:scaleX(.4)}
.navtoggle:checked ~ .burger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

.nav-scrim{display:none}

@media (max-width:940px){
  .burger{display:block; order:3}
  .site-nav{
    position:fixed; inset:var(--head-h) 0 0 auto; width:min(360px,86vw);
    z-index:var(--z-sheet);
    margin:0; flex-direction:column; align-items:stretch; justify-content:flex-start;
    gap:2px; padding:var(--s5) var(--s5) var(--s8);
    background:var(--bg); border-left:1px solid var(--border);
    box-shadow:var(--shadow-xl);
    overflow-y:auto; overscroll-behavior:contain;
    transform:translateX(100%); visibility:hidden;
    transition:transform var(--dur-3) var(--ease-out), visibility var(--dur-3);
  }
  .navtoggle:checked ~ .site-nav{transform:none; visibility:visible}
  .site-nav a{
    padding:15px 14px; font-size:1.06rem; font-weight:600; border-radius:12px;
    border-bottom:1px solid var(--border);
    /* Un menú largo se desplaza, no se comprime. Sin esto, en cuanto las entradas no
       caben, el reparto flexible les quita altura hasta dejarlas por debajo del
       objetivo táctil de 44 px — y las últimas, que son «Entrar» y «Descargar», son
       justo las que hay que poder pulsar. */
    flex:none;
  }
  .site-nav a[aria-current="page"]::after{display:none}
  /* 13 px de relleno y no 6: en la hoja móvil el selector de idioma se quedaba en 35 px
     de alto, por debajo del objetivo táctil de 44 px que piden tanto Apple como las
     pautas WCAG. Es el único control del menú que no era un enlace de ancho completo, y
     por eso se le había escapado. */
  .nav-lang{align-self:flex-start; margin:var(--s4) 0 0; padding:13px 16px!important; font-size:.85rem!important; border-bottom:1px solid var(--border)!important}
  .nav-cta,.nav-login{margin:var(--s3) 0 0; text-align:center; justify-content:center; border-bottom:none!important}
  .nav-cta{padding:15px 18px!important; border-radius:12px; font-size:1.02rem}
  /* Velo. Nace en display:none, así que no hay ninguna capa a pantalla
     completa compositando mientras el menú está cerrado. */
  .navtoggle:checked ~ .nav-scrim{
    display:block; position:fixed; inset:0; z-index:calc(var(--z-sheet) - 1);
    background:color-mix(in srgb, var(--ink) 42%, transparent);
    backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
    animation:fade var(--dur-3) ease both; cursor:pointer;
  }
  @keyframes fade{from{opacity:0}to{opacity:1}}
}

/* ==================================================================
   6 · SECCIONES
   ================================================================== */
section{padding:clamp(64px,8.5vw,132px) 0; position:relative}
section.tight{padding:clamp(34px,4.5vw,62px) 0}
section.flush{padding-top:0}
.alt{background:var(--surface-2); border-block:1px solid var(--border)}

.section-head{max-width:720px; margin:0 auto clamp(36px,4.6vw,62px); text-align:center}
.section-head h2{margin-bottom:var(--s4)}
.section-head p{color:var(--muted); font-size:1.09rem; margin:0}
/* Encabezado alineado a la izquierda, para las secciones editoriales
   donde el centrado hace que todo parezca una landing de plantilla. */
.section-head.left{text-align:left; margin-inline:0; max-width:760px}

.eyebrow{
  display:inline-block; font-family:var(--display); font-stretch:var(--track-stretch); font-size:.86rem; font-weight:600;
  letter-spacing:var(--track-display); text-transform:var(--case-display);
  color:var(--primary-ink); margin-bottom:var(--s3);
}
/* Antetítulo con guía: una raya corta delante, como en una portada de
   revista. Se usa donde el antetítulo va solo, sin icono. */
.kicker{
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--display); font-stretch:var(--track-stretch); font-size:.82rem; font-weight:600;
  letter-spacing:var(--track-display); text-transform:var(--case-display);
  color:var(--muted); margin-bottom:var(--s4);
}
.kicker::before{content:""; width:26px; height:1px; background:var(--primary); flex:none}

/* Regla con etiqueta: separa dos bloques largos sin gritar. */
.rule{display:flex; align-items:center; gap:var(--s4); margin:var(--s7) 0; color:var(--muted); font-size:var(--t-xs); text-transform:var(--case-display); letter-spacing:var(--track-display)}
.rule::before,.rule::after{content:""; height:1px; background:var(--border); flex:1}

/* ---------- banda invertida ----------
   La sección que se pone al revés que el resto de la página. Sirve para
   partir el ritmo cada tres o cuatro secciones; usada dos veces en una
   portada funciona, usada seis parece un tablero de ajedrez. */
section.invert{
  background:var(--invert-bg); border-block:none;
  /* Se reasigna la paleta ENTERA para el subárbol. Todo lo de dentro —tarjetas,
     iconos, tintes, bordes— sale de estas mismas variables, así que no hace falta ni
     una regla `.invert .card{…}`: los componentes se recolorean solos. */
  --primary:var(--invert-primary);
  --primary-ink:var(--invert-primary-ink);
  --surface:var(--invert-surface);
  --surface-2:color-mix(in srgb, var(--invert-surface) 70%, var(--invert-bg));
  --ink:var(--invert-ink);
  --text:var(--invert-text);
  --muted:color-mix(in srgb, var(--invert-text) 78%, transparent);
  --border:var(--invert-border);
  --hairline:color-mix(in srgb, var(--invert-ink) 8%, transparent);
  color:var(--invert-text);
}
section.invert h1,section.invert h2,section.invert h3,section.invert h4{color:var(--invert-ink)}
section.invert .eyebrow{color:var(--primary)}

/* ==================================================================
   7 · PORTADAS
   ================================================================== */
.hero{
  padding:clamp(64px,8vw,124px) 0 clamp(34px,4.4vw,58px);
  text-align:center; position:relative; isolation:isolate;
}
.hero::before{
  content:""; position:absolute; inset:-34% -10% 0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(58% 46% at 22% 8%,  color-mix(in srgb, var(--primary) calc(20% * var(--glow)), transparent), transparent 70%),
    radial-gradient(50% 42% at 82% 0%,  color-mix(in srgb, var(--accent)  calc(17% * var(--glow)), transparent), transparent 68%);
}
/* Grano sobre la malla: sin él, dos degradados grandes en una pantalla
   OLED enseñan bandas de color escalonadas. */
.hero::after{
  content:""; position:absolute; inset:-34% -10% 0; z-index:-1; pointer-events:none;
  background-image:var(--grain-url); background-size:160px 160px;
  opacity:var(--grain); mix-blend-mode:overlay;
}
/* Monograma grande de la portada. Mismo mecanismo de máscara que la
   cabecera, así que sigue al tema. */
.hero-mark{
  display:block; margin:0 auto var(--s5); width:clamp(48px,5vw,66px); height:clamp(73px,7.6vw,100px);
  background:currentColor; color:var(--primary-ink); opacity:.92;
  -webkit-mask-image:url('/assets/logo-mark.png'); mask-image:url('/assets/logo-mark.png');
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-position:center; mask-position:center;
}
.hero h1{margin-bottom:var(--s5); max-width:17ch; margin-inline:auto}
.hero .grad{
  background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent;
  /* Una descendente de la «g» o la «p» se corta con background-clip si
     la caja va justa: un pelo de relleno abajo lo evita. */
  padding-bottom:.06em;
}
.hero .lede{max-width:680px; margin:0 auto var(--s6)}
.hero-note{font-size:var(--t-sm); color:var(--muted); margin:var(--s4) 0 0}

/* Portada extragrande: la de la home. El titular a --t-display y sin
   límite de 17ch, porque aquí el titular ES el diseño. */
.hero-xl{padding:clamp(78px,10vw,168px) 0 clamp(40px,5vw,72px)}
.hero-xl h1{font-size:var(--t-display); letter-spacing:-.04em; line-height:.98; max-width:19ch}
.hero-xl .lede{max-width:600px; font-size:clamp(1.1rem,1rem + .7vw,1.42rem)}

/* Portada alineada a la izquierda con media al lado. Es la disposición
   editorial: el texto manda y la imagen acompaña, en vez del bloque
   centrado que usa todo el mundo. */
.hero-split{text-align:left}
.hero-split .wrap{
  display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(32px,5vw,76px); align-items:center;
}
/* En la portada partida el titular vive en media retícula, así que no puede usar la
   escala de la portada centrada: 6,6 rem en una columna de 540 px deja cinco letras
   por línea y ocho líneas de titular. Esta escala está calculada para esa columna. */
.hero-split h1{margin-inline:0; max-width:15ch; font-size:clamp(2.3rem,1.2rem + 3.4vw,4.15rem)}
.hero-split .lede{margin-inline:0; max-width:52ch}
.hero-split .cta,.hero-split .trustbar{justify-content:flex-start}
.hero-split .trustbar{gap:10px 22px}
.hero-media{display:flex; justify-content:center; align-items:center; min-width:0}
.hero-media .phone{max-width:290px}
.hero-media .frame{width:100%}
@media (max-width:900px){
  .hero-split{text-align:center}
  .hero-split .wrap{grid-template-columns:1fr}
  .hero-split h1,.hero-split .lede{max-width:none; margin-inline:auto}
  .hero-split .cta,.hero-split .trustbar{justify-content:center}
  /* La media baja debajo del texto y no encima: en un teléfono, empujar el titular
     por debajo del pliegue con una imagen es perder la única frase que se lee seguro. */
  .hero-split .hero-media{order:2; margin-top:var(--s6)}
}

.hero-page{padding:clamp(54px,6.4vw,96px) 0 clamp(24px,3.2vw,42px); text-align:center; position:relative; isolation:isolate}
.hero-page::before{
  content:""; position:absolute; inset:-40% 0 40%; z-index:-1; pointer-events:none;
  background:radial-gradient(48% 60% at 50% 0%, var(--tint), transparent 72%);
}
/* Mismo grano que la portada. Sin él, un degradado radial grande en una pantalla OLED
   enseña anillos escalonados justo detrás del titular. */
.hero-page::after{
  content:""; position:absolute; inset:-40% 0 40%; z-index:-1; pointer-events:none;
  background-image:var(--grain-url); background-size:160px 160px;
  opacity:var(--grain); mix-blend-mode:overlay;
}
.hero-page h1{margin-bottom:var(--s4)}
.hero-page .lede{max-width:720px; margin:0 auto}
.hero-page .cta{margin-top:var(--s6)}
/* Cifras bajo la entradilla de una página de colección. Sin tarjeta y separadas por
   líneas: en una portada interior no compiten con el titular, lo respaldan. */
.hero-stats{
  display:flex; flex-wrap:wrap; justify-content:center; align-items:stretch;
  gap:0; list-style:none; margin:var(--s6) 0 0; padding:0;
}
.hero-stats li{padding:0 clamp(18px,3vw,34px); border-left:1px solid var(--border)}
.hero-stats li:first-child{border-left:none}
.hero-stats b{
  display:block; font-family:var(--display); font-weight:600; line-height:1;
  font-size:clamp(1.5rem,1.2rem + 1.1vw,2.2rem); color:var(--ink);
  letter-spacing:-.01em; font-variant-numeric:tabular-nums;
}
.hero-stats span{display:block; margin-top:7px; font-size:var(--t-xs); color:var(--muted); line-height:1.4}
@media (max-width:600px){
  .hero-stats{gap:var(--s4) 0}
  .hero-stats li{flex:1 0 45%; padding:0 var(--s3)}
  .hero-stats li:nth-child(odd){border-left:none}
}
.hero-page-media{margin-top:clamp(30px,4vw,52px)}

/* Sello de confianza bajo los botones de la portada. */
.trustbar{
  display:flex; flex-wrap:wrap; justify-content:center; gap:10px 28px;
  list-style:none; margin:var(--s6) 0 0; padding:0;
}
.trustbar li{display:flex; align-items:center; gap:8px; font-size:var(--t-sm); color:var(--muted)}
.trustbar .ic{width:19px; height:19px; color:var(--primary-ink)}

/* ---------- entrada de la portada ----------
   Los hijos directos de la portada aparecen escalonados al cargar. Es
   la única animación del sitio que no depende del scroll, y existe
   porque la primera pantalla es la única que nadie desplaza para ver.

   `both` deja el estado inicial aplicado antes de arrancar; si el
   usuario pide menos movimiento, el bloque global del final las reduce
   a 1 ms y el contenido aparece de golpe, que es lo correcto. */
@media (prefers-reduced-motion:no-preference){
  .hero > .wrap > *,
  .hero-copy > *,
  .hero-split .hero-media{animation:enter var(--dur-4) var(--ease-out) both}
  /* En la portada partida el escalonado lo llevan los hijos del texto, no las dos
     columnas: si animas la columna entera, el titular y los botones aparecen a la vez
     y se pierde justo el efecto que se buscaba. */
  .hero-split > .wrap > *{animation:none}
  :where(.hero > .wrap, .hero-copy) > *:nth-child(1){animation-delay:.04s}
  :where(.hero > .wrap, .hero-copy) > *:nth-child(2){animation-delay:.11s}
  :where(.hero > .wrap, .hero-copy) > *:nth-child(3){animation-delay:.18s}
  :where(.hero > .wrap, .hero-copy) > *:nth-child(4){animation-delay:.25s}
  :where(.hero > .wrap, .hero-copy) > *:nth-child(5){animation-delay:.32s}
  .hero-split .hero-media{animation-delay:.22s; animation-duration:var(--dur-5)}
  @keyframes enter{from{opacity:0; transform:translateY(18px)} to{opacity:1; transform:none}}
}

/* ==================================================================
   8 · BOTONES
   ================================================================== */
.cta{display:flex; gap:12px; justify-content:center; flex-wrap:wrap}
.btn{
  position:relative; overflow:hidden;
  display:inline-flex; align-items:center; justify-content:center; gap:9px; text-decoration:none;
  font-weight:650; font-size:.96rem; padding:15px 26px; border-radius:14px; line-height:1.2;
  border:1.5px solid transparent; cursor:pointer;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease,
             filter var(--dur-2) ease, border-color var(--dur-2) ease;
}
.btn .ic{width:19px; height:19px; transition:transform var(--dur-2) var(--ease-out)}
.btn:hover{text-decoration:none; transform:translateY(-2px)}
.btn:active{transform:translateY(0) scale(.985)}
.btn-primary{background:var(--primary); color:var(--on-primary); box-shadow:0 12px 28px -12px var(--primary)}
.btn-primary:hover{filter:brightness(1.06); box-shadow:0 18px 38px -14px var(--primary)}
.btn-ghost{background:var(--surface); color:var(--ink); border-color:var(--border); box-shadow:var(--shadow-sm)}
.btn-ghost:hover{box-shadow:var(--shadow); border-color:var(--edge)}
/* Botón de texto: la tercera acción, la que no compite con las otras
   dos. Solo una flecha que se desplaza. */
.btn-text{
  background:none; border:none; padding:14px 4px; color:var(--primary-ink);
  box-shadow:none; text-decoration:none;
}
.btn-text:hover{transform:none; text-decoration:underline}
.btn-text:hover .ic{transform:translateX(4px)}
.btn-sm{padding:11px 19px; font-size:.9rem; border-radius:11px}
.btn-lg{padding:18px 32px; font-size:1.04rem; border-radius:16px}
.btn-block{width:100%}
/* Barrido de luz, igual que el de la cabecera. */
.btn-primary::before{
  content:""; position:absolute; top:0; bottom:0; left:-140%; width:55%;
  background:linear-gradient(100deg, transparent, color-mix(in srgb, #fff 40%, transparent), transparent);
  transform:skewX(-18deg); pointer-events:none;
}
@media (prefers-reduced-motion:no-preference){
  .btn-primary:hover::before{animation:sheen .85s var(--ease-out)}
}

/* ==================================================================
   9 · CIFRAS
   ================================================================== */
.stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:14px; margin:0; padding:0; list-style:none}
.stats li{
  border-radius:var(--radius); padding:var(--s5) var(--s4); text-align:center;
  transition:transform var(--dur-2) var(--ease-out), border-color var(--dur-2) ease;
}
.stats li:hover{transform:translateY(-2px); border-color:var(--edge)}
.stats b{
  display:block; color:var(--ink); font-size:clamp(1.95rem,1.35rem + 1.6vw,2.75rem);
  font-family:var(--display); font-weight:600; letter-spacing:.005em; line-height:1.02;
  font-variant-numeric:tabular-nums; position:relative; z-index:1;
}
.stats span{display:block; font-size:var(--t-xs); color:var(--muted); margin-top:6px; line-height:1.45; position:relative; z-index:1}

/* ---------- banda de cifras grandes ----------
   Las mismas cifras sin tarjeta: números enormes separados por líneas.
   Es lo que hace Stripe con sus métricas y lo que hace que una cifra
   parezca un hecho y no un adorno. */
.numbers{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  list-style:none; margin:0; padding:0; gap:0;
}
.numbers li{padding:var(--s5) var(--s5); border-left:1px solid var(--border)}
.numbers li:first-child{border-left:none; padding-left:0}
@media (max-width:760px){
  .numbers{grid-template-columns:repeat(2,minmax(0,1fr))}
  .numbers li{padding:var(--s4) var(--s4)}
  .numbers li:nth-child(odd){border-left:none; padding-left:0}
  .numbers li:nth-child(n+3){border-top:1px solid var(--border)}
}
.numbers b{
  display:block; font-family:var(--display); font-weight:600;
  font-size:clamp(2.6rem,1.6rem + 3.4vw,4.6rem); line-height:.96;
  letter-spacing:-.02em; color:var(--ink); font-variant-numeric:tabular-nums;
}
.numbers span{display:block; margin-top:10px; font-size:var(--t-sm); color:var(--muted); line-height:1.5; max-width:24ch}
/* Las cifras entran barridas desde abajo, recortadas por su propia
   caja. Sin contador animado a propósito: un contador en JavaScript no
   cabe en esta CSP, y uno en CSS con `counter()` imprimiría «2160» sin
   el separador de millares, que en español es un error de ortografía. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .numbers li{animation:reveal linear both; animation-timeline:view(); animation-range:entry 0% cover 26%}
    .numbers li:nth-child(2){animation-range:entry 0% cover 32%}
    .numbers li:nth-child(3){animation-range:entry 0% cover 38%}
    .numbers li:nth-child(4){animation-range:entry 0% cover 44%}
  }
}

/* ==================================================================
   10 · CAPTURAS Y MEDIA
   ================================================================== */
.shots{
  display:flex; gap:24px; overflow-x:auto; padding:10px 4px 20px;
  scroll-snap-type:x mandatory; scrollbar-width:thin; scroll-padding-inline:var(--gut);
}
.shots figure{margin:0; flex:0 0 auto; width:244px; scroll-snap-align:center}
.shots figcaption{font-size:var(--t-xs); color:var(--muted); text-align:center; margin-top:var(--s4); line-height:1.5}

/* Marco de teléfono en CSS: un borde grueso muy redondeado. Sin imagen
   de móvil que pesar ni que se vea borrosa en pantallas densas. */
.phone{
  border:7px solid color-mix(in srgb, var(--ink) 88%, transparent);
  border-radius:34px; padding:0; overflow:hidden; background:var(--ink);
  box-shadow:var(--shadow-lg); position:relative;
  transition:transform var(--dur-3) var(--ease-out), box-shadow var(--dur-3) ease;
}
.phone img{border-radius:27px; display:block}
/* Muesca del altavoz. */
.phone::after{
  content:""; position:absolute; top:6px; left:50%; transform:translateX(-50%);
  width:34%; height:4px; border-radius:99px; background:color-mix(in srgb, var(--bg) 34%, transparent);
  z-index:2;
}
/* Reflejo de la pantalla: una diagonal muy tenue que cruza el cristal.
   Es lo que hace que el marco parezca un objeto y no un rectángulo. */
.phone::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none; border-radius:27px;
  background:linear-gradient(122deg, color-mix(in srgb,#fff 13%,transparent) 0 26%, transparent 44%);
}
.shots figure:hover .phone,.split .media:hover .phone{transform:translateY(-6px); box-shadow:var(--shadow-xl)}

/* ---------- marco de imagen editorial ----------
   Para la fotografía, no para las capturas. Redondeado, con la misma
   línea de luz que las tarjetas y un zoom lento al pasar por encima. */
.frame{
  position:relative; overflow:hidden; border-radius:var(--radius-xl); margin:0;
  background:var(--surface-2); border:1px solid var(--border); box-shadow:var(--shadow-lg);
}
.frame img{width:100%; height:100%; object-fit:cover; transition:transform var(--dur-5) var(--ease-out)}
.frame:hover img{transform:scale(1.04)}
.frame figcaption{
  position:absolute; left:0; right:0; bottom:0; padding:var(--s6) var(--s5) var(--s4);
  font-size:var(--t-sm); color:#fff; line-height:1.5;
  background:linear-gradient(transparent, rgba(0,0,0,.72));
}
.frame.ratio-wide{aspect-ratio:16/9}
.frame.ratio-tall{aspect-ratio:3/4}
.frame.ratio-square{aspect-ratio:1/1}

/* ---------- banda de media a sangre ----------
   Fotografía a todo lo ancho con el texto encima. Es el recurso de
   portada de Nike y de Adidas: una imagen que ocupa la pantalla y tres
   palabras. Se usa una vez por página como mucho. */
.band{
  position:relative; isolation:isolate; overflow:hidden;
  min-height:min(78vh,660px); display:grid; align-items:center;
  /* Fondo oscuro FIJO detrás de la foto, y no `var(--invert-bg)` ni transparente.
     La imagen va en diferido —está muy por debajo del pliegue—, así que durante un
     instante no hay nada debajo del velo: sin este color, el titular blanco aparece
     sobre el fondo claro de la página y no se lee. El color no sigue al tema porque el
     texto de la banda es blanco en los dos. */
  background:#0a0d0b;
}
.band > img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:-2;
}
/* Velo de contraste. Sin él, un titular blanco sobre una foto clara es
   ilegible justo en la mitad de los casos, y no se sabe en cuál. */
/* DOS velos, no uno, y el motivo está medido.
   El velo vertical tenía su punto MÁS DÉBIL (.34) al 42 % de la altura, que es
   exactamente donde caen el titular y la entradilla. Midiendo los píxeles reales
   de `hero.webp` bajo el titular: luminancia media .354 y máxima .859, o sea
   blanco sobre foto a **3,7:1 de media y 1,7:1 en las zonas más claras** — por
   debajo del 4,5:1 que este mismo proyecto exige (ver la nota de `--muted` arriba
   y scripts/test-dark-mode.mjs en la app).
   Subir el velo vertical hasta tapar los brillos ennegrecería la foto entera y
   la dejaría sin sentido. La solución es un segundo velo HORIZONTAL en el lado
   del texto: la columna de lectura queda garantizada y la mitad derecha de la
   imagen respira. Con esto la media sube a ~7:1 y el peor píxel a ~3,3:1
   (el titular es texto grande, cuyo mínimo AA es 3:1). */
.band::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    linear-gradient(90deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.55) 38%, rgba(0,0,0,0) 72%),
    linear-gradient(180deg, rgba(0,0,0,.58), rgba(0,0,0,.42) 42%, rgba(0,0,0,.74));
}
/* Y una sombra en el texto, que es la parte que el velo NO puede resolver.
   Medido sobre `hero.webp`: con los dos velos la media sube de 3,7:1 a ~8,5:1,
   pero la foto tiene brillos especulares (luminancia hasta .86) y ahí el peor
   píxel se queda en ~2,5:1. Subir más el velo para tapar esos brillos apaga la
   imagen entera y la deja sin función.
   La sombra resuelve justo eso: rodea el TRAZO de la letra de oscuro, así que la
   legibilidad deja de depender de qué píxel de la foto haya detrás. Es la técnica
   estándar para tipografía sobre fotografía, y aquí es lo que cubre ese ~4 % de
   superficie que el velo no puede alcanzar sin estropear el fondo. */
.band h1, .band h2, .band p, .band .kicker, .band .eyebrow{
  text-shadow: 0 1px 2px rgba(0,0,0,.55), 0 2px 14px rgba(0,0,0,.38);
}
/* Sin foto detrás no hay nada que compensar, y la sombra solo ensuciaría el texto. */
@media (prefers-reduced-transparency: reduce){
  .band h1, .band h2, .band p, .band .kicker, .band .eyebrow{ text-shadow:none }
}
/* En pantallas estrechas el texto ocupa TODO el ancho, así que un velo lateral
   no protege nada: ahí vuelve a mandar uno plano y parejo. */
@media (max-width:760px){
  .band::before{ background:linear-gradient(180deg, rgba(0,0,0,.66), rgba(0,0,0,.58) 42%, rgba(0,0,0,.78)); }
}
.band .wrap{padding-block:clamp(60px,9vw,120px); position:relative}
/* El titular de la banda necesita margen inferior EXPLÍCITO. Los `h*` nacen con
   `margin:0` (sección 2) y el párrafo que va debajo solo trae margen inferior, así
   que sin esto el titular y la entradilla se tocan — y en un titular de tres
   líneas sobre foto, tocarse se lee como un error de maquetación. */
.band h2,.band h1{color:#fff; max-width:15ch; margin-bottom:var(--s4)}
/* Subida de .82 a .94: encima de una foto, ese 18 % de transparencia se come casi
   un escalón entero de contraste justo en el texto de tamaño normal, que es el que
   más exige (4,5:1). Sobre un fondo plano no se nota; aquí sí. */
.band p{color:rgba(255,255,255,.94); max-width:52ch}
.band .eyebrow,.band .kicker{color:#fff}
.band .kicker::before{background:#fff}
/* El borde pasa de .34 a .62 de blanco: a .34, y sobre una foto clara, el límite
   del control no llegaba al 3:1 que pide la AA para elementos de interfaz — el
   botón se perdía en la imagen y dejaba de leerse como botón. */
.band .btn-ghost{background:rgba(255,255,255,.1); color:#fff; border-color:rgba(255,255,255,.62); backdrop-filter:blur(6px)}
.band .btn-ghost:hover{background:rgba(255,255,255,.18)}
/* Paralaje muy contenido: la imagen se desplaza un 8 % mientras la
   banda cruza la pantalla. Ligado al scroll, así que no hay ni un
   listener ni un `requestAnimationFrame`. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .band > img{
      animation:parallax linear both; animation-timeline:view(); animation-range:cover 0% cover 100%;
      height:116%; top:-8%;
    }
    @keyframes parallax{from{transform:translateY(-4%)} to{transform:translateY(4%)}}
  }
}

/* ==================================================================
   11 · REJILLAS DE TARJETAS
   ================================================================== */
/* `.grid` es para conjuntos de 3 o 6: `auto-fit` los reparte en 3
   columnas y salen filas llenas. Para conjuntos de 4 usa `.grid-2`, que
   fuerza 2×2: con `auto-fit` saldrían 3+1 y la tarjeta huérfana canta. */
.grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(282px,1fr)); gap:18px}
.grid-2{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px}
.grid-4{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px}
@media (max-width:900px){ .grid-4{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:760px){ .grid-2{grid-template-columns:1fr} }

.card{
  border-radius:var(--radius); padding:var(--s6) 28px;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease, border-color var(--dur-2) ease;
}
.card > *{position:relative; z-index:1}
.card:hover{transform:translateY(-4px); box-shadow:var(--shadow); border-color:var(--edge)}
.card h3{margin-bottom:9px}
.card p{font-size:var(--t-sm); margin-bottom:.8em}
.card ul{margin:var(--s3) 0 0; padding-left:19px; font-size:var(--t-sm)}
.card li{margin-bottom:7px}
.card li::marker{color:var(--primary)}
.card-note{font-size:var(--t-xs)!important; color:var(--muted); margin-top:var(--s3)!important; font-style:italic}
.card-link{margin-top:var(--s4)!important; font-size:var(--t-sm)!important}
.card-link a{display:inline-flex; align-items:center; gap:6px; font-weight:620; text-decoration:none}
.card-link a:hover{text-decoration:underline}
.card-link .ic{width:16px; height:16px; transition:transform var(--dur-2) var(--ease-out)}
.card-link a:hover .ic{transform:translateX(4px)}

/* ---------- bento ----------
   La rejilla de celdas de distinto tamaño que Apple usa desde 2022. No
   es decoración: es jerarquía. La celda ancha lleva la idea principal y
   las pequeñas los detalles, y se lee en ese orden sin necesidad de
   numerarlas.

   Doce columnas para poder decir «esta ocupa 7 y esta 5», que es lo que
   rompe la monotonía del 6+6. */
.bento{display:grid; grid-template-columns:repeat(12,minmax(0,1fr)); gap:16px; grid-auto-rows:minmax(0,auto)}
.bento > *{
  border-radius:var(--radius-xl); padding:clamp(24px,2.4vw,36px); grid-column:span 4;
  display:flex; flex-direction:column; overflow:hidden;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease, border-color var(--dur-2) ease;
}
.bento > *:hover{transform:translateY(-4px); box-shadow:var(--shadow); border-color:var(--edge)}
.bento > * > *{position:relative; z-index:1}
.bento h3{font-size:clamp(1.18rem,1.05rem + .6vw,1.55rem); margin-bottom:10px; letter-spacing:-.025em}
.bento p{font-size:var(--t-sm); color:var(--text)}
.bento .b-num{
  font-family:var(--display); font-weight:600; line-height:1;
  font-size:clamp(2.4rem,1.6rem + 2.6vw,3.6rem); color:var(--ink);
  letter-spacing:-.02em; margin-bottom:10px;
}
.bento .b-media{margin:auto -8px -14px; border-radius:var(--radius-sm); overflow:hidden}
.bento .b-media img{width:100%; display:block}
/* Anchos. Se combinan libremente mientras sumen 12 por fila. */
.b-3{grid-column:span 3} .b-4{grid-column:span 4} .b-5{grid-column:span 5}
.b-6{grid-column:span 6} .b-7{grid-column:span 7} .b-8{grid-column:span 8}
.b-9{grid-column:span 9} .b-12{grid-column:span 12}
.b-tall{grid-row:span 2}
/* Celda destacada: fondo tintado en vez de superficie plana. */
.bento .b-hi{
  background:linear-gradient(160deg, var(--tint), var(--tint-2) 60%, transparent), var(--surface);
  border-color:var(--tint-3);
}
@media (max-width:1000px){
  .bento{grid-template-columns:repeat(6,minmax(0,1fr))}
  .b-3,.b-4,.b-5{grid-column:span 3}
  .b-6,.b-7,.b-8,.b-9,.b-12{grid-column:span 6}
  .b-tall{grid-row:auto}
}
@media (max-width:640px){
  .bento{grid-template-columns:1fr}
  .bento > *,.b-3,.b-4,.b-5,.b-6,.b-7,.b-8,.b-9,.b-12{grid-column:1/-1}
}

/* ---------- rejilla de especificaciones ----------
   Etiqueta arriba, dato grande abajo, sin tarjeta. Para las fichas
   técnicas: qué plataformas, qué idiomas, qué versión. */
.spec{display:grid; grid-template-columns:repeat(auto-fit,minmax(184px,1fr)); gap:1px; background:var(--border); border:1px solid var(--border); border-radius:var(--radius); overflow:hidden}
.spec div{border:none; border-radius:0; box-shadow:none; padding:var(--s5)}
.spec dt,.spec .k{display:block; font-size:var(--t-xs); color:var(--muted); font-weight:600; letter-spacing:.03em; text-transform:var(--case-display); margin-bottom:8px}
.spec dd,.spec .v{margin:0; font-size:1.06rem; color:var(--ink); font-weight:650; line-height:1.35}

/* ---------- lista de verificación ---------- */
.checks{list-style:none; margin:0; padding:0; display:grid; gap:11px}
.checks li{display:flex; gap:11px; align-items:flex-start; font-size:var(--t-sm)}
.checks .ic{color:var(--primary-ink); margin-top:3px}

/* ==================================================================
   12 · EDITORIAL
   ================================================================== */

/* ---------- texto + captura alternos ---------- */
.split{display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(32px,5vw,76px); align-items:center}
.split + .split{margin-top:clamp(60px,8vw,116px)}
.split .media{display:flex; justify-content:center}
.split .phone{max-width:268px}
.split .txt h3{font-size:clamp(1.34rem,1.08rem + 1.2vw,2rem); margin-bottom:var(--s4); letter-spacing:-.028em}
.split .txt ul{margin:var(--s5) 0 0; padding-left:20px}
.split .txt li{margin-bottom:10px}
.split .txt li::marker{color:var(--primary)}
@media (max-width:820px){
  .split{grid-template-columns:1fr; gap:30px}
  .split.rev .media{order:-1}
}

/* ---------- relato con media fija ----------
   La columna de la imagen se queda pegada mientras la de texto pasa por
   delante. Es lo que hace Apple en las páginas de producto y lo que
   convierte tres párrafos sueltos en una secuencia.

   Sin JavaScript: `position:sticky` y ya. En móvil se deshace y vuelve
   a ser una columna, porque una imagen fija ocupando media pantalla en
   un teléfono deja al texto sin sitio. */
.story{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:clamp(32px,5vw,84px); align-items:start}
.story.rev .story-media{order:2}
.story-media{position:sticky; top:calc(var(--head-h) + 40px)}
.story-steps{display:grid; gap:clamp(48px,9vw,120px); padding-block:clamp(20px,4vw,60px)}
.story-steps > li{list-style:none}
.story-steps h3{font-size:clamp(1.3rem,1.1rem + 1vw,1.8rem); margin-bottom:var(--s3); letter-spacing:-.026em}
.story-steps p{font-size:var(--t-sm)}
.story-n{
  display:inline-grid; place-items:center; width:34px; height:34px; border-radius:11px;
  background:var(--tint); color:var(--primary-ink); font-family:var(--display);
  font-weight:700; font-size:.95rem; margin-bottom:var(--s3);
}
@media (max-width:900px){
  .story{grid-template-columns:1fr; gap:32px}
  .story.rev .story-media{order:-1}
  .story-media{position:static}
  .story-steps{gap:44px; padding-block:0}
}

/* ---------- marquesina ----------
   Una tira que se desplaza sin fin. Sirve para enseñar una lista larga
   sin gastar altura: las plataformas soportadas, los grupos musculares,
   las especialidades.

   El truco es duplicar el contenido en el HTML y desplazar el carril
   exactamente la mitad: al llegar al 50 % la copia está donde estaba el
   original y el salto no se ve. La copia va con `aria-hidden`, así que
   un lector de pantalla lee la lista una sola vez. */
.marquee{
  overflow:hidden; position:relative;
  /* Se desvanece por los dos lados en vez de cortarse a hachazo. */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
}
.marquee-track{display:flex; width:max-content; gap:0}
.marquee-track > *{
  display:flex; align-items:center; gap:14px; padding:0;
  list-style:none; margin:0;
}
.marquee li,.marquee-item{
  display:inline-flex; align-items:center; gap:10px; white-space:nowrap;
  padding:0 clamp(20px,3vw,44px);
  font-family:var(--display); font-stretch:var(--track-stretch); font-weight:600;
  font-size:clamp(1.1rem,.9rem + .9vw,1.7rem);
  letter-spacing:var(--track-display); text-transform:var(--case-display);
  color:var(--muted);
}
.marquee li::after,.marquee-item::after{
  content:""; width:6px; height:6px; border-radius:50%; background:var(--primary); flex:none; opacity:.55;
}
.marquee .ic{color:var(--primary-ink)}
@media (prefers-reduced-motion:no-preference){
  .marquee-track{animation:marquee 42s linear infinite}
  .marquee:hover .marquee-track{animation-play-state:paused}
  @keyframes marquee{to{transform:translateX(-50%)}}
}

/* ---------- carrusel con indicador ----------
   Desplazamiento horizontal con anclaje, más una barra que marca por
   dónde va. La barra está ligada al scroll DEL PROPIO carril
   (`scroll(self inline)`), así que refleja la posición real y no una
   estimación. */
.rail{position:relative}
.rail-track{
  display:flex; gap:18px; overflow-x:auto; padding:6px 4px 22px;
  scroll-snap-type:x mandatory; scroll-padding-inline:var(--gut);
  scrollbar-width:none;
}
.rail-track::-webkit-scrollbar{display:none}
.rail-track > *{flex:0 0 auto; scroll-snap-align:start; width:min(340px,78vw)}
.rail-bar{height:3px; border-radius:99px; background:var(--border); overflow:hidden; margin-top:var(--s2)}
.rail-bar::after{content:""; display:block; height:100%; width:34%; border-radius:99px; background:var(--primary); transform-origin:0 50%}
@supports (animation-timeline:scroll()){
  .rail-bar::after{
    width:100%; transform:scaleX(.2);
    animation:rail-progress linear both;
    animation-timeline:scroll(nearest inline);
  }
  /* El carril es el antecesor con scroll horizontal más cercano al
     indicador, así que hay que meterlo dentro para que `nearest` lo
     encuentre. Cuando el indicador va fuera, se usa la versión de
     respaldo de arriba. */
  @keyframes rail-progress{from{transform:scaleX(.2)} to{transform:scaleX(1)}}
}

/* ---------- cita destacada ----------
   El bloque editorial que da voz. En Somatryx va en serif y es lo que
   hace que la casa matriz suene distinta de sus dos productos. */
.pull{
  border-radius:var(--radius-xl); padding:clamp(30px,4vw,56px);
  border-left:3px solid var(--primary);
}
.pull p{
  /* `--serif` solo lo declara la marca que separa los dos roles (Somatryx: grotesca
     para titulares, serif para citas). Las demás caen en su propia display. */
  font-family:var(--serif, var(--display)); font-size:clamp(1.3rem,1.05rem + 1.3vw,2.1rem);
  line-height:1.32; letter-spacing:-.02em; color:var(--ink); font-weight:500;
  margin:0; text-wrap:balance; position:relative; z-index:1;
}
.pull footer,.pull .who{
  margin-top:var(--s5); font-size:var(--t-sm); color:var(--muted);
  font-family:var(--sans); position:relative; z-index:1;
}

/* ---------- línea de tiempo ---------- */
.timeline{list-style:none; margin:0; padding:0; display:grid; gap:14px}
.timeline li{
  border-radius:var(--radius); padding:var(--s5) var(--s5) var(--s5) 56px;
}
.timeline li::before{
  content:""; position:absolute; left:24px; top:30px; width:11px; height:11px;
  border-radius:50%; background:var(--primary); box-shadow:0 0 0 4px var(--tint); z-index:1;
}
.timeline h3{font-size:1.05rem; margin-bottom:6px}
.timeline p{font-size:var(--t-sm); margin:0}
.timeline time{display:block; font-size:var(--t-xs); color:var(--muted); margin-bottom:5px; font-variant-numeric:tabular-nums}

/* ---------- pasos numerados ----------
   El número lo pone el CSS con un contador: si mañana se añade un paso
   en medio, la numeración se recoloca sola. */
.steps{list-style:none; counter-reset:s; margin:0; padding:0; display:grid; gap:18px; grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.steps li{counter-increment:s; border-radius:var(--radius); padding:var(--s6)}
.steps li::before{
  content:counter(s); display:grid; place-items:center; width:34px; height:34px; border-radius:11px;
  background:var(--tint); color:var(--primary-ink); font-family:var(--display);
  font-weight:700; font-size:.95rem; margin-bottom:15px; position:relative; z-index:1;
}
.steps h3{margin-bottom:7px; position:relative; z-index:1}
.steps p{font-size:var(--t-sm); margin:0; position:relative; z-index:1}

/* ---------- cierre de página ---------- */
.closer .lede{max-width:620px; margin:var(--s4) auto var(--s6)}
/* Llamada final con fondo propio: cierra la página en vez de dejarla
   deshilachada contra el pie. */
.ctaband{
  border-radius:var(--radius-xl); padding:clamp(40px,6vw,88px) clamp(24px,4vw,60px);
  text-align:center; position:relative; overflow:hidden; isolation:isolate;
  background:
    radial-gradient(70% 130% at 50% 0%, var(--tint), transparent 70%),
    var(--surface);
  border:1px solid var(--border); box-shadow:var(--shadow);
}
.ctaband::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background-image:var(--grain-url); background-size:160px 160px;
  opacity:var(--grain); mix-blend-mode:overlay;
}
.ctaband h2{margin-bottom:var(--s4)}
.ctaband .lede{max-width:600px; margin:0 auto var(--s6); color:var(--muted)}

/* ==================================================================
   13 · TABLAS
   ================================================================== */
.table-wrap{overflow-x:auto; border-radius:var(--radius); background:var(--surface)}
table{border-collapse:collapse; width:100%; min-width:540px; font-size:var(--t-sm)}
caption{text-align:left; padding:16px 20px 0; color:var(--muted); font-size:var(--t-xs)}
th,td{text-align:left; padding:15px 20px; border-bottom:1px solid var(--border); vertical-align:top}
thead th{
  background:var(--surface-2); color:var(--ink); font-weight:700; font-size:var(--t-xs);
  text-transform:uppercase; letter-spacing:.05em; white-space:nowrap;
  position:sticky; top:0; z-index:1;
}
tbody th{color:var(--ink); font-weight:650}
tbody tr{transition:background var(--dur-1) ease}
tbody tr:hover{background:var(--tint-2)}
tr:last-child th,tr:last-child td{border-bottom:none}
td .yes{color:var(--primary-ink); font-weight:700}
td .no{color:var(--muted)}

/* ==================================================================
   14 · AVISOS
   ================================================================== */
.callout{
  display:flex; gap:15px; align-items:flex-start;
  border-left:3px solid var(--primary);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  padding:var(--s5) var(--s5); font-size:var(--t-sm);
}
.callout .ic{color:var(--primary-ink); margin-top:2px}
.callout.warn{border-left-color:#d98324}
.callout.warn .ic{color:#d98324}
.callout h3{font-size:1rem; margin-bottom:7px}
.callout p:last-child{margin-bottom:0}

/* ==================================================================
   15 · PLATAFORMAS
   ================================================================== */
.plats{display:grid; grid-template-columns:repeat(auto-fit,minmax(232px,1fr)); gap:16px}
.plat{
  border-radius:var(--radius); padding:var(--s6); text-decoration:none; color:inherit; display:block;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease, border-color var(--dur-2) ease;
}
.plat > *{position:relative; z-index:1}
a.plat:hover{transform:translateY(-4px); box-shadow:var(--shadow); text-decoration:none; border-color:var(--edge)}
.plat .ic{color:var(--primary-ink); margin-bottom:var(--s4); width:26px; height:26px; position:relative; z-index:1; transition:transform var(--dur-2) var(--ease-spring)}
a.plat:hover .ic{transform:scale(1.12) rotate(-4deg)}
.plat b{display:block; color:var(--ink); font-size:1.03rem; margin-bottom:5px}
.plat span{font-size:var(--t-sm); color:var(--muted); display:block; line-height:1.5}
.plat[aria-disabled="true"]{opacity:.62}
.badge{
  display:inline-block; font-size:.7rem; font-weight:720; letter-spacing:.05em; text-transform:uppercase;
  background:var(--surface-3); color:var(--primary-ink); border-radius:99px; padding:4px 10px; margin-top:11px;
}

/* ==================================================================
   16 · PLANES DE PRECIO
   ================================================================== */
.plans{display:grid; grid-template-columns:repeat(auto-fit,minmax(268px,1fr)); gap:18px; align-items:start}
.plan{border-radius:var(--radius); padding:32px 28px}
.plan > *{position:relative; z-index:1}
.plan.featured{border-color:var(--primary); box-shadow:var(--shadow); border-width:1.5px}
/* El plan destacado lleva un halo de color muy suave para que se
   distinga del de al lado sin cambiarle el tamaño. */
.plan.featured::after{box-shadow:inset 0 1px 0 var(--hairline), 0 0 0 4px var(--tint-2)}
.plan-tag{
  position:absolute; top:-12px; left:28px; background:var(--primary); color:var(--on-primary);
  font-size:.72rem; font-weight:740; letter-spacing:.05em; text-transform:uppercase;
  padding:5px 12px; border-radius:99px; z-index:2;
}
.plan h3{margin-bottom:12px}
.plan-price{display:flex; align-items:baseline; gap:7px; margin-bottom:10px!important}
.plan-price b{font-size:2.3rem; font-weight:800; letter-spacing:-.038em; color:var(--ink); line-height:1}
.plan-price span{font-size:var(--t-sm); color:var(--muted)}
.plan-blurb{font-size:var(--t-sm); color:var(--muted); margin-bottom:var(--s5)!important}
.plan .checks{margin-bottom:var(--s5)}
.plan-cta{margin:0!important}

/* ==================================================================
   17 · PREGUNTAS FRECUENTES
   ------------------------------------------------------------------
   `<details>` nativo: sin JavaScript, accesible por teclado sin
   programar nada, y el Ctrl+F del navegador encuentra dentro de los
   cerrados en Chrome.
   ================================================================== */
.faq{max-width:840px; margin:0 auto}
.faq details{border-radius:var(--radius-sm); margin-bottom:11px; overflow:hidden}
.faq details[open]{border-color:var(--edge)}
.faq summary{
  cursor:pointer; padding:20px 22px; font-weight:640; color:var(--ink); font-size:1.03rem;
  list-style:none; display:flex; align-items:flex-start; gap:14px;
  transition:background var(--dur-1) ease;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::before{
  content:""; flex:none; width:11px; height:11px; margin-top:8px;
  background:currentColor; color:var(--primary-ink);
  clip-path:polygon(46% 0,54% 0,54% 46%,100% 46%,100% 54%,54% 54%,54% 100%,46% 100%,46% 54%,0 54%,0 46%,46% 46%);
  transition:transform var(--dur-2) var(--ease-out);
}
.faq details[open] summary::before{transform:rotate(135deg)}
.faq summary:hover{background:var(--surface-2)}
.faq .answer{padding:2px 22px 24px 47px; font-size:var(--t-sm)}
.faq .answer ul{padding-left:19px; margin:10px 0 0}
.faq .answer li{margin-bottom:7px}
@media (prefers-reduced-motion:no-preference){
  .faq details[open] .answer{animation:answer var(--dur-3) var(--ease-out) both}
  @keyframes answer{from{opacity:0; transform:translateY(-6px)} to{opacity:1; transform:none}}
}
@media (max-width:540px){ .faq .answer{padding-left:22px} }

/* ==================================================================
   18 · NOVEDADES
   ================================================================== */
.log{max-width:820px; margin:0 auto}
.log article{border-radius:var(--radius); padding:var(--s6) 28px; margin-bottom:16px}
.log article > *{position:relative; z-index:1}
.log h3{display:flex; align-items:baseline; gap:14px; flex-wrap:wrap; margin-bottom:var(--s4)}
.log time{font-size:var(--t-xs); color:var(--muted); font-weight:500}
.log ul{margin:0; padding-left:19px; font-size:var(--t-sm)}
.log li{margin-bottom:8px}
.log li::marker{color:var(--primary)}

/* ==================================================================
   19 · PIE
   ================================================================== */
/* Va por CLASE y no por etiqueta. `<footer>` es un elemento legal dentro de
   `<article>`, `<section>` y `<blockquote>` —la atribución de una cita destacada usa uno,
   que es lo semánticamente correcto—, y un selector `footer{…}` a secas le encasquetaba
   a esa atribución el fondo, el borde superior y los 52 px de relleno del pie del sitio.
   El fallo era invisible en el HTML y evidente en pantalla. */

.site-foot{border-top:1px solid var(--border); background:var(--surface-2); padding:clamp(52px,6vw,80px) 0 40px; position:relative; overflow:hidden}
/* Marca + cinco columnas de enlaces. `minmax(0,1fr)` y no `1fr` a
   secas: sin el mínimo en cero, una etiqueta larga («Recuperación y
   wearables») ensancha su columna y descuadra las otras cuatro. */
.foot-grid{display:grid; grid-template-columns:1.3fr repeat(5,minmax(0,1fr)); gap:32px}
@media (max-width:1080px){ .foot-grid{grid-template-columns:repeat(3,minmax(0,1fr)); gap:30px} .foot-brand{grid-column:1/-1} }
@media (max-width:700px){ .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:460px){ .foot-grid{grid-template-columns:1fr} }
.foot-brand p{font-size:var(--t-sm); color:var(--muted); margin:var(--s4) 0 0; max-width:280px}

.site-foot h2{font-size:.79rem; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); margin-bottom:var(--s4); font-weight:740}
.site-foot ul{list-style:none; margin:0; padding:0}
.site-foot li{margin-bottom:9px}
.site-foot li a{color:var(--text); text-decoration:none; font-size:var(--t-sm); transition:color var(--dur-1) ease}
.site-foot li a:hover{color:var(--primary-ink); text-decoration:underline}
.foot-legal{
  margin:clamp(34px,4.4vw,52px) 0 0; padding-top:28px; border-top:1px solid var(--border);
  font-size:var(--t-xs); color:var(--muted); line-height:1.65; max-width:900px;
}
/* Crédito de la fotografía. Discreto pero VISIBLE y con el enlace real: los
   términos de la API de Pexels piden exactamente eso, y un crédito que nadie
   puede ver no cumple. Ver `mediaCredit()` en web/components.mjs. */
.foot-credit{margin:var(--s3) 0 0!important; font-size:var(--t-xs); color:var(--muted)}
.foot-credit a{color:var(--muted); text-decoration:underline; text-underline-offset:2px}
.foot-credit a:hover{color:var(--primary-ink)}
.foot-copy{margin:var(--s4) 0 0!important; font-size:var(--t-xs); color:var(--muted)}
/* Nombre de la marca gigante al fondo del pie, recortado por el borde
   inferior. Es la firma de la casa: ocupa el espacio muerto del final y
   no compite con nada porque va detrás de todo y muy apagado. */
.foot-word{
  position:absolute; left:0; right:0; bottom:-.28em; z-index:0; pointer-events:none;
  margin:0; text-align:center; user-select:none;
  font-family:var(--display); font-weight:700; line-height:.8;
  font-size:clamp(4rem,17vw,15rem); letter-spacing:-.045em;
  color:var(--ink); opacity:.045; text-transform:var(--case-display);
}
.site-foot .wrap{position:relative; z-index:1}

/* ==================================================================
   20 · PÁGINAS LEGALES
   ------------------------------------------------------------------
   Contenido largo de una sola columna: privacidad, términos y borrado
   de cuenta.
   ================================================================== */
.legal{max-width:var(--wrap-text); margin:0 auto; padding:clamp(32px,4vw,52px) 0 clamp(56px,6.5vw,88px)}
.legal h2{font-size:1.38rem; margin:48px 0 12px; scroll-margin-top:calc(var(--head-h) + 24px)}
.legal h3{font-size:1.08rem; margin:30px 0 10px}
.legal p,.legal li{font-size:var(--t-sm)}
.legal ul,.legal ol{padding-left:22px; margin:0 0 1em}
.legal li{margin-bottom:7px}
.legal table{min-width:0}
.legal .updated{color:var(--muted); font-size:var(--t-xs); margin-bottom:8px}
.legal .toc{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--radius);
  padding:24px 26px; margin:30px 0 44px; box-shadow:var(--shadow-sm);
}
.legal .toc h2{font-size:.79rem; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); margin:0 0 12px}
.legal .toc ol{margin:0; padding-left:20px; font-size:var(--t-sm); columns:2; column-gap:30px}
@media (max-width:640px){ .legal .toc ol{columns:1} }
.legal .toc li{margin-bottom:6px; break-inside:avoid}
/* Resumen destacado en cabeza del documento: lo que dice el texto legal
   en cuatro frases, para quien no va a leer las cuarenta. */
.legal .tldr{
  background:var(--tint-2); border:1px solid var(--tint-3); border-left:3px solid var(--primary);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  padding:var(--s5) var(--s5); margin:0 0 var(--s6); font-size:var(--t-sm);
}
.legal .tldr strong{color:var(--ink)}

/* ==================================================================
   21 · PANEL WEB (solo /panel — /en/dashboard)
   ================================================================== */
.panel-loading{display:grid; place-items:center; gap:16px; padding:120px 20px; color:var(--muted)}
.spinner{
  width:34px; height:34px; border-radius:50%; border:3px solid var(--border);
  border-top-color:var(--primary); animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

.panel-app{padding:clamp(30px,4vw,48px) var(--gut) clamp(56px,6.5vw,88px)}
.panel-head{display:flex; flex-wrap:wrap; gap:18px; align-items:flex-end; justify-content:space-between; margin-bottom:32px}
.panel-head h1{font-size:clamp(1.7rem,1.3rem + 1.6vw,2.4rem); margin-bottom:6px}
.panel-head .muted{font-size:var(--t-sm); margin:0}
.panel-actions{display:flex; gap:10px; flex-wrap:wrap}
.panel-empty{max-width:620px; margin:0 auto; padding:80px var(--gut); text-align:center}
.panel-empty h1{margin-bottom:16px}
.panel-empty .lede{margin-bottom:var(--s5)}

/* Fila de indicadores. `auto-fit` con mínimo pequeño para que en móvil
   salgan de dos en dos en vez de una columna de ocho tarjetas. */
.kpis{display:grid; grid-template-columns:repeat(auto-fit,minmax(178px,1fr)); gap:14px; margin-bottom:var(--s5)}
.kpi{border-radius:var(--radius-sm); padding:18px 20px}
.kpi > *{position:relative; z-index:1}
.kpi-l{display:block; font-size:var(--t-xs); color:var(--muted); font-weight:600; letter-spacing:.02em}
.kpi-v{display:block; font-size:clamp(1.5rem,1.2rem + .9vw,1.9rem); font-weight:800; color:var(--ink); letter-spacing:-.03em; line-height:1.15; margin:6px 0 3px; font-variant-numeric:tabular-nums}
.kpi-s{display:block; font-size:var(--t-xs); color:var(--muted); line-height:1.4}

.kpi-of{font-size:.62em; font-weight:650; color:var(--muted); letter-spacing:0}
/* Tono opcional de una cifra. Solo tres, y siempre acompañados de texto: el
   color no puede ser el único portador del significado. */
.kpi.k-ok{border-color:color-mix(in srgb,var(--primary) 30%,var(--border))}
.kpi.k-warn{border-color:color-mix(in srgb,#d98324 34%,var(--border))}
.kpi.k-bad{border-color:color-mix(in srgb,#d94a3d 34%,var(--border))}
/* Cifras secundarias dentro de una tarjeta: más pequeñas y sin superficie
   propia, para que no compitan con la rejilla de arriba. */
.mini-kpis{display:grid; grid-template-columns:repeat(auto-fit,minmax(118px,1fr)); gap:10px; margin-top:18px}
.mini-kpis .kpi{background:var(--surface-2); border-color:transparent; box-shadow:none; padding:12px 14px}
.mini-kpis .kpi::after{box-shadow:none}
.mini-kpis .kpi-v{font-size:1.12rem; margin:3px 0 2px}

/* Delta con flecha. La dirección «buena» la decide quien llama, porque subir
   de peso no es bueno ni malo sin saber el objetivo: por eso existe `.neu`. */
.dl{font-variant-numeric:tabular-nums; font-weight:660; white-space:nowrap}
.dl.up{color:var(--primary-ink)}
.dl.down{color:#b3372c}
.dl.neu{color:var(--muted)}
@media (prefers-color-scheme:dark){ .dl.down{color:#ff9d92} }

/* ---------- pestañas del panel ---------- */
.ptabs{
  display:flex; gap:4px; overflow-x:auto; scrollbar-width:none;
  border-bottom:1px solid var(--border); margin-bottom:var(--s5);
}
.ptabs::-webkit-scrollbar{display:none}
.ptab{
  flex:0 0 auto; font:inherit; font-size:var(--t-sm); font-weight:620; cursor:pointer;
  color:var(--muted); background:none; border:none; padding:12px 15px;
  border-bottom:2.5px solid transparent; margin-bottom:-1px; white-space:nowrap;
  transition:color var(--dur-1) ease, border-color var(--dur-1) ease;
}
.ptab:hover{color:var(--ink)}
.ptab.on{color:var(--primary-ink); border-bottom-color:var(--primary)}
.ptab:focus-visible{outline:2.5px solid var(--primary); outline-offset:-3px; border-radius:var(--radius-xs)}
.ptab-body:focus{outline:none}

/* Aviso de la demostración. Va arriba del todo y no se puede confundir con
   una tarjeta más: si alguien enseña una captura del panel, tiene que
   quedar claro que esos números no son de nadie. */
.demo-bar{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px 16px;
  background:var(--tint); border:1px solid var(--edge); border-radius:var(--radius-sm);
  padding:14px 18px; margin-bottom:var(--s5); font-size:var(--t-sm); color:var(--text);
}
.demo-bar strong{color:var(--primary-ink)}
.demo-bar .btn{margin-left:auto}

.pgrid{display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); gap:18px; margin-bottom:18px; align-items:start}
.pcard{border-radius:var(--radius); padding:var(--s5) var(--s6)}
.pcard > *{position:relative; z-index:1}
.pcard h2{font-size:1.05rem; margin-bottom:6px}
/* Una tarjeta ancha ocupa la rejilla entera. Sin esto, `auto-fit` la mete en
   una columna de 340 px y la tabla de dentro nace con scroll horizontal. */
.pcard.wide{grid-column:1/-1}
.pcard-note{font-size:var(--t-xs)!important; color:var(--muted); margin:16px 0 0!important; line-height:1.55}
.pc-sub{font-size:var(--t-xs)!important; color:var(--muted); margin:0 0 16px!important; line-height:1.5}
.pcard h2 + *:not(.pc-sub){margin-top:18px}
.pcard .table-wrap{box-shadow:none}
.p-empty{font-size:var(--t-sm); padding:26px 0; text-align:center; margin:0!important}

/* Pista de ayuda de una tarjeta: un signo de interrogación con `title`. */
.pc-hint{
  display:inline-grid; place-items:center; width:17px; height:17px; border-radius:50%;
  background:var(--surface-2); color:var(--muted); font-size:11px; font-weight:700;
  vertical-align:middle; cursor:help;
}

/* ---------- tablas ordenables ---------- */
.ptable .th-sort{
  font:inherit; font-weight:inherit; color:inherit; background:none; border:none;
  padding:0; cursor:pointer; display:inline-flex; align-items:center; gap:5px;
}
.ptable .th-sort:hover{color:var(--primary-ink)}
.ptable .th-sort:focus-visible{outline:2px solid var(--primary); outline-offset:3px; border-radius:3px}
.th-arrow{width:0; height:0; border-left:4px solid transparent; border-right:4px solid transparent; opacity:0}
.ptable th[aria-sort] .th-arrow{opacity:1}
.ptable th[aria-sort="ascending"] .th-arrow{border-bottom:5px solid var(--primary)}
.ptable th[aria-sort="descending"] .th-arrow{border-top:5px solid var(--primary)}
.ptable td.n,.ptable th.n{text-align:right; font-variant-numeric:tabular-nums}

/* ---------- selectores de una gráfica ---------- */
/* `.seg` ya existe arriba para el patrón input+label de las calculadoras. El
   panel construye sus segmentos con <button> porque los dibuja en vivo, así
   que necesita su propia pintura con el mismo aspecto. */
.seg-b{
  font:inherit; font-size:var(--t-xs); font-weight:620; cursor:pointer;
  padding:7px 13px; border-radius:99px; border:1px solid var(--border);
  background:var(--surface); color:var(--muted);
  transition:border-color var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease;
}
.seg-b:hover{border-color:var(--edge); color:var(--ink)}
.seg-b.on{background:var(--tint); border-color:var(--primary); color:var(--primary-ink)}
.seg-b:focus-visible{outline:2.5px solid var(--primary); outline-offset:2px}
.sel-row{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:16px}
.sel-row label{font-size:var(--t-xs); font-weight:660; color:var(--muted)}
.psel{
  font:inherit; font-size:var(--t-sm); padding:8px 12px; border-radius:var(--radius-xs);
  border:1.5px solid var(--border); background:var(--surface); color:var(--ink);
  max-width:100%; flex:1 1 200px;
}
.psel:focus-visible{border-color:var(--primary); outline:none; box-shadow:0 0 0 3px var(--tint)}

/* ==================================================================
   Gráficas interactivas del panel
   ------------------------------------------------------------------
   Todas comparten el mismo esqueleto: controles, un `.chart-box` que es
   el marco de referencia del globo de datos, el SVG y una leyenda.

   El globo (`.ch-tip`) se posiciona por CSSOM desde el JavaScript —la CSP
   del dominio es `style-src 'self'` y prohíbe el atributo `style=`, pero
   no `el.style.x`—, así que aquí solo se define su aspecto y el hecho de
   que no debe capturar el puntero: si lo capturara, aparecería bajo el
   ratón, robaría el `pointermove` del SVG y parpadearía sin parar.
   ================================================================== */
.chart-fig{margin:0}
.chart-ctl{display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px}
.chart-box{position:relative; touch-action:pan-y}
.chart{width:100%; height:auto; overflow:visible; display:block}
.chart:focus-visible{outline:2.5px solid var(--primary); outline-offset:4px; border-radius:var(--radius-xs)}
.ch-grid{stroke:var(--border); stroke-width:1}
.ch-lab{fill:var(--muted); font-size:11px; font-family:inherit}
/* COLOR POR CLASE, NO POR ATRIBUTO. El JavaScript solo decide un índice de serie
   y lo escribe como `s0`…`s5`; el color entero vive aquí abajo, en el bloque de
   la paleta. Por eso estas reglas llevan la FORMA y nada más: si alguna declarara
   un `stroke`, ganaría sobre la clase de paleta —misma especificidad, pero va
   antes— y dejaría las seis series del mismo verde. */
.ch-line{fill:none; stroke-width:2.4; stroke-linejoin:round; stroke-linecap:round}
.ch-line.dash{stroke-width:1.8; stroke-dasharray:5 4; opacity:.85}
.ch-area{stroke:none}
.ch-dot{stroke:var(--surface); stroke-width:1.5}
.ch-bar{transition:opacity var(--dur-1) ease}
.ch-goal{stroke:var(--muted); stroke-width:1.5; stroke-dasharray:5 4}
/* Franja de referencia (el rango objetivo de proteína, por ejemplo). */
.ch-band{fill:var(--surface-2)}
.ch-band.good{fill:var(--tint-2)}
/* La rejilla de captura: invisible pero es la que recibe el puntero. Sin
   `fill:transparent` el SVG no le entrega ningún evento —`fill:none` deja
   pasar el ratón a través— y la gráfica queda muerta al señalarla. */
.ch-hit{fill:transparent; cursor:crosshair}
/* Selección de arrastre. `pointer-events:none` es imprescindible: si capturara el
   puntero, el rectángulo se interpondría entre el ratón y la zona de captura en
   cuanto creciera y el arrastre se cortaría solo a los pocos píxeles. */
.ch-brush{fill:var(--tint-3); stroke:var(--primary); stroke-width:1; pointer-events:none}
.ch-cursor{stroke:var(--edge); stroke-width:1.5; stroke-dasharray:3 3; pointer-events:none}
.ch-focus{stroke:var(--surface); stroke-width:2.5; pointer-events:none}
.ch-bg{cursor:pointer}
.ch-bg .ch-bar{opacity:.78}
.ch-bg.on .ch-bar,.ch-bg:hover .ch-bar{opacity:1}
.ch-cap{font-size:var(--t-xs); color:var(--muted); margin-top:12px; line-height:1.5}

/* Globo de datos. `left`/`top` los pone el JavaScript; el `translateX(-50%)`
   lo ancla por su centro para que el cálculo de allí sea el del punto. */
.ch-tip{
  position:absolute; left:0; top:0; transform:translateX(-50%);
  pointer-events:none; z-index:3; min-width:112px; max-width:230px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xs);
  box-shadow:var(--shadow); padding:9px 11px; font-size:var(--t-xs); line-height:1.45;
}
.tip-d{display:block; color:var(--muted); font-weight:640; margin-bottom:5px; text-transform:capitalize}
.tip-r{display:flex; align-items:center; gap:7px; color:var(--text); white-space:nowrap}
.tip-r b{margin-left:auto; color:var(--ink); font-variant-numeric:tabular-nums; font-weight:700}
.tip-dot{width:9px; height:9px; border-radius:50%; flex:0 0 auto; background:var(--primary)}
.tip-n{display:block; margin-top:5px; color:var(--muted); font-style:italic}

/* Leyenda. En una gráfica de varias series los botones apagan y encienden
   cada una; en las apiladas es solo una clave y por eso existe `.static`. */
.chart-legend{display:flex; flex-wrap:wrap; gap:8px 16px; margin-top:14px}
.lg{
  display:inline-flex; align-items:center; gap:7px; font:inherit; font-size:var(--t-xs);
  font-weight:600; color:var(--text); background:none; border:none; padding:2px 0; cursor:pointer;
}
.lg.static{cursor:default}
.lg.off{color:var(--muted); text-decoration:line-through; opacity:.6}
.lg:not(.static):hover{color:var(--ink)}
.lg:focus-visible{outline:2px solid var(--primary); outline-offset:3px; border-radius:4px}
.lg-dot{width:10px; height:10px; border-radius:3px; flex:0 0 auto; background:var(--primary)}

/* ---------- anillo de reparto ---------- */
.donut-fig{margin:0; display:flex; flex-wrap:wrap; align-items:center; gap:22px}
.donut{width:190px; height:190px; flex:0 0 auto}
.dn-arc{cursor:pointer; transition:opacity var(--dur-1) ease}
.dn-arc.on{opacity:1}
.donut:hover .dn-arc:not(.on),.donut:focus-within .dn-arc:not(.on){opacity:.42}
.dn-arc:focus-visible{outline:2px solid var(--primary); outline-offset:2px}
.dn-v{fill:var(--ink); font-size:24px; font-weight:800; font-family:inherit; letter-spacing:-.02em}
.dn-l{fill:var(--muted); font-size:11px; font-family:inherit}
.dn-key{list-style:none; margin:0; padding:0; display:grid; gap:8px; flex:1 1 170px; min-width:160px}
.dn-key li{
  display:grid; grid-template-columns:auto 1fr auto auto; align-items:center; gap:9px;
  font-size:var(--t-xs); padding:4px 7px; margin:0 -7px; border-radius:var(--radius-xs);
  transition:background var(--dur-1) ease;
}
.dn-key li.on{background:var(--surface-2)}
.dn-n{color:var(--text); font-weight:600}
.dn-p{color:var(--ink); font-weight:700; font-variant-numeric:tabular-nums}
.dn-x{color:var(--muted); font-variant-numeric:tabular-nums}

/* ---------- calendario de actividad ---------- */
/* Un año son 53 columnas. En una pantalla estrecha se dejan encoger en vez
   de meter scroll horizontal: el patrón de huecos —que es lo que se viene a
   ver— se lee igual de bien pequeño. */
.cal-c{fill:var(--surface-2); transition:fill var(--dur-1) ease}
.cal-c.lv1{fill:color-mix(in srgb,var(--primary) 26%,var(--surface-2))}
.cal-c.lv2{fill:color-mix(in srgb,var(--primary) 48%,var(--surface-2))}
.cal-c.lv3{fill:color-mix(in srgb,var(--primary) 72%,var(--surface-2))}
.cal-c.lv4{fill:var(--primary)}
.cal-c.on{stroke:var(--ink); stroke-width:1.5}
.cal-m{fill:var(--muted); font-size:10px; font-family:inherit}
.cal-leg{display:flex; align-items:center; gap:5px; margin-top:12px; font-size:var(--t-xs); color:var(--muted)}
.cal-leg i{display:block; width:11px; height:11px; border-radius:2.5px; background:var(--surface-2)}
.cal-leg i.lv1{background:color-mix(in srgb,var(--primary) 26%,var(--surface-2))}
.cal-leg i.lv2{background:color-mix(in srgb,var(--primary) 48%,var(--surface-2))}
.cal-leg i.lv3{background:color-mix(in srgb,var(--primary) 72%,var(--surface-2))}
.cal-leg i.lv4{background:var(--primary)}

/* ---------- barra de volumen con MEV / MAV / MRV ---------- */
/* Las tres marcas se colocan por `left` desde el JavaScript. `overflow:hidden`
   NO: una marca justo en el borde se recortaría a la mitad. */
.vbar{position:relative; display:inline-block; width:100px; height:9px; border-radius:99px; background:var(--surface-2); vertical-align:middle}
.vbar-f{position:absolute; inset:0 auto 0 0; background:var(--primary); border-radius:99px}
.vbar-m{position:absolute; top:-3px; bottom:-3px; width:1.5px; background:var(--muted); opacity:.55}
.vbar-m.mrv{background:#d94a3d; opacity:.8}

/* ---------- medidor genérico ---------- */
.mtr{display:block; height:9px; border-radius:99px; background:var(--surface-2); overflow:hidden}
.mtr-f{display:block; height:100%; background:var(--primary); border-radius:99px; transition:width var(--dur-2) var(--ease-out)}

/* ---------- filas de objetivo ---------- */
.goalrows{list-style:none; margin:0; padding:0; display:grid; gap:14px}
.goalrows li{display:grid; grid-template-columns:minmax(92px,1.1fr) 2.2fr auto auto; align-items:center; gap:12px; font-size:var(--t-sm)}
.goalrows.big li{grid-template-columns:minmax(110px,1.2fr) 2fr auto auto auto}
.goalrows li.done .gr-l{color:var(--muted)}
.gr-l{color:var(--ink); font-weight:600; display:flex; align-items:center; gap:7px; flex-wrap:wrap}
.gr-v{color:var(--ink); font-variant-numeric:tabular-nums; white-space:nowrap}
.gr-p{font-weight:700; font-variant-numeric:tabular-nums; min-width:46px; text-align:right}
.gr-p.ok{color:var(--primary-ink)}
.gr-p.hi{color:#a4611a}
.gr-p.lo{color:#b3372c}
.gr-x{color:var(--muted); font-size:var(--t-xs); white-space:nowrap; text-align:right}
@media (prefers-color-scheme:dark){ .gr-p.hi{color:#f0b46a} .gr-p.lo{color:#ff9d92} }
@media (max-width:640px){
  .goalrows li,.goalrows.big li{grid-template-columns:1fr auto; gap:6px 10px}
  .goalrows .mtr{grid-column:1/-1; order:3}
  .goalrows .gr-x{grid-column:1/-1; order:4; text-align:left}
}

/* ---------- lecturas del resumen ----------
   Cada una lleva una barra de color a la izquierda, pero el color NUNCA es lo
   único que dice el tono: el texto del título ya lo dice con palabras. Es la
   condición para que sirva en escala de grises y con daltonismo. */
.reads{list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:14px}
.rd{display:grid; grid-template-columns:auto 1fr; gap:14px; padding:15px 17px; border-radius:var(--radius-sm); background:var(--surface-2)}
.rd-b{width:4px; border-radius:99px; background:var(--muted)}
.rd.r-good .rd-b{background:var(--primary)}
.rd.r-warn .rd-b{background:#d98324}
.rd.r-bad .rd-b{background:#d94a3d}
.rd.r-info .rd-b{background:var(--edge)}
.rd b{display:block; color:var(--ink); font-size:var(--t-sm); font-weight:680; margin-bottom:5px; line-height:1.35}
.rd p{font-size:var(--t-xs); color:var(--text); line-height:1.55; margin:0!important}
.rd-go{
  font:inherit; font-size:var(--t-xs); font-weight:640; color:var(--primary-ink);
  background:none; border:none; padding:0; margin-top:9px; cursor:pointer;
}
.rd-go:hover{text-decoration:underline}
.rd-go:focus-visible{outline:2px solid var(--primary); outline-offset:3px; border-radius:3px}

/* ---------- las tres coberturas ---------- */
.covers{list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(270px,1fr)); gap:20px}
.cv{display:grid; grid-template-columns:1fr auto; gap:7px 12px; align-content:start}
.cv-l{color:var(--ink); font-weight:660; font-size:var(--t-sm)}
.cv-v{font-size:var(--t-sm); text-align:right; font-variant-numeric:tabular-nums}
.cv-v b{color:var(--ink); font-size:1.25rem; font-weight:800}
.cv .mtr{grid-column:1/-1}
.cv-h{grid-column:1/-1; font-size:var(--t-xs); color:var(--muted); line-height:1.45}
.cv.none .cv-v{font-size:var(--t-sm)}

/* ---------- señales de recuperación con minigráfica ---------- */
.sigs{list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:16px}
.sigs li{display:grid; grid-template-columns:1fr auto; gap:3px 12px; align-items:baseline; padding:14px 16px; border-radius:var(--radius-sm); background:var(--surface-2)}
.sg-l{color:var(--muted); font-size:var(--t-xs); font-weight:640}
.sg-v{grid-row:2; color:var(--ink); font-size:1.45rem; font-weight:800; letter-spacing:-.03em; font-variant-numeric:tabular-nums}
.sg-u{font-size:.62em; font-weight:650; color:var(--muted); margin-left:2px}
.sg-d{grid-row:3; grid-column:1/-1; font-size:var(--t-xs); margin-top:2px}
.sg-s{grid-row:1/3; grid-column:2; align-self:center}
/* La minigráfica reserva su hueco aunque no haya serie que dibujar (`.empty`),
   para que la fila no dé un salto de 38 px según haya datos o no. */
.spark{display:block; width:110px; height:38px; overflow:visible}
.sp-line{fill:none; stroke-width:2; stroke-linejoin:round; stroke-linecap:round}
.sp-area{stroke:none; opacity:.9}
.sp-dot{stroke:var(--surface-2); stroke-width:1.5}

/* ---------- listas de últimos entrenos y récords ---------- */
.feed{list-style:none; margin:0; padding:0; display:grid; gap:1px; background:var(--border); border-radius:var(--radius-sm); overflow:hidden}
.feed li{display:grid; grid-template-columns:auto 1fr; gap:2px 12px; padding:11px 14px; background:var(--surface); font-size:var(--t-sm)}
.fd-d{color:var(--muted); font-size:var(--t-xs); font-variant-numeric:tabular-nums; white-space:nowrap}
.fd-n{color:var(--ink); font-weight:620}
.fd-x{grid-column:1/-1; color:var(--muted); font-size:var(--t-xs); font-variant-numeric:tabular-nums}
.fd-x b{color:var(--primary-ink); font-weight:700}

/* ---------- fichas sueltas (músculos sin tocar) ---------- */
.chips{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:8px}
.chip{
  display:inline-flex; align-items:baseline; gap:7px; font-size:var(--t-xs); font-weight:620;
  padding:6px 12px; border-radius:99px; border:1px solid var(--border);
  background:var(--surface-2); color:var(--ink);
}
.chip span{color:var(--muted); font-weight:500}
.chip.warn{border-color:color-mix(in srgb,#d98324 36%,transparent); background:color-mix(in srgb,#d98324 10%,transparent)}

/* ---------- logros ---------- */
.ach{list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:10px}
.ach li{
  display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto; gap:2px 12px;
  align-items:center; padding:12px 14px; border-radius:var(--radius-sm);
  background:var(--surface-2); border:1px solid transparent;
}
.ach.locked li{background:none; border-color:var(--border); opacity:.72}
.ach-ic{grid-row:1/3; font-size:1.5rem; line-height:1; filter:saturate(1.1)}
.ach.locked .ach-ic{filter:grayscale(1); opacity:.7}
.ach-n{color:var(--ink); font-weight:660; font-size:var(--t-sm)}
.ach-d{color:var(--muted); font-size:var(--t-xs); line-height:1.4}
.ach-x{grid-column:2; color:var(--primary-ink); font-size:var(--t-xs); font-weight:640; margin-top:3px}
.ach.locked .ach-x{color:var(--muted)}

/* ---------- paleta categórica de las gráficas ----------
   Vive en el CSS y NO en el JavaScript a propósito: así el tema oscuro la
   cambia solo, la leyenda y la línea nunca se desincronizan (el panel lee
   estas mismas variables con `getComputedStyle`) y un cambio de marca no
   obliga a tocar código. Seis colores porque ninguna gráfica del panel
   pinta más series que eso; el séptimo daría la vuelta y repetiría.

   El primero es el primario de la marca, que es el que se lleva la serie
   protagonista. Los otros cinco se eligieron con dos condiciones: 3:1
   contra la superficie (son grafismo, no texto) y distinguibles entre sí
   en deuteranopía, que es la carencia de color más frecuente — por eso no
   hay un rojo y un verde compitiendo, sino que el contraste se apoya
   también en claro/oscuro. */
:root{
  --pc1:var(--primary);        --pc1-fill:color-mix(in srgb,var(--primary) 14%,transparent);
  --pc2:#2f6f8f;               --pc2-fill:color-mix(in srgb,#2f6f8f 14%,transparent);
  --pc3:#b5751b;               --pc3-fill:color-mix(in srgb,#b5751b 14%,transparent);
  --pc4:#8a5cc4;               --pc4-fill:color-mix(in srgb,#8a5cc4 14%,transparent);
  --pc5:#b34a63;               --pc5-fill:color-mix(in srgb,#b34a63 14%,transparent);
  --pc6:#4d6b52;               --pc6-fill:color-mix(in srgb,#4d6b52 14%,transparent);
}
/* Aplicación de la paleta. Una serie lleva la clase `s0`…`s5` y de aquí saca su
   color, sea trazo, relleno o fondo según el elemento. Escrito a mano y no
   generado porque son seis y se leen mejor así que con un bucle de preprocesador
   que este proyecto no tiene. */
.ch-line.s0,.sp-line.s0,.dn-arc.s0{stroke:var(--pc1)}
.ch-line.s1,.sp-line.s1,.dn-arc.s1{stroke:var(--pc2)}
.ch-line.s2,.sp-line.s2,.dn-arc.s2{stroke:var(--pc3)}
.ch-line.s3,.sp-line.s3,.dn-arc.s3{stroke:var(--pc4)}
.ch-line.s4,.sp-line.s4,.dn-arc.s4{stroke:var(--pc5)}
.ch-line.s5,.sp-line.s5,.dn-arc.s5{stroke:var(--pc6)}

.ch-dot.s0,.ch-focus.s0,.ch-bar.s0,.sp-dot.s0{fill:var(--pc1)}
.ch-dot.s1,.ch-focus.s1,.ch-bar.s1,.sp-dot.s1{fill:var(--pc2)}
.ch-dot.s2,.ch-focus.s2,.ch-bar.s2,.sp-dot.s2{fill:var(--pc3)}
.ch-dot.s3,.ch-focus.s3,.ch-bar.s3,.sp-dot.s3{fill:var(--pc4)}
.ch-dot.s4,.ch-focus.s4,.ch-bar.s4,.sp-dot.s4{fill:var(--pc5)}
.ch-dot.s5,.ch-focus.s5,.ch-bar.s5,.sp-dot.s5{fill:var(--pc6)}

.ch-area.s0,.sp-area.s0{fill:var(--pc1-fill)}
.ch-area.s1,.sp-area.s1{fill:var(--pc2-fill)}
.ch-area.s2,.sp-area.s2{fill:var(--pc3-fill)}
.ch-area.s3,.sp-area.s3{fill:var(--pc4-fill)}
.ch-area.s4,.sp-area.s4{fill:var(--pc5-fill)}
.ch-area.s5,.sp-area.s5{fill:var(--pc6-fill)}

.lg-dot.s0,.tip-dot.s0{background:var(--pc1)}
.lg-dot.s1,.tip-dot.s1{background:var(--pc2)}
.lg-dot.s2,.tip-dot.s2{background:var(--pc3)}
.lg-dot.s3,.tip-dot.s3{background:var(--pc4)}
.lg-dot.s4,.tip-dot.s4{background:var(--pc5)}
.lg-dot.s5,.tip-dot.s5{background:var(--pc6)}

/* La barra a cero de una gráfica no es una serie: es el hueco de un día sin
   registrar y se pinta con el borde, no con un color de paleta. */
.ch-bar.zero{fill:var(--border)}

/* En oscuro los mismos tonos se aclaran: un #2f6f8f sobre un fondo casi negro
   se queda en 2:1 y la línea desaparece. */
@media (prefers-color-scheme:dark){
  :root{
    --pc1:#8ccb4e;             --pc1-fill:color-mix(in srgb,#8ccb4e 16%,transparent);
    --pc2:#6cb8d8;             --pc2-fill:color-mix(in srgb,#6cb8d8 16%,transparent);
    --pc3:#e0a84e;             --pc3-fill:color-mix(in srgb,#e0a84e 16%,transparent);
    --pc4:#b492e6;             --pc4-fill:color-mix(in srgb,#b492e6 16%,transparent);
    --pc5:#e58aa1;             --pc5-fill:color-mix(in srgb,#e58aa1 16%,transparent);
    --pc6:#8fb896;             --pc6-fill:color-mix(in srgb,#8fb896 16%,transparent);
  }
}

/* Veredicto de volumen frente a los rangos de referencia. */
.vtag{
  display:inline-block; font-size:var(--t-xs); font-weight:660; border-radius:99px;
  padding:3px 10px; border:1px solid; white-space:nowrap;
}
.vtag.ok{background:var(--tint); color:var(--primary-ink); border-color:color-mix(in srgb,var(--primary) 34%,transparent)}
.vtag.high{background:color-mix(in srgb,#d98324 12%,transparent); color:#a4611a; border-color:color-mix(in srgb,#d98324 30%,transparent)}
.vtag.low,.vtag.over{background:color-mix(in srgb,#d94a3d 12%,transparent); color:#b3372c; border-color:color-mix(in srgb,#d94a3d 30%,transparent)}
@media (prefers-color-scheme:dark){
  .vtag.high{color:#f0b46a} .vtag.low,.vtag.over{color:#ff9d92}
}

/* Ranking de barras horizontales (volumen por músculo). */
.rank{list-style:none; margin:0; padding:0; display:grid; gap:11px}
.rank li{display:grid; grid-template-columns:minmax(96px,1.1fr) 3fr auto; align-items:center; gap:12px; font-size:var(--t-sm)}
.rank-l{color:var(--ink); font-weight:560}
.rank-t{background:var(--surface-2); border-radius:99px; height:11px; overflow:hidden}
.rank-f{display:block; height:100%; background:var(--primary); border-radius:99px; transition:width var(--dur-2) var(--ease-out)}
/* El veredicto tiñe la barra, pero nunca es lo único que lo dice: la tabla de
   debajo lo repite con palabras. El color solo adelanta la lectura. */
.rank-f.t-low{background:#c0632a}
.rank-f.t-over{background:#c04a3d}
.rank-v{color:var(--muted); font-variant-numeric:tabular-nums; min-width:38px; text-align:right}
@media (max-width:520px){ .rank li{grid-template-columns:minmax(78px,1fr) 2fr auto; gap:8px} }

/* ==================================================================
   Informe imprimible del panel (el «Descargar PDF»)
   ------------------------------------------------------------------
   No se ve NUNCA en pantalla: solo existe para el diálogo de impresión,
   donde todos los navegadores ofrecen «Guardar como PDF». Por eso el PDF
   sale con texto de verdad —seleccionable, buscable y legible por un
   lector de pantalla— y con las gráficas vectoriales, cosa que ninguna
   biblioteca que rasteriza la pantalla puede dar.

   OJO: se oculta con una CLASE y no con el atributo `hidden`. El reset de
   este archivo trae `[hidden]{display:none!important}` —hizo falta para
   otro bug del panel— y ese `!important` no lo levanta ninguna regla de
   `@media print`. Con `hidden` puesto, el informe no se imprimiría nunca.
   ================================================================== */
.preport{display:none}

/* ---------- acceso ---------- */
.login-wrap{display:grid; grid-template-columns:minmax(0,420px) minmax(0,1fr); gap:clamp(30px,5vw,64px); align-items:start; max-width:940px; margin:0 auto}
@media (max-width:800px){ .login-wrap{grid-template-columns:1fr} .login-side{order:-1} }
.login-card{border-radius:var(--radius); padding:32px 28px; box-shadow:var(--shadow)}
.login-card > *{position:relative; z-index:1}
.login-card h2{font-size:1.25rem; margin-bottom:6px}
.login-card #pGoogle{margin-top:20px}
.login-card label{display:block; font-size:var(--t-xs); font-weight:660; color:var(--ink); margin:16px 0 6px}
.login-card input{
  width:100%; font:inherit; font-size:.95rem; padding:12px 14px; border-radius:var(--radius-xs);
  border:1.5px solid var(--border); background:var(--bg); color:var(--ink);
}
.login-card input:focus-visible{border-color:var(--primary); outline:none; box-shadow:0 0 0 3px var(--tint)}
.login-card #pSubmit{margin-top:22px}
.login-sep{display:flex; align-items:center; gap:14px; margin:22px 0 4px; color:var(--muted); font-size:var(--t-xs)}
.login-sep::before,.login-sep::after{content:""; flex:1; height:1px; background:var(--border)}
.login-forgot{margin:16px 0 0!important; font-size:var(--t-xs); text-align:center}
.login-foot{margin:20px 0 0!important; padding-top:18px; border-top:1px solid var(--border); font-size:var(--t-xs); color:var(--muted)}
.login-side h2{font-size:1.15rem; margin-bottom:18px}

.panel-msg{margin:14px 0 0!important; font-size:var(--t-sm); padding:11px 14px; border-radius:var(--radius-xs); border:1px solid}
.panel-msg.err{background:color-mix(in srgb,#d94a3d 10%,transparent); border-color:color-mix(in srgb,#d94a3d 34%,transparent); color:#b3372c}
.panel-msg.ok{background:var(--tint); border-color:color-mix(in srgb,var(--primary) 34%,transparent); color:var(--primary-ink)}
@media (prefers-color-scheme:dark){ .panel-msg.err{color:#ff9d92} }

/* ====================================================================
   22 · BIBLIOTECA PÚBLICA
   --------------------------------------------------------------------
   Ejercicios, suplementos, mitos, guías, glosario, síntomas, atlas.
   Estas páginas no son marketing: son el contenido de la app publicado
   tal cual. Por eso priorizan la lectura y el escaneo por encima del
   efecto — sin degradados de portada, con más densidad y con el dato
   siempre delante.
   ==================================================================== */

/* ---------- migas de pan ---------- */
.crumbs{border-bottom:1px solid var(--border); background:var(--surface-2)}
.crumbs ol{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px;
  list-style:none; margin:0; padding:11px 0; font-size:var(--t-xs);
}
.crumbs li{display:flex; align-items:center; gap:6px; color:var(--muted)}
/* El separador lo pone el CSS y no el HTML: así no lo lee un lector de pantalla. */
.crumbs li+li::before{content:"›"; color:var(--border); font-size:1.05rem; line-height:1}
.crumbs a{color:var(--muted); text-decoration:none}
.crumbs a:hover{color:var(--primary-ink); text-decoration:underline}
.crumbs [aria-current]{color:var(--ink); font-weight:600}

/* ---------- barra de filtros ----------
   Pegajosa bajo la cabecera: con 306 tarjetas, perder el buscador al
   desplazarse obliga a subir del todo para cambiar un filtro. */
.lib-bar{
  position:sticky; top:var(--head-h); z-index:var(--z-bar);
  background:color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter:saturate(170%) blur(14px); -webkit-backdrop-filter:saturate(170%) blur(14px);
  border-bottom:1px solid var(--border); padding:14px 0;
}
.lib-bar .wrap{display:flex; flex-wrap:wrap; gap:10px; align-items:center}
.lib-search{
  flex:1 1 260px; min-width:0; font:inherit; font-size:.95rem; padding:12px 14px 12px 40px;
  border-radius:var(--radius-xs); border:1.5px solid var(--border); background:var(--surface); color:var(--ink);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7a63' stroke-width='1.9' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.6'/%3E%3Cpath d='M16 16l4.4 4.4'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:12px center; background-size:18px;
  transition:border-color var(--dur-1) ease, box-shadow var(--dur-1) ease;
}
.lib-search:focus-visible{border-color:var(--primary); outline:none; box-shadow:0 0 0 3px var(--tint)}
.lib-sel{
  font:inherit; font-size:.9rem; padding:12px 32px 12px 13px; border-radius:var(--radius-xs);
  border:1.5px solid var(--border); background:var(--surface); color:var(--ink); cursor:pointer;
  appearance:none; -webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7a63' stroke-width='2' stroke-linecap='round'%3E%3Cpolyline points='6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 9px center; background-size:16px;
}
.lib-count{font-size:var(--t-xs); color:var(--muted); margin-left:auto; font-variant-numeric:tabular-nums}
/* La barra nace OCULTA y solo la enseña `.js`, que añade el propio
   script al arrancar. Invertido a propósito: si el script no carga, no
   aparece un buscador que no busca — la lista completa sigue ahí abajo,
   enlazada y legible, que es lo que importa. */
.lib-bar{display:none}
.js .lib-bar{display:block}
@media (max-width:640px){ .lib-count{margin-left:0; width:100%} }

/* ---------- rejilla de fichas ---------- */
.lib-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(238px,1fr)); gap:16px}
.lib-card{
  display:flex; flex-direction:column; border-radius:var(--radius-sm);
  overflow:hidden; text-decoration:none; color:inherit;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease, border-color var(--dur-2) ease;
}
.lib-card:hover{transform:translateY(-4px); text-decoration:none; box-shadow:var(--shadow); border-color:var(--edge)}
.lib-card .thumb{background:var(--surface-2); aspect-ratio:1/1; display:grid; place-items:center; overflow:hidden}
.lib-card .thumb img{width:100%; height:100%; object-fit:cover; transition:transform var(--dur-4) var(--ease-out)}
.lib-card:hover .thumb img{transform:scale(1.05)}
.lib-card .thumb.none{color:var(--border)}
.lib-card .thumb.none .ic{width:44px; height:44px}
.lib-card .body{padding:15px 17px 17px; display:flex; flex-direction:column; gap:7px; flex:1; position:relative; z-index:1}
.lib-card b{color:var(--ink); font-size:.97rem; font-weight:650; line-height:1.32; letter-spacing:-.012em}
.lib-card .meta{font-size:var(--t-xs); color:var(--muted); line-height:1.45; margin-top:auto}
.lib-hidden{display:none!important}
.lib-empty{text-align:center; padding:60px 20px; color:var(--muted)}

/* ---------- lista densa ----------
   Variante para las colecciones SIN miniatura: síntomas, fármacos,
   términos del glosario, guías. Con 1.082 fichas, una rejilla de
   tarjetas cuadradas obliga a recorrer tres pantallas de hueco para ver
   lo que en una lista cabe de un vistazo. */
.lib-grid.rows{grid-template-columns:repeat(auto-fill,minmax(min(100%,330px),1fr)); gap:10px}
.lib-grid.rows .lib-card{flex-direction:row; align-items:center}
.lib-grid.rows .lib-card .body{padding:13px 16px; gap:3px}
.lib-grid.rows .lib-card .meta{margin-top:0}
.lib-grid.rows .lib-card:hover{transform:translateX(3px)}

/* Secciones dentro de un índice. El grupo entero es el que se oculta
   cuando el filtro deja su lista a cero: un encabezado «Cardiología»
   encima de ningún resultado es peor que no tener encabezado. */
.lib-sections{display:flex; flex-direction:column; gap:clamp(28px,3.2vw,42px)}
.lib-section > h2{font-size:var(--t-h3); margin:0 0 3px; scroll-margin-top:calc(var(--head-h) + 60px)}
.lib-section > p{font-size:var(--t-xs); color:var(--muted); margin:0 0 13px}

/* ---------- etiquetas ---------- */
.tags{display:flex; flex-wrap:wrap; gap:7px; list-style:none; margin:0; padding:0}
.tag{
  display:inline-flex; align-items:center; gap:5px; font-size:var(--t-xs); font-weight:600;
  background:var(--surface-2); color:var(--text); border:1px solid var(--border);
  border-radius:99px; padding:4px 11px; text-decoration:none; line-height:1.5;
  transition:border-color var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease;
}
a.tag:hover{border-color:var(--primary); color:var(--primary-ink); background:var(--tint-2); text-decoration:none}
.tag.on{background:var(--tint); color:var(--primary-ink); border-color:var(--tint-3)}
.tag.warn{background:color-mix(in srgb,#d98324 12%,transparent); color:#a4611a; border-color:color-mix(in srgb,#d98324 30%,transparent)}
.tag.bad{background:color-mix(in srgb,#d94a3d 12%,transparent); color:#b3372c; border-color:color-mix(in srgb,#d94a3d 30%,transparent)}
@media (prefers-color-scheme:dark){
  .tag.warn{color:#f0b46a} .tag.bad{color:#ff9d92}
}

/* ---------- ficha de detalle (dos columnas) ---------- */
.detail{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,320px);
  gap:clamp(30px,4.4vw,60px); align-items:start;
  padding:clamp(32px,4vw,52px) 0 clamp(56px,6.5vw,88px);
}
@media (max-width:900px){ .detail{grid-template-columns:1fr} .detail .aside{order:-1} }
.detail h1{font-size:clamp(1.8rem,1.35rem + 1.9vw,2.85rem); margin-bottom:12px}
.detail .lede{margin-bottom:var(--s5)}
.detail h2{font-size:1.3rem; margin:40px 0 14px}
.detail h2:first-child{margin-top:0}
.detail h3{font-size:1.05rem; margin:26px 0 9px}
.detail p,.detail li{font-size:var(--t-sm)}
.detail ol,.detail ul{padding-left:21px; margin:0 0 1em}
.detail li{margin-bottom:9px}
.detail li::marker{color:var(--primary)}

/* Columna lateral pegajosa: la animación y los datos rápidos acompañan
   mientras se lee la técnica. Se despega en móvil. */
.detail .aside{position:sticky; top:calc(var(--head-h) + 22px); display:grid; gap:16px}
@media (max-width:900px){ .detail .aside{position:static} }

/* Animación del ejercicio. Cuadrada porque así vienen las de la app. */
.exanim{border-radius:var(--radius); overflow:hidden; margin:0}
.exanim img{width:100%; object-fit:cover; background:var(--surface-2)}
/* La proporción cuadrada se declara con `:not(.fit)` y no en `.exanim img` a secas.
   Parece un rodeo y es justo lo contrario: es lo que permite que la variante `.fit` NO
   declare `aspect-ratio` en absoluto.
   ------------------------------------------------------------------
   El motivo, comprobado en el navegador y no deducido: cuando una <img> trae `width` y
   `height`, el navegador le asigna `aspect-ratio: auto 900 / 600` — «usa la proporción
   natural y, mientras no la tengas, la de los atributos». Esa segunda mitad es la que
   reserva el hueco durante la descarga. Y `aspect-ratio:auto` escrito en la hoja de
   estilos NO es equivalente: sustituye la declaración entera y se lleva por delante el
   `900/600`, con lo que la imagen se queda en alto 0 hasta que carga.
   Medido en la ficha del atlas: caja de 398×0 con `aspect-ratio:auto`, y 400×267 sin
   declarar nada. Era el salto de maquetación de las 1.112 fichas, y no lo arreglaban los
   atributos por sí solos: hacía falta además dejar de pisarlos desde aquí.
   Y `revert` tampoco sirve — la proporción de los atributos no es una regla de la hoja
   del navegador que se pueda restaurar, sino el tamaño natural del objeto. La única
   forma de conservarla es no declarar nada encima. */
.exanim:not(.fit) img{aspect-ratio:1/1}
.exanim figcaption{font-size:var(--t-xs); color:var(--muted); padding:11px 15px; border-top:1px solid var(--border)}
/* Sin recortar: una animación de ejercicio es cuadrada y se puede
   encajar, pero un ECG de 12 derivaciones o una radiografía de tórax
   son apaisados y `object-fit:cover` les corta justo el borde donde
   está el hallazgo. Aquí la imagen manda sobre la caja. */
.exanim.fit img{object-fit:contain; height:auto}

/* Lista de datos rápidos: etiqueta a la izquierda, valor a la derecha. */
.facts{border-radius:var(--radius); padding:8px 20px; margin:0}
.facts div{display:flex; gap:14px; justify-content:space-between; align-items:baseline; padding:12px 0; border-bottom:1px solid var(--border)}
.facts div:last-child{border-bottom:none}
.facts dt{font-size:var(--t-xs); color:var(--muted); font-weight:600; flex:none}
.facts dd{margin:0; font-size:var(--t-sm); color:var(--ink); font-weight:560; text-align:right}

/* Cues y errores: dos listas con el mismo peso visual y signo opuesto. */
.cues,.errs{list-style:none; padding:0; margin:0; display:grid; gap:11px}
.cues li,.errs li{display:flex; gap:11px; align-items:flex-start; font-size:var(--t-sm)}
.cues li::before,.errs li::before{
  content:""; flex:none; width:19px; height:19px; margin-top:2px; border-radius:50%;
  background-repeat:no-repeat; background-position:center; background-size:13px;
}
.cues li::before{
  background-color:var(--tint);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234f8f06' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 12.5 10 17.5 19 6.5'/%3E%3C/svg%3E");
}
.errs li::before{
  background-color:color-mix(in srgb,#d94a3d 13%,transparent);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c0392b' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M7 7l10 10M17 7L7 17'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme:dark){
  .cues li::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a5ed45' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 12.5 10 17.5 19 6.5'/%3E%3C/svg%3E")}
  .errs li::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ff9d92' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M7 7l10 10M17 7L7 17'/%3E%3C/svg%3E")}
}

/* ---------- veredicto de un mito ---------- */
.verdict{
  display:flex; align-items:center; gap:14px; border-radius:var(--radius);
  padding:19px 23px; margin-bottom:var(--s5); border:1px solid; font-weight:650;
  background:color-mix(in srgb,#d94a3d 9%,transparent); border-color:color-mix(in srgb,#d94a3d 28%,transparent); color:#b3372c;
}
.verdict b{font-family:var(--display); font-size:1.4rem; font-weight:600; letter-spacing:.03em; text-transform:uppercase; color:inherit}
.verdict.ok{background:var(--tint); border-color:var(--tint-3); color:var(--primary-ink)}
.verdict.mid{background:color-mix(in srgb,#d98324 11%,transparent); border-color:color-mix(in srgb,#d98324 30%,transparent); color:#a4611a}
@media (prefers-color-scheme:dark){ .verdict{color:#ff9d92} .verdict.mid{color:#f0b46a} }

/* Barra de nivel de evidencia: cinco tramos, los llenos en color de marca. */
.eviscale{display:flex; gap:4px; align-items:center}
.eviscale i{width:20px; height:7px; border-radius:99px; background:var(--border)}
.eviscale i.on{background:var(--primary)}

/* ---------- glosario ----------
   187 términos en una sola página con anclas, y no 187 páginas de dos
   líneas: una definición suelta no sostiene una página propia, y Google
   trata un montón de páginas casi vacías como contenido de relleno. */
.gloss{display:grid; gap:12px}
.gloss article{border-radius:var(--radius-sm); padding:20px 22px; scroll-margin-top:calc(var(--head-h) + 84px)}
.gloss article > *{position:relative; z-index:1}
.gloss h3{font-size:1.05rem; margin-bottom:7px; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap}
.gloss h3 .tag{font-weight:600}
.gloss p{font-size:var(--t-sm); margin:0}
.gloss .syn{font-size:var(--t-xs); color:var(--muted); margin-top:9px!important}
/* Índice alfabético que salta a cada letra. */
.alpha{display:flex; flex-wrap:wrap; gap:5px; margin-bottom:var(--s5); justify-content:center}
.alpha a{
  display:grid; place-items:center; min-width:32px; height:32px; padding:0 7px;
  border-radius:9px; border:1px solid var(--border); background:var(--surface);
  font-size:var(--t-sm); font-weight:650; color:var(--text); text-decoration:none;
  transition:border-color var(--dur-1) ease, color var(--dur-1) ease, transform var(--dur-1) var(--ease-out);
}
.alpha a:hover{border-color:var(--primary); color:var(--primary-ink); text-decoration:none; transform:translateY(-2px)}
.gloss-letter{
  font-family:var(--display); font-size:1.55rem; font-weight:600; color:var(--primary-ink);
  margin:34px 0 12px; scroll-margin-top:calc(var(--head-h) + 84px); letter-spacing:.04em;
}
.gloss-letter:first-child{margin-top:0}

/* ---------- calculadoras ---------- */
.calc{border-radius:var(--radius); padding:clamp(24px,3vw,36px); box-shadow:var(--shadow)}
.calc > *{position:relative; z-index:1}
.calc-fields{display:grid; grid-template-columns:repeat(auto-fit,minmax(158px,1fr)); gap:16px}
.calc label{display:block; font-size:var(--t-xs); font-weight:660; color:var(--ink); margin-bottom:6px}
.calc input,.calc select{
  width:100%; font:inherit; font-size:.95rem; padding:12px 13px; border-radius:var(--radius-xs);
  border:1.5px solid var(--border); background:var(--bg); color:var(--ink);
  transition:border-color var(--dur-1) ease, box-shadow var(--dur-1) ease;
}
.calc input:focus-visible,.calc select:focus-visible{border-color:var(--primary); outline:none; box-shadow:0 0 0 3px var(--tint)}
.calc .hint{font-size:var(--t-xs); color:var(--muted); margin:6px 0 0}
/* Grupo de botones tipo radio (sexo, objetivo, actividad). */
.seg{display:flex; flex-wrap:wrap; gap:6px}
.seg input{position:absolute; opacity:0; width:0; height:0}
.seg label{
  margin:0; cursor:pointer; font-size:var(--t-sm); font-weight:600; padding:10px 16px;
  border-radius:99px; border:1.5px solid var(--border); background:var(--bg); color:var(--text);
  transition:background var(--dur-1) ease, border-color var(--dur-1) ease, color var(--dur-1) ease;
}
.seg label:hover{border-color:var(--edge)}
.seg input:checked + label{background:var(--tint); border-color:var(--primary); color:var(--primary-ink)}
.seg input:focus-visible + label{outline:2.5px solid var(--primary); outline-offset:2px}

.calc-out{margin-top:var(--s5); padding-top:var(--s5); border-top:1px solid var(--border)}
.calc-res{display:grid; grid-template-columns:repeat(auto-fit,minmax(132px,1fr)); gap:13px}
.calc-res div{background:var(--surface-2); border:1px solid var(--border); border-radius:var(--radius-sm); padding:18px; text-align:center}
.calc-res b{
  display:block; font-family:var(--mono); font-size:clamp(1.4rem,1.15rem + .85vw,1.9rem);
  font-weight:700; color:var(--ink); letter-spacing:-.02em; line-height:1.1; font-variant-numeric:tabular-nums;
}
.calc-res span{display:block; font-size:var(--t-xs); color:var(--muted); margin-top:6px; line-height:1.4}
.calc-res .hi{background:var(--tint); border-color:var(--tint-3)}
.calc-res .hi b{color:var(--primary-ink)}
/* Sin JavaScript una calculadora no calcula. Así que el formulario nace
   oculto y en su lugar se ve un aviso; `.js` invierte las dos cosas.
   Nunca se enseña un formulario muerto que parece roto. */
.calc-live{display:none}
.js .calc-live{display:block}
.js .calc-nojs{display:none}

/* ---------- rejilla de índice de secciones ---------- */
.tiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(252px,1fr)); gap:16px}
.tile{
  display:block; border-radius:var(--radius); padding:var(--s5) var(--s6);
  text-decoration:none; color:inherit;
  transition:transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) ease, border-color var(--dur-2) ease;
}
.tile > *{position:relative; z-index:1}
.tile:hover{transform:translateY(-4px); box-shadow:var(--shadow); text-decoration:none; border-color:var(--edge)}
.tile .ic{color:var(--primary-ink); margin-bottom:13px; position:relative; z-index:1}
.tile b{display:block; color:var(--ink); font-size:1.06rem; margin-bottom:6px}
.tile span{display:block; font-size:var(--t-sm); color:var(--muted); line-height:1.5}
.tile .n{font-family:var(--display); font-weight:600; color:var(--primary-ink); font-size:.9rem; letter-spacing:.04em}

/* ---------- índice interno de una guía ---------- */
.guide-toc{padding:20px 22px}
.guide-toc h2{font-size:.79rem; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); margin:0 0 12px; font-weight:740}
.guide-toc ol{margin:0; padding-left:19px; font-size:var(--t-sm)}
.guide-toc li{margin-bottom:8px}
.guide-toc li::marker{color:var(--primary); font-variant-numeric:tabular-nums}
.guide-toc a{color:var(--text); text-decoration:none}
.guide-toc a:hover{color:var(--primary-ink); text-decoration:underline}
/* Cada sección de una guía va separada por una línea fina: son bloques
   largos y sin respiro visual se leen como un muro. */
.guide-sec + .guide-sec{margin-top:36px; padding-top:34px; border-top:1px solid var(--border)}

/* ---------- navegación entre fichas ---------- */
.prevnext{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-top:48px; padding-top:30px; border-top:1px solid var(--border)}
@media (max-width:600px){ .prevnext{grid-template-columns:1fr} }
.prevnext a{
  display:block; padding:17px 20px; border-radius:var(--radius-sm);
  text-decoration:none; color:inherit;
  transition:border-color var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
}
.prevnext a:hover{border-color:var(--primary); text-decoration:none}
.prevnext a:first-child:hover{transform:translateX(-3px)}
.prevnext .next:hover{transform:translateX(3px)}
.prevnext span{display:block; font-size:var(--t-xs); color:var(--muted); margin-bottom:4px}
.prevnext b{color:var(--ink); font-size:var(--t-sm); font-weight:640}
.prevnext .next{text-align:right}

/* ====================================================================
   23 · MOVIMIENTO AL ENTRAR EN PANTALLA
   --------------------------------------------------------------------
   Solo donde el navegador lo soporta de forma nativa
   (`animation-timeline: view()`). Sin JavaScript, sin
   IntersectionObserver y sin el riesgo clásico de dejar contenido
   invisible para siempre si el script falla: si no hay soporte, no hay
   animación y el contenido se ve, que es lo único que importa.

   El escalonado dentro de una fila se consigue variando el RANGO por
   posición, no con un `animation-delay`: en una animación ligada al
   scroll el retardo no existe (no hay tiempo, hay recorrido), así que
   lo que se retrasa es el tramo en el que cada elemento completa su
   entrada.
   ==================================================================== */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    :where(.stats li,.card,.plat,.steps li,.plan,.split,.log article,.tile,
           .bento > *,.timeline li,.spec div,.pull,.frame,.story-steps > li,
           .ctaband,.numbers li,.table-wrap,.faq details){
      animation:reveal linear both;
      animation-timeline:view();
      animation-range:entry 0% cover 28%;
    }
    :where(.grid,.grid-2,.grid-4,.tiles,.plats,.plans,.stats,.steps,.bento,.spec,.lib-grid) > *:nth-child(2){animation-range:entry 0% cover 34%}
    :where(.grid,.grid-2,.grid-4,.tiles,.plats,.plans,.stats,.steps,.bento,.spec,.lib-grid) > *:nth-child(3){animation-range:entry 0% cover 40%}
    :where(.grid,.grid-2,.grid-4,.tiles,.plats,.plans,.stats,.steps,.bento,.spec,.lib-grid) > *:nth-child(4){animation-range:entry 0% cover 46%}
    @keyframes reveal{from{opacity:0; transform:translateY(18px)} to{opacity:1; transform:none}}

    /* Los encabezados de sección entran igual, pero sin desplazamiento
       lateral y un poco antes: si el titular aparece a la vez que las
       tarjetas, la sección entera parpadea. */
    .section-head{animation:reveal-soft linear both; animation-timeline:view(); animation-range:entry 0% cover 22%}
    @keyframes reveal-soft{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
  }
}

/* ====================================================================
   24 · PREFERENCIAS Y MEDIOS
   ==================================================================== */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important; animation-iteration-count:1!important;
    transition-duration:.001ms!important; scroll-behavior:auto!important;
  }
  /* La marquesina no se puede «acelerar»: se para y se deja como una
     lista normal que se puede desplazar a mano. */
  .marquee-track{animation:none!important; transform:none!important}
  .marquee{overflow-x:auto}
}

/* Modo de contraste forzado de Windows. El sistema sustituye los
   colores, así que lo único que hay que hacer es devolver los bordes
   que se pierden y asegurar que lo dibujado con `currentColor`
   (iconos, máscaras) sigue el color del sistema. */
@media (forced-colors:active){
  .card,.plat,.plan,.tile,.stats li,.bento > *,.lib-card,.faq details,.table-wrap{border:1px solid CanvasText}
  .btn{border:1px solid ButtonText}
  .brand-mark,.brand-word,.hero-mark{background:CanvasText}
  .head-progress,.rail-bar::after,.rank-f{background:Highlight}
  .hero::before,.hero::after,.mesh::after,.grainy::before,.ctaband::before{display:none}
}

/* ---------- impresión ---------- */
@media print{
  .site-head,.site-foot,.cta,.skip,.trustbar,.lib-bar,.marquee,.ctaband,.head-progress,.foot-word{display:none!important}
  body{background:#fff; color:#000}
  .card,.plan,.plat,.table-wrap,.bento > *{box-shadow:none; border-color:#ccc}
  .band > img{position:static; height:auto}
  .band::before{display:none}
  /* Sin velo y con el texto ya en negro sobre papel blanco, la sombra que
     compensa la foto en pantalla solo emborronaría la letra impresa. */
  .band h2,.band p{color:#000}
  .band h1,.band h2,.band p,.band .kicker,.band .eyebrow{text-shadow:none}
  a[href^="http"]::after{content:" (" attr(href) ")"; font-size:.75em; color:#555}

  @page{margin:14mm 12mm}

  /* --- Panel: se imprime el INFORME, no la pantalla ---
     La pantalla son siete pestañas y solo una está a la vista: imprimirla
     dejaría fuera seis séptimas partes de los datos justo en el documento
     que alguien se lleva a una consulta. */
  .panel-head,.head-kpis,.ptabs,.ptab-body,.demo-bar,.panel-loading,.panel-actions{display:none!important}
  .preport{display:block}
  .panel-app{padding:0}

  /* Los neutros y la paleta se fijan al tema CLARO. Si no, quien tenga el
     sistema en oscuro imprime el verde claro de la paleta oscura sobre papel
     blanco y las líneas se ven lavadas — y el texto atenuado, directamente no
     se ve. La impresión no hereda el tema: se elige. */
  :root{
    --bg:#fff; --surface:#fff; --surface-2:#f2f2f2; --surface-3:#e8e8e8;
    --ink:#000; --text:#1a1a1a; --muted:#555; --border:#bbb;
    --hairline:transparent; --shadow:none; --shadow-sm:none;
    --pc1:#3d6f05; --pc2:#255a75; --pc3:#8f5c13; --pc4:#6c46a0;
    --pc5:#93384f; --pc6:#3d5642;
  }

  /* Los navegadores quitan fondos e imágenes al imprimir para ahorrar tinta.
     En una gráfica, ese «ahorro» borra justamente el dato: las barras del
     ranking y los medidores se imprimirían vacíos. */
  .rank-f,.mtr-f,.vbar-f,.vbar-m,.rd-b,.ch-band{print-color-adjust:exact; -webkit-print-color-adjust:exact}

  .preport{color:#000; font-size:10.5pt; line-height:1.5}
  .prep-head{border-bottom:2px solid #000; padding-bottom:10px; margin-bottom:18px}
  .prep-brand{font-family:var(--display); font-weight:700; letter-spacing:.08em; text-transform:uppercase; font-size:9pt}
  .prep-head h1{font-size:20pt; margin:6px 0 4px}
  .prep-meta{font-size:9pt; color:#555; margin:0!important}
  .prep-demo{border:1.5px solid #000; padding:7px 10px; margin:10px 0 0!important; font-size:9pt}

  /* `break-inside:avoid` en cada sección, y `break-after:avoid` en los
     titulares: sin lo segundo salen encabezados solos al pie de una página
     con su tabla empezando en la siguiente. */
  /* `padding:0` no es cosmético: el sitio da a todo `<section>` un respiro de
     página (`section{padding:clamp(64px,8.5vw,132px) 0}`) y aquí eso son 148 px de
     aire por sección — casi un cuarto de folio en blanco entre cada dos bloques,
     multiplicado por nueve secciones. */
  .prep-sec{break-inside:avoid; margin-bottom:16px; padding:0}
  .prep-sec h2{font-size:12pt; margin:0 0 8px; padding-bottom:4px; border-bottom:1px solid #999; break-after:avoid}
  .prep-note{font-size:8.5pt; color:#555; line-height:1.45; margin:7px 0 0!important}

  .prep-t{width:100%; min-width:0; border-collapse:collapse; font-size:9.5pt}
  .prep-t th,.prep-t td{border-bottom:1px solid #ddd; padding:4px 7px; text-align:left; vertical-align:top}
  .prep-t thead th{border-bottom:1px solid #666; font-weight:700; font-size:8.5pt; text-transform:uppercase; letter-spacing:.03em}
  .prep-t .n{text-align:right; font-variant-numeric:tabular-nums}
  .prep-t tbody th{font-weight:600}
  .prep-t.two tbody th{width:42%}
  .prep-t.two td:last-child{color:#555; font-size:8.5pt}

  .prep-reads{list-style:none; margin:0; padding:0}
  .prep-reads li{border-left:3px solid #666; padding:2px 0 2px 9px; margin-bottom:7px; font-size:9.5pt; break-inside:avoid}
  .prep-reads li.r-bad{border-left-color:#000; border-left-width:4px}
  .prep-reads b{display:block}

  .prep-foot{border-top:1px solid #999; margin-top:20px; padding-top:9px; font-size:8pt; color:#555}
  .prep-foot p{margin:0 0 3px!important}

  /* Dentro del informe, las gráficas van sin sus mandos: en papel no se puede
     pulsar «90 d», y una fila de botones impresa solo gasta tinta. */
  .preport .chart-ctl,.preport .ch-tip,.preport .cal-leg{display:none!important}
  .preport .chart-fig{margin-top:8px; break-inside:avoid}
  .preport .chart-legend{margin-top:6px; font-size:8.5pt}
  /* Sin esto, un SVG que en pantalla mide 760 de ancho se lleva media página
     de alto en A4 y el informe se estira a diez folios. */
  .preport .chart{max-height:62mm}
}

/* ====================================================================
   25 · UTILIDADES DE ESPACIADO Y TIPOGRAFÍA
   --------------------------------------------------------------------
   Existen por una razón de seguridad, no de estilo. La CSP de los tres
   sitios lleva `style-src 'self'` SIN `'unsafe-inline'`, y esa
   directiva no solo bloquea `<style>`: también bloquea los atributos
   `style="…"` sueltos (en CSP 3, `style-src-attr` hereda de
   `style-src`).

   O sea que cada `style="margin-top:30px"` que quedaba en las páginas
   se descartaba en producción: el sitio se veía con el espaciado roto y
   en local, sin cabeceras, no se notaba.

   La alternativa era añadir `'unsafe-inline'` y perder la protección
   entera. Estas clases son la otra: el espaciado vuelve a aplicarse y
   la política se queda igual de cerrada.

   No es un sistema de utilidades al estilo Tailwind ni pretende serlo:
   son exactamente los valores que las páginas ya usaban.
   ==================================================================== */

.mt-18 { margin-top: 18px }
.mt-20 { margin-top: 20px }
.mt-22 { margin-top: 22px }
.mt-24 { margin-top: 24px }
.mt-26 { margin-top: 26px }
.mt-28 { margin-top: 28px }
.mt-30 { margin-top: 30px }
.mt-32 { margin-top: 32px }
.mt-34 { margin-top: 34px }
.mt-36 { margin-top: 36px }
.mt-44 { margin-top: 44px }
.mt-56 { margin-top: 56px }
.mb-24 { margin-bottom: 24px }
.mb-44 { margin-bottom: 44px }
.my-22 { margin-top: 22px; margin-bottom: 22px }
/* El resumen destacado de los documentos legales: párrafos muy juntos. */
.my-tight { margin: .2em 0 }

/* Bloques centrados con ancho de lectura. El `margin:Npx auto 0`
   original se parte en dos: la clase pone el centrado y el margen
   superior lo elige la utilidad `.mt-*` correspondiente. */
.block-600 { max-width: 600px; margin-left: auto; margin-right: auto }
.block-820 { max-width: 820px; margin-left: auto; margin-right: auto }
.block-840 { max-width: 840px; margin-left: auto; margin-right: auto }
/* Entradilla suelta bajo un titular: centrada, con aire arriba y abajo. */
.lede-block { max-width: 600px; margin: 16px auto 28px }
.lede-block-narrow { margin: 18px auto 26px }

.fs-xs { font-size: var(--t-xs) }
.fs-sm { font-size: var(--t-sm) }
.fs-105 { font-size: 1.05rem }
.fs-135 { font-size: 1.35em }
/* `.card-note` va en cursiva por defecto; esta lo devuelve a redonda
   cuando el contenido es una cita bibliográfica y la cursiva estorba. */
.fst-normal { font-style: normal }

/* ====================================================================
   26 · MOVIMIENTO v3
   --------------------------------------------------------------------
   Todo lo que hay de aquí abajo obedece las mismas dos reglas que el
   resto del archivo, y conviene repetirlas porque aquí es donde más
   tienta saltárselas:

     · `script-src 'none'`: no hay JavaScript. Ni un
       IntersectionObserver, ni un `requestAnimationFrame`, ni una
       librería de scroll. Lo que no sepa hacer el navegador solo, no se
       hace.
     · `style-src 'self'` sin `'unsafe-inline'`: tampoco hay atributos
       `style="--x:3"`. Por eso los mandos que en otro sitio serían una
       variable en línea (cuántas láminas tiene un escaparate) aquí son
       clases contadas: `.showcase-3`, `.showcase-4`…

   La consecuencia práctica es que TODO lo de abajo está envuelto en
   `@supports` y en `prefers-reduced-motion:no-preference`. Donde el
   navegador no llega, no hay animación y el contenido se ve. Un
   revelado que se queda a medias y deja una sección en blanco para
   siempre es infinitamente peor que no tener revelado.
   ==================================================================== */

/* ==================================================================
   26.1 · PROPIEDADES REGISTRADAS
   ------------------------------------------------------------------
   Una variable CSS normal no se puede animar: el navegador no sabe si
   `20%` es un número, un color o una cadena, así que salta del valor
   inicial al final sin pasar por el medio. `@property` le dice el tipo
   y a partir de ahí la interpola.

   Es lo que hace posible casi todo lo de abajo —el barrido del titular,
   el degradado que gira, la cortina de las imágenes— sin una sola línea
   de JavaScript.
   ================================================================== */
@property --sweep      { syntax:'<percentage>'; inherits:false; initial-value:130% }
@property --curtain    { syntax:'<percentage>'; inherits:false; initial-value:0% }
@property --grad-angle { syntax:'<angle>';      inherits:false; initial-value:102deg }
@property --shine      { syntax:'<percentage>'; inherits:false; initial-value:-40% }

/* ==================================================================
   26.2 · TRANSICIONES ENTRE PÁGINAS
   ------------------------------------------------------------------
   `@view-transition` con navegación automática: al pasar de una página
   a otra del mismo origen, el navegador hace un fundido cruzado del
   documento entero en vez del parpadeo en blanco de siempre. Dos
   líneas, cero JavaScript, y es lo que separa un sitio estático de algo
   que se siente como una aplicación.

   Importa especialmente aquí: entre las tres webs hay ~4.600 páginas y
   la navegación por la biblioteca —síntoma, ficha, síntoma— es un ir y
   venir constante. Cada salto era un fogonazo en blanco.

   Los elementos con `view-transition-name` quedan FUERA del fundido y
   se animan por su cuenta. La cabecera y el pie llevan nombre porque
   son idénticos en las dos páginas: sin nombre se desvanecerían y
   volverían a aparecer, que es justo lo que delata que ha habido una
   recarga.
   ================================================================== */
@view-transition{ navigation:auto }

@media (prefers-reduced-motion:no-preference){
  ::view-transition-group(root){ animation-duration:.34s; animation-timing-function:var(--ease-out) }
  /* El contenido nuevo entra subiendo un pelo; el viejo solo se apaga.
     Si los dos se mueven, el cruce se ve sucio. */
  ::view-transition-new(root){ animation-name:vt-in }
  ::view-transition-old(root){ animation-name:vt-out }
  @keyframes vt-in { from{ opacity:0; transform:translateY(10px) } }
  @keyframes vt-out{ to  { opacity:0 } }
}
@media (prefers-reduced-motion:reduce){
  /* No se desactiva la transición: se deja instantánea. Quitarla del todo
     devuelve el parpadeo en blanco, que para alguien sensible al
     movimiento es peor que un corte limpio. */
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){ animation:none!important }
}
.site-head{ view-transition-name:head }
.site-foot{ view-transition-name:foot }

/* ==================================================================
   26.3 · REVELADO DEL TITULAR
   ------------------------------------------------------------------
   Dos mecanismos distintos, y no es redundancia: uno es para lo que
   está en la primera pantalla y el otro para lo que hay que ir a
   buscar.

   a) PORTADA — palabra a palabra, al cargar. La primera pantalla es la
      única que nadie desplaza, así que su animación no puede depender
      del scroll. Cada palabra sube desenfocada y se enfoca al aterrizar.
      El desenfoque es lo que lo separa de un fundido de plantilla:
      imita el enfoque de una cámara y el ojo lo lee como profundidad.

   b) INTERIOR — barrido con máscara, al entrar en pantalla. Una franja
      de luz cruza el titular de izquierda a derecha y lo va
      descubriendo. No necesita ni una etiqueta extra en el HTML, así
      que sirve para los cuarenta titulares de sección de una página sin
      engordarla.
   ================================================================== */

/* --- a) palabra a palabra --- */
.w{ display:inline-block }
@media (prefers-reduced-motion:no-preference){
  .h-words .w{ animation:word-in .78s var(--ease-out) both }
  @keyframes word-in{
    from{ opacity:0; transform:translateY(.42em) rotate(1.2deg); filter:blur(7px) }
    to  { opacity:1; transform:none;                             filter:blur(0) }
  }
  /* Escalonado por CLASE NUMERADA y no por `nth-child`, y esto no es manía:
     `nth-child` cuenta entre HERMANOS, así que en cuanto una parte del
     titular va dentro de otra etiqueta —el trozo con degradado de la
     portada, un `<em>`— la cuenta se reinicia dentro y el orden se
     rompe. Con la clase puesta por el generador el número es global y da
     igual cómo esté anidado el titular.

     El paso es de 42 ms: por debajo de 30 no se percibe el orden y por
     encima de 60 la frase tarda en poder leerse. Catorce palabras cubren
     cualquier titular de este sitio; de ahí en adelante todas entran con
     el último retardo, que a esa altura ya no se distingue. */
  .h-words .w-1 { animation-delay:.050s } .h-words .w-2 { animation-delay:.092s }
  .h-words .w-3 { animation-delay:.134s } .h-words .w-4 { animation-delay:.176s }
  .h-words .w-5 { animation-delay:.218s } .h-words .w-6 { animation-delay:.260s }
  .h-words .w-7 { animation-delay:.302s } .h-words .w-8 { animation-delay:.344s }
  .h-words .w-9 { animation-delay:.386s } .h-words .w-10{ animation-delay:.428s }
  .h-words .w-11{ animation-delay:.470s } .h-words .w-12{ animation-delay:.512s }
  .h-words .w-13{ animation-delay:.554s } .h-words .w-n { animation-delay:.596s }

  /* --- c) barrido por TIEMPO, para la portada ---
     Mismo efecto que `.h-sweep` pero sin depender del scroll, porque la
     primera pantalla es la única que nadie desplaza. Existe porque el
     revelado palabra a palabra necesita partir el titular en etiquetas, y
     eso NO se puede hacer cuando el titular ya lleva un trozo con
     degradado: `background-clip:text` recorta el fondo del elemento a SU
     texto, y si los hijos se mueven por separado el recorte deja de
     seguirlos y el degradado se parte.

     Regla, entonces: titular de portada sin marcado dentro → `.h-words`;
     con marcado → `.h-wipe`. `web/components.mjs` lo decide solo. */
  .h-wipe{
    --sweep:130%;
    -webkit-mask-image:linear-gradient(96deg, #000 var(--sweep), transparent calc(var(--sweep) + 20%));
    mask-image:linear-gradient(96deg, #000 var(--sweep), transparent calc(var(--sweep) + 20%));
    padding-bottom:.08em;
    animation:h-wipe 1.15s var(--ease-out) .08s both;
  }
  @keyframes h-wipe{ from{ --sweep:-20% } to{ --sweep:130% } }
  :where(.hero > .wrap, .hero-copy) > h1.h-wipe{ animation:h-wipe 1.15s var(--ease-out) .08s both }
  /* La portada ya escalonaba a sus hijos directos con `enter`. Si además
     el titular hace lo suyo, entra dos veces y se ve el doble salto. Con
     el titular partido en palabras manda el titular.

     Escrito SIN `:where()` a propósito: la regla que hay que ganar es
     `.hero > .wrap > *`, que pesa (0,2,0). `:where()` vale cero, así que
     `:where(…) > h1.h-words` se queda en (0,1,1) y perdía — el titular
     seguía entrando dos veces y no había forma de ver por qué. */
  .hero > .wrap > h1.h-words,
  .hero-copy > h1.h-words{ animation:none }
}

/* --- b) barrido con máscara --- */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .h-sweep{
      /* El valor en reposo descubre el titular entero. Solo mientras la
         animación está en su tramo vale otra cosa. */
      --sweep:130%;
      -webkit-mask-image:linear-gradient(96deg, #000 var(--sweep), transparent calc(var(--sweep) + 18%));
      mask-image:linear-gradient(96deg, #000 var(--sweep), transparent calc(var(--sweep) + 18%));
      /* La máscara recorta la caja exacta del texto y se come las
         descendentes de la «g» y la «p». */
      padding-bottom:.08em;
      animation:h-sweep linear both;
      animation-timeline:view();
      animation-range:entry 12% cover 32%;
    }
    @keyframes h-sweep{ from{ --sweep:-18% } to{ --sweep:130% } }
  }
}

/* ==================================================================
   26.4 · CORTINA DE IMAGEN
   ------------------------------------------------------------------
   La foto no aparece: se descubre. Un recorte que se abre de abajo
   arriba mientras la imagen, dentro, viene de un 9 % más grande y se
   asienta. Los dos movimientos a la vez son lo que hace que parezca que
   la imagen llega, en vez de que se encienda.
   ================================================================== */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .frame,.reveal-curtain{
      clip-path:inset(0 0 var(--curtain) 0 round var(--radius-xl));
      animation:curtain linear both;
      animation-timeline:view();
      animation-range:entry 0% cover 34%;
    }
    @keyframes curtain{ from{ --curtain:88% } to{ --curtain:0% } }

    .frame img,.reveal-curtain img{
      animation:settle linear both;
      animation-timeline:view();
      animation-range:entry 0% cover 46%;
    }
    @keyframes settle{ from{ transform:scale(1.09) } to{ transform:scale(1) } }
    /* El zoom del `:hover` y el del revelado son la misma propiedad. Una
       vez revelada manda el hover: se le quita la animación y la
       transición recupera el control. */
    .frame:hover img{ animation:none; transform:scale(1.04) }
  }
}

/* ==================================================================
   26.5 · PROFUNDIDAD Y LUZ EN LAS SUPERFICIES
   ------------------------------------------------------------------
   Lo que separa una tarjeta de un rectángulo con borde no es la sombra:
   es que reaccione a la luz. Dos capas, las dos en pseudoelementos para
   no tocar el HTML:

     · elevación con perspectiva — la tarjeta se inclina un grado hacia
       el observador, no solo sube;
     · reflejo especular — una franja diagonal que la cruza.

   Un grado de inclinación parece poco escrito y es exactamente lo que
   se nota. A tres grados ya parece un naipe.
   ================================================================== */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  /* Selectores explícitos y NO `:where()`: las reglas de `:hover` que ya
     existían arriba (`.card:hover`, `a.plat:hover`…) tienen peso propio, y
     `:where()` vale cero. Envueltas en `:where()` estas líneas se escribían
     y las ganaba la regla de más arriba, así que la inclinación no se veía.
     `.lib-grid.rows .lib-card:hover` se queda fuera a propósito: en la vista
     de filas el desplazamiento es lateral y ahí una inclinación estorba. */
  .card:hover,
  a.plat:hover,
  .tile:hover,
  .bento > *:hover,
  .lib-grid:not(.rows) .lib-card:hover{
    transform:perspective(900px) rotateX(1.1deg) translateY(-5px) scale(1.006);
  }
  /* Reflejo. El pseudoelemento hereda el radio y recorta lo que sobra,
     así que no hace falta `overflow` en la tarjeta.
     Ojo: `.card::before` NO existía antes (la línea de luz vive en
     `::after`), así que esto no pisa nada. */
  :where(.card,.plat,.tile,.bento > *)::before{
    content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
    border-radius:inherit; overflow:hidden;
    background:linear-gradient(
      100deg,
      transparent calc(var(--shine) - 18%),
      color-mix(in srgb, var(--primary) 9%, transparent) var(--shine),
      transparent calc(var(--shine) + 18%));
    opacity:0; transition:opacity var(--dur-2) ease;
  }
  :where(.card,.plat,.tile,.bento > *):hover::before{
    opacity:1; animation:shine .9s var(--ease-out) forwards;
  }
  @keyframes shine{ from{ --shine:-40% } to{ --shine:140% } }
}

/* Botón principal: además del barrido que ya tenía, un halo que respira
   mientras el puntero está encima. Es el detalle que hace que el botón
   parezca encendido y no pintado. */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .btn-primary:hover{ animation:btn-glow 2.4s var(--ease-inout) infinite alternate }
  @keyframes btn-glow{
    from{ box-shadow:0 18px 38px -14px var(--primary) }
    to  { box-shadow:0 22px 52px -14px var(--primary), 0 0 0 6px var(--tint-2) }
  }
}

/* ==================================================================
   26.6 · DEGRADADOS VIVOS
   ------------------------------------------------------------------
   El texto destacado del titular deja de ser una imagen fija: el ángulo
   del degradado gira muy despacio —un ciclo cada 18 segundos— y eso
   basta para que la portada no parezca una captura de pantalla.

   Muy despacio a propósito: es un movimiento que se ve al mirarlo, no
   uno que persiga la vista mientras se lee.
   ================================================================== */
@media (prefers-reduced-motion:no-preference){
  .hero .grad,.grad-live{
    background:linear-gradient(var(--grad-angle), var(--primary-ink), var(--accent), var(--primary-ink));
    background-size:200% 100%;
    -webkit-background-clip:text; background-clip:text; color:transparent;
    animation:grad-drift 18s linear infinite;
  }
  @keyframes grad-drift{
    0%  { --grad-angle:96deg;  background-position:0% 50% }
    50% { --grad-angle:112deg; background-position:100% 50% }
    100%{ --grad-angle:96deg;  background-position:0% 50% }
  }
}

/* ==================================================================
   26.7 · KEN BURNS Y PARALAJE DE TEXTO
   ------------------------------------------------------------------
   La banda a sangre ya tenía paralaje en la imagen. Le faltaban las dos
   cosas que hacen que una banda de Nike aguante diez segundos en
   pantalla:

     · la imagen además se ACERCA mientras cruza (Ken Burns), y
     · el texto se mueve MENOS que la imagen, no igual.

   La diferencia de velocidad entre los dos planos es literalmente lo
   que el ojo lee como profundidad. Con los dos a la misma velocidad la
   banda es una postal.
   ================================================================== */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .band > img,.band > video{
      animation:kenburns linear both;
      animation-timeline:view(); animation-range:cover 0% cover 100%;
      height:122%; top:-11%;
    }
    @keyframes kenburns{
      from{ transform:translateY(-4.5%) scale(1.12) }
      to  { transform:translateY(4.5%)  scale(1.02) }
    }
    /* El texto, a un tercio del recorrido y en sentido contrario. */
    .band .wrap{
      animation:band-text linear both;
      animation-timeline:view(); animation-range:cover 0% cover 100%;
    }
    /* La opacidad no baja de .78 en los extremos. Con .55 el texto quedaba
       medio apagado cuando la banda es la ÚLTIMA sección de la página: ahí ya
       no queda scroll, la animación nunca llega a su tramo central y el
       titular se quedaba tenue para siempre. */
    @keyframes band-text{
      from{ transform:translateY(26px);  opacity:.78 }
      35% { opacity:1 }
      to  { transform:translateY(-26px); opacity:.78 }
    }
  }
}

/* ==================================================================
   26.8 · BANDA DE VÍDEO
   ------------------------------------------------------------------
   La misma banda, con vídeo en lugar de foto. La CSP ya lo permite
   (`media-src 'self'`): el archivo se sirve desde el propio dominio,
   así que no hay ni una petición a un tercero — que es la razón por la
   que aquí no se incrusta un YouTube.

   El vídeo va SIEMPRE mudo, en bucle, `playsinline` y con cartel. El
   cartel importa más de lo que parece: es lo que se ve mientras el
   vídeo llega y lo único que se ve si el sistema tiene el ahorro de
   batería activo, que en un móvil es la mitad de las visitas.
   ================================================================== */
.band > video{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:-2;
  /* Es decorado, no contenido. `pointer-events:none` evita que un toque
     en el móvil lo pause y deje la banda congelada a media escena. */
  pointer-events:none;
}
/* Con `prefers-reduced-motion` el vídeo se sustituye por su cartel. Un
   `<video autoplay>` no se puede parar desde CSS, así que se esconde y
   queda la imagen fija que ya viaja con él como fondo de la banda. */
@media (prefers-reduced-motion:reduce){
  .band > video{ display:none }
}

/* ==================================================================
   26.9 · ESCENAS FIJADAS
   ------------------------------------------------------------------
   La sección se queda quieta en pantalla mientras el scroll avanza por
   dentro de ella. Es el recurso con el que Apple cuenta un producto: en
   lugar de tres bloques que pasan, una escena que se transforma.

   El alto de la sección decide cuánto dura la parada, y como no puede
   ir en un `style=` en línea, va en clases contadas.
   ================================================================== */
.scene{ position:relative }
.scene-2{ height:200vh } .scene-3{ height:280vh } .scene-4{ height:360vh }
.scene-stage{
  position:sticky; top:var(--head-h);
  height:calc(100vh - var(--head-h));
  display:grid; place-items:center; overflow:hidden;
}
@supports (animation-timeline:view()){
  @media (min-width:901px) and (prefers-reduced-motion:no-preference){
    .scene{ view-timeline-name:--scene; view-timeline-axis:block }
    .scene-zoom{
      animation:scene-zoom linear both;
      animation-timeline:--scene; animation-range:entry 100% exit 0%;
    }
    @keyframes scene-zoom{
      from{ transform:scale(.86);  opacity:.35; filter:blur(3px) }
      22% { transform:scale(1);    opacity:1;   filter:blur(0) }
      78% { transform:scale(1);    opacity:1;   filter:blur(0) }
      to  { transform:scale(1.06); opacity:.2;  filter:blur(3px) }
    }
  }
}
@media (max-width:900px){
  /* En un teléfono una escena fijada roba la pantalla entera durante
     tres deslizamientos y quien lee no sabe si la página se ha colgado.
     Se deshace y vuelve a ser una sección normal. */
  .scene,.scene-2,.scene-3,.scene-4{ height:auto }
  .scene-stage{ position:static; height:auto; padding-block:var(--s8) }
}

/* ==================================================================
   26.10 · ESCAPARATE HORIZONTAL
   ------------------------------------------------------------------
   Mientras la página baja, la fila avanza de lado. Sirve para enseñar
   ocho piezas —capturas, módulos del atlas, ejercicios— sin gastar ocho
   pantallas de alto ni pedir que alguien arrastre a mano una barra
   horizontal, cosa que con un ratón sin rueda lateral no hace nadie.

   El recorrido depende de cuántas láminas hay, y otra vez: no puede ir
   en línea, así que van clases.
   ================================================================== */
.showcase{ position:relative }
.showcase-3{ height:230vh } .showcase-4{ height:300vh }
.showcase-5{ height:370vh } .showcase-6{ height:440vh }
.showcase-stage{
  position:sticky; top:var(--head-h);
  height:calc(100vh - var(--head-h));
  display:flex; align-items:center; overflow:hidden;
}
.showcase-track{ display:flex; gap:clamp(18px,2.4vw,34px); padding-inline:var(--gut) }
.showcase-track > *{ flex:0 0 auto; width:min(430px,74vw) }

@supports (animation-timeline:view()){
  @media (min-width:901px) and (prefers-reduced-motion:no-preference){
    .showcase{ view-timeline-name:--showcase; view-timeline-axis:block }
    .showcase-track{
      animation:showcase linear both;
      animation-timeline:--showcase; animation-range:entry 100% exit 0%;
    }
    /* Se desplaza su propio ancho menos una ventana: así la última
       lámina queda encuadrada al final y no se pasa de largo. */
    @keyframes showcase{ to{ transform:translateX(calc(-100% + 100vw - var(--gut) * 2)) } }
  }
}
/* Sin soporte o en móvil: carril con arrastre y anclaje, que es lo que
   ya sabe hacer `.rail`. */
@media (max-width:900px){
  .showcase,.showcase-3,.showcase-4,.showcase-5,.showcase-6{ height:auto }
  .showcase-stage{ position:static; height:auto; overflow-x:auto; scroll-snap-type:x mandatory; scrollbar-width:none }
  .showcase-stage::-webkit-scrollbar{ display:none }
  .showcase-track > *{ scroll-snap-align:center }
}
@supports not (animation-timeline:view()){
  .showcase,.showcase-3,.showcase-4,.showcase-5,.showcase-6{ height:auto }
  .showcase-stage{ position:static; height:auto; overflow-x:auto; scroll-snap-type:x mandatory }
  .showcase-track > *{ scroll-snap-align:center }
}

/* ==================================================================
   26.11 · CIFRAS QUE SUBEN
   ------------------------------------------------------------------
   No es un contador: es la cifra entera saliendo de debajo de una
   línea. Un contador de verdad necesitaría JavaScript —y aquí no lo
   hay— o un `counter()` animado, que imprimiría «2434» sin el punto de
   los millares, y eso en español está mal escrito.

   Este efecto da lo mismo que se buscaba —la sensación de que la cifra
   se está calculando— sin mentir sobre el número ni romper la
   ortografía.
   ================================================================== */
/* La cifra no se recorta con `overflow` en su propia caja: el recorte se
   aplica al elemento y luego el `transform` mueve las dos cosas juntas, así
   que no esconde nada. Quien tendría que recortar es el `<li>`, pero el
   número es su PRIMER hijo y bajarlo lo mete encima de la etiqueta, no fuera
   de la caja. Lo que oculta el recorrido es la opacidad, y por eso el
   desplazamiento se queda en media línea: subir una línea entera con el
   número ya visible se ve como un salto, no como un revelado. */
.numbers b,.hero-stats b{ padding-bottom:.06em }
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .numbers li b,.hero-stats li b{
      animation:digits linear both;
      animation-timeline:view(); animation-range:entry 10% cover 34%;
    }
    @keyframes digits{
      from{ transform:translateY(.42em) skewY(2.5deg); opacity:0 }
      to  { transform:none;                            opacity:1 }
    }
    .numbers li:nth-child(2) b{ animation-range:entry 10% cover 40% }
    .numbers li:nth-child(3) b{ animation-range:entry 10% cover 46% }
    .numbers li:nth-child(4) b{ animation-range:entry 10% cover 52% }
  }
}

/* ==================================================================
   26.12 · MARQUESINA DOBLE
   ------------------------------------------------------------------
   Dos carriles a distinta velocidad y en sentido contrario. Con uno
   solo la tira es un adorno; con dos cruzándose, la sección tiene
   textura y aguanta ocupar 200 px de alto.
   ================================================================== */
.marquee-slow .marquee-track{ animation-duration:64s }
.marquee-fast .marquee-track{ animation-duration:28s }
@media (prefers-reduced-motion:no-preference){
  .marquee-rev .marquee-track{ animation-direction:reverse }
}
/* Marquesina de imágenes: la misma mecánica con fotos en vez de texto.
   Sirve para el muro de capturas y para el mosaico del atlas. */
.marquee-img .marquee-item{ padding:0 8px }
/* Dos carriles cruzándose necesitan aire entre ellos o se leen como una rejilla
   de dos filas —que es justo lo contrario del efecto— hasta que arrancan. */
.marquee + .marquee{ margin-top:14px }
.marquee-img img{
  width:clamp(150px,17vw,250px); height:clamp(100px,11.5vw,168px);
  object-fit:cover; border-radius:var(--radius-sm);
  border:1px solid var(--border); box-shadow:var(--shadow-sm);
  transition:transform var(--dur-3) var(--ease-out), box-shadow var(--dur-3) ease;
}
.marquee-img .marquee-item::after{ display:none }
@media (hover:hover){
  .marquee-img img:hover{ transform:scale(1.05); box-shadow:var(--shadow) }
}

/* ==================================================================
   26.13 · MOSAICO EDITORIAL
   ------------------------------------------------------------------
   Cuatro fotos de proporciones distintas encajadas. Es lo que hace
   Gymshark en su portada y lo que evita la fila de tres rectángulos
   iguales, que es la maquetación que grita «plantilla».

   Cada pieza entra con su propio retardo, así que el bloque se compone
   a la vista en vez de aparecer de golpe.
   ================================================================== */
.mosaic{
  display:grid; grid-template-columns:repeat(12,minmax(0,1fr));
  grid-auto-rows:clamp(74px,8.2vw,120px); gap:clamp(10px,1.3vw,18px);
}
.mosaic > *{ margin:0; overflow:hidden; border-radius:var(--radius); position:relative }
.mosaic img{ width:100%; height:100%; object-fit:cover; display:block }
.mosaic .m-a{ grid-column:span 7; grid-row:span 3 }
.mosaic .m-b{ grid-column:span 5; grid-row:span 2 }
.mosaic .m-c{ grid-column:span 5; grid-row:span 2 }
.mosaic .m-d{ grid-column:span 7; grid-row:span 2 }
@media (max-width:760px){
  .mosaic{ grid-template-columns:repeat(6,minmax(0,1fr)) }
  .mosaic .m-a{ grid-column:span 6; grid-row:span 3 }
  .mosaic .m-b,.mosaic .m-c{ grid-column:span 3; grid-row:span 2 }
  .mosaic .m-d{ grid-column:span 6; grid-row:span 2 }
}
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .mosaic > *{ animation:mosaic-in linear both; animation-timeline:view(); animation-range:entry 0% cover 32% }
    .mosaic .m-b{ animation-range:entry 0% cover 38% }
    .mosaic .m-c{ animation-range:entry 0% cover 44% }
    .mosaic .m-d{ animation-range:entry 0% cover 50% }
    @keyframes mosaic-in{ from{ opacity:0; transform:translateY(30px) scale(.965) } to{ opacity:1; transform:none } }
    .mosaic img{ animation:settle linear both; animation-timeline:view(); animation-range:entry 0% cover 60% }
  }
}

/* ==================================================================
   26.14 · DESENFOQUE PROGRESIVO BAJO LA CABECERA
   ------------------------------------------------------------------
   El cristal de la cabecera corta en seco: por encima hay desenfoque y
   por debajo no, y esa línea recta se ve. Una segunda capa que se
   desvanece hacia abajo con una máscara reparte el corte en 38 px y
   deja de notarse.

   Solo de 941 px para arriba: por debajo la cabecera renuncia al
   cristal a propósito (ver el bloque de la sección 5), y una capa a
   pantalla completa desenfocando es justo lo que peor lleva un móvil.
   ================================================================== */
@media (min-width:941px){
  .site-head::after{
    content:""; position:absolute; left:0; right:0; top:100%; height:38px;
    pointer-events:none; z-index:-1;
    backdrop-filter:blur(7px); -webkit-backdrop-filter:blur(7px);
    -webkit-mask-image:linear-gradient(#000, transparent);
    mask-image:linear-gradient(#000, transparent);
  }
}

/* ==================================================================
   26.15 · MICROINTERACCIÓN
   ================================================================== */

/* Enlaces de navegación: el subrayado ya no aparece solo en el activo,
   también crece bajo el que se señala. */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .site-nav a::after{
    content:""; position:absolute; left:13px; right:13px; bottom:3px; height:2px;
    border-radius:2px; background:var(--primary);
    transform:scaleX(0); transform-origin:50% 50%;
    transition:transform var(--dur-2) var(--ease-out);
  }
  .site-nav a:hover::after{ transform:scaleX(1) }
  .site-nav a[aria-current="page"]::after{ transform:scaleX(1) }
}

/* Las preguntas frecuentes se despliegan con altura animada de verdad.
   `interpolate-size` es lo que permite interpolar hasta `auto`; sin él
   el navegador salta, y no hay forma de saber la altura sin JavaScript. */
@supports (interpolate-size:allow-keywords){
  :root{ interpolate-size:allow-keywords }
  @media (prefers-reduced-motion:no-preference){
    .faq details::details-content{
      block-size:0; overflow:clip;
      transition:block-size var(--dur-3) var(--ease-out), content-visibility var(--dur-3) allow-discrete;
    }
    .faq details[open]::details-content{ block-size:auto }
  }
}

/* Foco visible con anillo animado: quien navega con teclado merece la
   misma calidad de interacción que quien usa el ratón. */
@media (prefers-reduced-motion:no-preference){
  :focus-visible{ transition:outline-offset var(--dur-1) var(--ease-out) }
  a:focus-visible,button:focus-visible,summary:focus-visible{ outline-offset:4px }
}

/* ==================================================================
   26.16 · CINTURÓN DE SEGURIDAD DEL MOVIMIENTO
   ------------------------------------------------------------------
   El bloque de `prefers-reduced-motion:reduce` de la sección 24 recorta
   las duraciones a 1 ms, y eso basta para las animaciones de tiempo.
   NO basta para las ligadas al scroll: en una animación con
   `animation-timeline` la duración se ignora —no hay tiempo, hay
   recorrido—, así que una regla de duración no la para.

   De ahí que cada bloque de arriba lleve su propio
   `prefers-reduced-motion:no-preference`. Esto es el cinturón por si
   alguna se escapa: se apaga la línea de tiempo y la animación deja de
   existir, dejando el elemento en su estado normal.
   ================================================================== */
@media (prefers-reduced-motion:reduce){
  *{ animation-timeline:auto!important; view-timeline-name:none!important }
  .h-sweep{ -webkit-mask-image:none!important; mask-image:none!important }
  .frame,.reveal-curtain{ clip-path:none!important }
  .scene-stage,.showcase-stage{ position:static!important; height:auto!important }
  .scene,.showcase{ height:auto!important }
}

/* Fila de redes del pie. Solo aparece si la marca declara `site.social`
   (ver web/site.config.mjs); vacía no pinta nada. */
.foot-social{display:flex; gap:6px; list-style:none; margin:clamp(30px,3.8vw,44px) 0 0; padding:0}
.foot-social a{
  display:grid; place-items:center; width:40px; height:40px; border-radius:12px;
  color:var(--muted); border:1px solid var(--border); background:var(--surface);
  transition:color var(--dur-2) ease, border-color var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
}
.foot-social a:hover{color:var(--primary-ink); border-color:var(--edge); transform:translateY(-2px)}
.foot-social .ic{width:19px; height:19px}


/* ==================================================================
   27 · REDISEÑO DEL ECOSISTEMA 2026
   ------------------------------------------------------------------
   Portadas inspiradas en los modelos aprobados: mensaje de producto a
   la izquierda, producto real a la derecha y una banda de capacidades
   que permite entender el sistema antes del primer scroll largo.
   ================================================================== */
.hero-kicker{
  display:inline-flex; align-items:center; gap:9px; width:max-content;
  margin:0 0 var(--s4); padding:8px 12px; border:1px solid color-mix(in srgb,var(--primary) 40%,var(--border));
  border-radius:999px; color:var(--primary-ink); background:color-mix(in srgb,var(--primary) 8%,var(--surface));
  font-family:var(--display); font-size:.76rem; font-weight:700; line-height:1;
  letter-spacing:var(--track-display); text-transform:var(--case-display);
}
.hero-kicker::before{content:""; width:7px; height:7px; border-radius:50%; background:var(--primary); box-shadow:0 0 16px var(--primary)}
.hero-split .hero-kicker{margin-inline:0}

.device-stage{
  position:relative; width:min(100%,620px); min-height:560px; display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr)); align-items:center; isolation:isolate;
  padding:24px 0 38px;
}
.device-stage::before{
  content:""; position:absolute; inset:5% -8% 0; z-index:-2; border-radius:50%;
  background:radial-gradient(circle at 52% 48%,color-mix(in srgb,var(--primary) 24%,transparent),transparent 58%);
  filter:blur(12px); opacity:.9;
}
.device-stage::after{
  content:""; position:absolute; left:2%; right:2%; bottom:2%; height:22%; z-index:-1;
  background:radial-gradient(ellipse,color-mix(in srgb,var(--primary) 22%,transparent),transparent 68%);
  filter:blur(18px); transform:perspective(420px) rotateX(66deg);
}
.device-frame{margin:0; position:relative; width:100%; z-index:1; transform:translateX(18%) rotate(-3deg) scale(.86); transform-origin:center bottom}
.device-frame:nth-child(2){z-index:3; transform:translateY(-10px) scale(1.07)}
.device-frame.is-primary{z-index:3}
.device-frame:nth-child(3){z-index:2; transform:translateX(-18%) rotate(3deg) scale(.86)}
.device-frame .phone{width:100%; border-width:5px; border-radius:28px; box-shadow:0 28px 72px rgba(0,0,0,.28)}
.device-frame .phone img{border-radius:22px}
.device-frame figcaption{
  position:absolute; left:50%; bottom:-31px; transform:translateX(-50%); width:max-content; max-width:150%;
  padding:7px 11px; border:1px solid var(--border); border-radius:999px; background:color-mix(in srgb,var(--surface) 88%,transparent);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px); color:var(--text); font-size:.72rem; font-weight:650;
  box-shadow:var(--shadow-sm);
}
@media (hover:hover){
  .device-frame{transition:transform var(--dur-3) var(--ease-out),filter var(--dur-3) ease}
  .device-stage:hover .device-frame:not(:hover){filter:saturate(.72) brightness(.88)}
  .device-frame:first-child:hover{transform:translateX(12%) rotate(-1deg) scale(.91)}
  .device-frame:nth-child(2):hover{transform:translateY(-18px) scale(1.1)}
  .device-frame:nth-child(3):hover{transform:translateX(-12%) rotate(1deg) scale(.91)}
}

.feature-strip{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); list-style:none;
  margin:0; padding:0; overflow:hidden; border:1px solid var(--border); border-radius:var(--radius-xl);
  background:linear-gradient(135deg,color-mix(in srgb,var(--surface) 96%,var(--primary)),var(--surface));
  box-shadow:var(--shadow);
}
.feature-strip li{display:flex; align-items:flex-start; gap:12px; min-height:108px; padding:22px 20px; border-left:1px solid var(--border)}
.feature-strip li:first-child{border-left:0}
.feature-strip-icon{
  flex:0 0 38px; height:38px; display:grid; place-items:center; border-radius:12px;
  color:var(--primary-ink); background:color-mix(in srgb,var(--primary) 12%,var(--surface));
}
.feature-strip-icon .ic{width:20px;height:20px}
.feature-strip b{display:block; color:var(--ink); font-size:.9rem; line-height:1.25}
.feature-strip small{display:block; margin-top:5px; color:var(--muted); font-size:.76rem; line-height:1.45}

.ecosystem-stage{
  position:relative; width:min(100%,610px); aspect-ratio:1/1; display:grid; place-items:center; isolation:isolate;
}
.ecosystem-orbit{position:absolute; inset:10%; border:1px solid color-mix(in srgb,var(--primary) 28%,var(--border)); border-radius:50%; box-shadow:inset 0 0 90px color-mix(in srgb,var(--primary) 8%,transparent)}
.ecosystem-orbit::before,.ecosystem-orbit::after{content:"";position:absolute;border:1px solid color-mix(in srgb,var(--primary) 20%,transparent);border-radius:50%}
.ecosystem-orbit::before{inset:13%;transform:rotate(32deg)}
.ecosystem-orbit::after{inset:28%;transform:rotate(-20deg)}
.ecosystem-core{
  width:42%; aspect-ratio:1; display:grid; place-items:center; border-radius:30%;
  color:var(--ink); background:linear-gradient(145deg,var(--surface),var(--surface-2));
  border:1px solid var(--edge); box-shadow:0 34px 90px color-mix(in srgb,var(--primary) 17%,transparent),inset 0 1px #fff4;
  transform:rotate(45deg);
}
.ecosystem-core .hero-mark{display:block; width:62%; height:62%; margin:0; transform:rotate(-45deg)}
.ecosystem-chip{
  position:absolute; display:flex; align-items:center; gap:9px; max-width:190px; padding:11px 13px;
  color:var(--text); background:color-mix(in srgb,var(--surface) 86%,transparent); border:1px solid var(--border);
  border-radius:15px; backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); box-shadow:var(--shadow);
  font-size:.75rem; line-height:1.35;
}
.ecosystem-chip .ic{flex:0 0 21px;width:21px;height:21px;color:var(--primary-ink)}
.ecosystem-chip b{display:block;color:var(--ink);font-size:.8rem}
.ecosystem-chip:nth-of-type(1){top:12%;right:0}.ecosystem-chip:nth-of-type(2){left:0;top:44%}.ecosystem-chip:nth-of-type(3){right:2%;bottom:10%}

@media (max-width:900px){
  .hero-split .hero-kicker{margin-inline:auto}
  .device-stage{min-height:0; width:min(94vw,610px); margin-inline:auto}
  .ecosystem-stage{width:min(90vw,560px);margin-inline:auto}
}
@media (max-width:620px){
  .device-stage{display:flex; overflow-x:auto; scroll-snap-type:x mandatory; gap:14px; padding:14px var(--gut) 42px; scrollbar-width:none}
  .device-stage::-webkit-scrollbar{display:none}
  .device-frame,.device-frame:nth-child(2),.device-frame:nth-child(3){flex:0 0 62vw;max-width:245px;transform:none;scroll-snap-align:center}
  .device-frame:first-child{margin-left:auto}.device-frame:last-child{margin-right:auto}
  .feature-strip{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;border-radius:var(--radius);scrollbar-width:none}
  .feature-strip::-webkit-scrollbar{display:none}
  .feature-strip li{flex:0 0 78vw;min-height:96px;border-left:1px solid var(--border);scroll-snap-align:start}
  .feature-strip li:first-child{border-left:0}
  .ecosystem-chip{position:static;max-width:none;width:100%}
  .ecosystem-stage{aspect-ratio:auto;display:grid;grid-template-columns:1fr;gap:10px;padding-top:260px}
  .ecosystem-orbit{inset:0 8% auto;height:240px}.ecosystem-core{position:absolute;top:55px;width:145px}
}
@media (prefers-reduced-motion:no-preference){
  .ecosystem-orbit{animation:orbit-drift 18s ease-in-out infinite alternate}
  @keyframes orbit-drift{to{transform:rotate(7deg) scale(1.025)}}
}

/* ====================================================================
   Portada Epistemis 2026 — blanca, azul y centrada en el producto
   ==================================================================== */
.model-home.med-model-home{background:#fff;color:#0b1b3b;color-scheme:light;font-family:Inter,system-ui,sans-serif}
.med-model-home .site-head{background:rgba(255,255,255,.92);border-color:#dce6f6;backdrop-filter:blur(20px);box-shadow:none}.med-model-home .head-inner{width:min(1450px,calc(100% - 80px));min-height:72px}.med-model-home .brand,.med-model-home .site-nav a{color:#0c1e42}.med-model-home .site-nav a{font-size:.83rem;font-weight:600}.med-model-home .site-nav a[aria-current="page"]{color:#1266e8}.med-model-home .nav-lang,.med-model-home .nav-login{border-color:#cad9ef;background:#fff;color:#105bc4}.med-model-home .nav-cta{border-color:#1269ec;background:linear-gradient(135deg,#166fec,#0a5eda);color:#fff;box-shadow:0 9px 25px rgba(16,100,224,.2)}
.med-model-home main{overflow:hidden;background:#fff}.med-model-home .med-ref-wrap{width:min(1450px,calc(100% - 80px));margin-inline:auto}
.med-model-home .med-ref-hero{position:relative;min-height:600px;border-bottom:1px solid #e1e9f6;background:linear-gradient(135deg,#fff 20%,#fbfdff 74%,#f3f8ff);overflow:hidden}.med-model-home .med-blue-shape{position:absolute;right:-8%;top:0;width:58%;height:100%;border-radius:46% 0 0 48%;background:linear-gradient(145deg,#9cc9ff 0,#3181ee 46%,#075fd9 100%);clip-path:polygon(20% 0,100% 0,100% 100%,0 100%,8% 60%,0 33%);opacity:.95}.med-model-home .med-blue-shape::before,.med-model-home .med-blue-shape::after{content:"";position:absolute;border-radius:50%;border:1px solid rgba(255,255,255,.28)}.med-model-home .med-blue-shape::before{inset:10% -18% 7% 10%}.med-model-home .med-blue-shape::after{inset:28% -5% 21% -5%}
.med-model-home .med-hero-grid{position:relative;z-index:2;display:grid;grid-template-columns:1.04fr 1.21fr;gap:20px;align-items:center;min-height:600px;padding:46px 0 28px}.med-model-home .med-hero-copy{position:relative;z-index:4;max-width:690px}.med-model-home .med-eyebrow{display:inline-flex;align-items:center;margin:0 0 20px;padding:9px 15px;border-radius:999px;background:#f1f6ff;color:#075bd2;font-size:.7rem;font-weight:750;letter-spacing:.035em}.med-model-home .med-hero-copy h1{margin:0;color:#0a214e;font-family:Inter,system-ui,sans-serif;font-size:clamp(2.85rem,4vw,4.75rem);font-weight:760;line-height:1.03;letter-spacing:-.055em}.med-model-home .med-hero-copy h1 span{display:block;color:#186be3}.med-model-home .med-lede{max-width:650px;margin:26px 0 0;color:#617397;font-size:1.02rem;line-height:1.67}.med-model-home .med-actions{display:flex;gap:15px;margin-top:30px}.med-model-home .med-btn{display:inline-flex;align-items:center;justify-content:center;min-height:52px;padding:0 25px;border:1px solid #bfd0ed;border-radius:9px;color:#0a58c4;text-decoration:none;font-weight:700;font-size:.86rem;transition:.2s ease}.med-model-home .med-btn:hover{transform:translateY(-2px);box-shadow:0 12px 30px rgba(15,104,229,.14)}.med-model-home .med-btn-primary{border-color:#1169ed;background:linear-gradient(135deg,#1772ef,#085cd8);color:#fff}.med-model-home .med-btn-outline{background:#fff}
.med-model-home h2,.med-model-home h3,.med-model-home h4{font-family:Inter,system-ui,sans-serif}
.med-model-home .med-metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:34px}.med-model-home .med-metrics>div{display:grid;grid-template-columns:31px 1fr;align-items:center;column-gap:8px}.med-model-home .med-metrics .ic{grid-row:1/3;width:26px;height:26px;color:#0863df}.med-model-home .med-metrics strong{font-size:.76rem;color:#0e4fae}.med-model-home .med-metrics span{font-size:.64rem;color:#7c8ca9}
.med-model-home .med-product-stage{position:relative;min-height:525px}.med-model-home .med-desktop{position:absolute;left:0;top:16px;width:88%;height:480px;border:7px solid #18202b;border-radius:25px;background:#fff;box-shadow:0 28px 65px rgba(7,44,102,.25);overflow:hidden;transform:perspective(1200px) rotateY(-1deg)}.med-model-home .med-desktop-bar{height:48px;display:grid;grid-template-columns:150px 1fr 28px;align-items:center;gap:14px;padding:0 16px;border-bottom:1px solid #e0e8f5;color:#175cca;font-size:.71rem}.med-model-home .med-desktop-bar span{padding:8px 14px;border:1px solid #e2e9f5;border-radius:8px;color:#91a0b7;font-size:.58rem}.med-model-home .med-desktop-body{display:grid;grid-template-columns:140px 1fr;height:calc(100% - 48px)}.med-model-home .med-desktop aside{display:flex;flex-direction:column;gap:6px;padding:18px 12px;border-right:1px solid #e4eaf3;background:#fbfdff}.med-model-home .med-desktop aside span,.med-model-home .med-desktop aside b{padding:9px 12px;border-radius:7px;font-size:.64rem;font-weight:500}.med-model-home .med-desktop aside b{background:#1169e8;color:#fff}.med-model-home .med-dashboard{padding:22px 22px 15px;color:#112243}.med-model-home .med-dashboard h3{margin:0 0 3px;font-size:1.15rem}.med-model-home .med-dashboard>p{margin:0 0 15px;color:#7b8ca8;font-size:.67rem}.med-model-home .med-quick{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.med-model-home .med-quick article{display:flex;flex-direction:column;gap:4px;padding:13px 10px;border:1px solid #e4ebf7;border-radius:10px;background:#fff;box-shadow:0 7px 18px rgba(28,78,150,.06)}.med-model-home .med-quick .ic{width:19px;height:19px;color:#1268e5}.med-model-home .med-quick b{font-size:.62rem}.med-model-home .med-quick small{color:#91a0b8;font-size:.52rem}.med-model-home .med-dashboard h4{margin:18px 0 9px;font-size:.72rem}.med-model-home .med-courses{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}.med-model-home .med-courses span{position:relative;padding:12px 8px 22px;border:1px solid #e7edf7;border-radius:8px;font-size:.57rem}.med-model-home .med-courses span::after{content:"";position:absolute;left:8px;right:8px;bottom:9px;height:3px;border-radius:2px;background:linear-gradient(90deg,#116ee8 68%,#dbe5f5 68%)}.med-model-home .med-courses i{float:right;color:#7690b5;font-style:normal}.med-model-home .med-dashboard ul{display:grid;gap:7px;margin:0;padding:0;list-style:none}.med-model-home .med-dashboard li{padding:8px 11px;border:1px solid #e5ebf5;border-radius:7px;font-size:.58rem}.med-model-home .med-dashboard li b{float:right;color:#0964da}
.med-model-home .med-phone{position:absolute;right:-1%;bottom:-25px;width:210px;height:445px;margin:0;padding:7px;border:3px solid #1b2734;border-radius:38px;background:#10151c;box-shadow:0 26px 55px rgba(5,32,74,.34);overflow:hidden;z-index:5}.med-model-home .med-phone img{width:100%;height:100%;object-fit:cover;object-position:top;border-radius:29px}.med-model-home .med-phone-notch{position:absolute;top:13px;left:50%;z-index:2;width:77px;height:18px;border-radius:999px;background:#05080b;transform:translateX(-50%)}
.med-model-home .med-modules{position:relative;z-index:4;padding:0 0 24px;background:#fff}.med-model-home .med-modules-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:14px}.med-model-home .med-module-card{display:flex;gap:13px;min-height:130px;padding:20px 17px;border:1px solid #dbe5f3;border-radius:13px;background:#fff;color:#0c2450;text-decoration:none;box-shadow:0 8px 22px rgba(28,80,160,.04);transition:.2s ease}.med-model-home .med-module-card:hover{transform:translateY(-3px);border-color:#79aef2;box-shadow:0 13px 30px rgba(27,91,186,.1)}.med-model-home .med-module-card>.ic{flex:0 0 27px;width:27px;height:27px;color:#0b67e7}.med-model-home .med-module-card h3{margin:1px 0 7px;font-size:.78rem}.med-model-home .med-module-card p{margin:0;color:#647593;font-size:.67rem;line-height:1.45}.med-model-home .med-module-card span{display:block;margin-top:12px;color:#0d63dc;font-size:.62rem;font-weight:700}
.med-model-home .med-lower{padding:0 0 30px;background:#fff}.med-model-home .med-lower-grid{display:grid;grid-template-columns:1.6fr 1fr;gap:18px}.med-model-home .med-device-band,.med-model-home .med-community{position:relative;overflow:hidden;min-height:180px;border-radius:14px}.med-model-home .med-device-band{display:grid;grid-template-columns:.78fr 1.22fr;padding:24px 25px;background:linear-gradient(135deg,#f0f6ff,#fff);border:1px solid #e4ebf6}.med-model-home .med-device-band h2,.med-model-home .med-community h2{margin:0;color:#0b58c8;font-size:1.25rem;line-height:1.05}.med-model-home .med-device-band p{margin:12px 0 18px;color:#6c7f9e;font-size:.69rem;line-height:1.45}.med-model-home .med-platforms{display:flex;flex-wrap:wrap;gap:11px;color:#1c3155;font-size:.6rem}.med-model-home .med-device-shots{position:relative;height:180px}.med-model-home .med-device-shots img{position:absolute;bottom:-85px;width:118px;height:235px;object-fit:cover;object-position:top;border:4px solid #26303b;border-radius:15px;box-shadow:0 16px 30px rgba(17,50,96,.18)}.med-model-home .med-device-shots img:nth-child(1){left:8%;transform:rotate(-4deg)}.med-model-home .med-device-shots img:nth-child(2){left:38%;z-index:2;width:145px;height:270px}.med-model-home .med-device-shots img:nth-child(3){right:0;transform:rotate(3deg)}.med-model-home .med-community{padding:27px 32px;background:linear-gradient(145deg,#0d65df,#078af1 58%,#5bc8f1);color:#fff}.med-model-home .med-community::after{content:"";position:absolute;inset:auto -15% -65% 5%;height:130%;border:1px solid rgba(255,255,255,.25);border-radius:50%;transform:rotate(-8deg)}.med-model-home .med-community h2{color:#fff}.med-model-home .med-community p{max-width:330px;margin:14px 0 21px;font-size:.72rem;line-height:1.5}.med-model-home .med-people{position:relative;z-index:2;display:flex}.med-model-home .med-people span{display:grid;place-items:center;width:38px;height:38px;margin-left:-5px;border:2px solid #fff;border-radius:50%;background:#f1d4c6;color:#14417c;font-size:.57rem;font-weight:800}.med-model-home .med-people span:first-child{margin-left:0}.med-model-home .med-people span:last-child{width:48px;background:#fff;color:#0864dd}
.med-model-home .med-proof{padding:24px 0 33px;border-top:1px solid #e3eaf5;background:#fff;text-align:center}.med-model-home .med-proof p{margin:0;color:#596b8e;font-size:.68rem}.med-model-home .med-proof div>div{display:grid;grid-template-columns:repeat(6,1fr);gap:22px;margin-top:22px;color:#2264bb;font-size:1.05rem;font-weight:800}.med-model-home .site-foot{background:#f7faff;border-color:#e0e8f4;color:#6a7b97}.med-model-home .site-foot a,.med-model-home .site-foot h2{color:#183c75}.med-model-home .foot-word{color:#eef4fc}
@media(max-width:1120px){.med-model-home .med-ref-wrap,.med-model-home .head-inner{width:min(100% - 42px,1000px)}.med-model-home .med-hero-grid{grid-template-columns:1fr}.med-model-home .med-blue-shape{top:42%;width:100%;height:60%}.med-model-home .med-product-stage{min-height:540px}.med-model-home .med-modules-grid{grid-template-columns:repeat(3,1fr)}.med-model-home .med-lower-grid{grid-template-columns:1fr}.med-model-home .med-desktop{left:4%;width:82%}.med-model-home .med-phone{right:5%}}
@media(max-width:720px){.med-model-home .med-ref-wrap,.med-model-home .head-inner{width:min(100% - 28px,650px)}.med-model-home .med-hero-copy h1{font-size:2.85rem}.med-model-home .med-actions{flex-direction:column}.med-model-home .med-metrics{grid-template-columns:1fr 1fr}.med-model-home .med-product-stage{min-height:480px;margin-inline:-90px}.med-model-home .med-desktop{left:6%;top:60px;width:82%;height:365px;transform:scale(.88);transform-origin:left top}.med-model-home .med-phone{right:6%;bottom:-25px;transform:scale(.78);transform-origin:right bottom}.med-model-home .med-modules-grid{display:flex;overflow-x:auto;scroll-snap-type:x mandatory}.med-model-home .med-module-card{flex:0 0 72vw;scroll-snap-align:start}.med-model-home .med-device-band{grid-template-columns:1fr;min-height:390px}.med-model-home .med-device-shots{margin-top:20px}.med-model-home .med-proof div>div{grid-template-columns:repeat(3,1fr)}}
.med-model-home .med-hero-grid{align-items:start}

/* Sistema visual interno Epistemis 2026: blanco clinico y azul medico. */
body:not(.model-home){
  color-scheme:light;--primary:#1269ed;--primary-ink:#075fd6;--accent:#35a8ff;--on-primary:#fff;
  --bg:#f7faff;--surface:#fff;--surface-2:#f0f5fd;--surface-3:#e8f0fc;
  --ink:#0b1f46;--text:#42587c;--muted:#7486a3;--border:#d9e5f5;
  --tint:color-mix(in srgb,var(--primary) 10%,transparent);--tint-2:color-mix(in srgb,var(--primary) 6%,transparent);--tint-3:color-mix(in srgb,var(--primary) 22%,transparent);
  --edge:color-mix(in srgb,var(--primary) 36%,var(--border));--grad:linear-gradient(100deg,#0b2351 4%,#1269ed 64%,#30a9f2 100%);
  --radius-xl:22px;--radius:16px;--radius-sm:11px;
  background:radial-gradient(900px 520px at 88% -7%,rgba(24,111,236,.12),transparent 66%),radial-gradient(700px 480px at -4% 34%,rgba(73,177,255,.07),transparent 70%),#f7faff;color:var(--text)
}
body:not(.model-home)::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.42;background-image:linear-gradient(rgba(32,91,170,.035) 1px,transparent 1px),linear-gradient(90deg,rgba(32,91,170,.035) 1px,transparent 1px);background-size:72px 72px;mask-image:linear-gradient(to bottom,#000,transparent 74%)}
body:not(.model-home) main{overflow:hidden;background:transparent}
body:not(.model-home) .site-head{background:rgba(255,255,255,.91);border-bottom-color:#dbe6f5;box-shadow:0 8px 30px rgba(23,69,132,.045);backdrop-filter:blur(20px) saturate(145%)}
body:not(.model-home) .head-inner{width:min(1390px,calc(100% - 64px));min-height:72px}
body:not(.model-home) .brand{color:#0b1e42;font-size:1.12rem}body:not(.model-home) .brand img{box-shadow:0 8px 22px rgba(18,105,237,.18)}
body:not(.model-home) .site-nav a{color:#344866;font-size:.83rem;font-weight:620}
body:not(.model-home) .site-nav a:hover{color:#075fd6;background:#f0f5fd}
body:not(.model-home) .site-nav a[aria-current="page"]{color:#075fd6;background:#eaf2ff}
body:not(.model-home) .nav-lang{border-color:#cfddf0!important;background:#fff;color:#36629c!important}
body:not(.model-home) .nav-cta{background:linear-gradient(135deg,#1873f0,#0a5edb)!important;color:#fff!important;box-shadow:0 12px 30px rgba(18,105,237,.20)}
body:not(.model-home) .head-progress{background:linear-gradient(90deg,#1269ed,#36b8f3)}
body:not(.model-home) .crumbs{background:#f2f7fe;border-color:#dce7f5}body:not(.model-home) .crumbs a{color:#075fd6}
body:not(.model-home) .hero-page{min-height:520px;padding:clamp(92px,10vw,154px) 0 clamp(66px,7.5vw,108px);text-align:left;display:grid;align-items:center;border-bottom:1px solid #dce7f5;background:linear-gradient(116deg,#fff 0 57%,#f0f6ff 57% 68%,#e8f2ff 68%)}
body:not(.model-home) .hero-page::before{inset:0;background:radial-gradient(620px 420px at 84% 45%,rgba(18,105,237,.22),transparent 68%)}
body:not(.model-home) .hero-page::after{content:"";position:absolute;right:-6%;top:-17%;width:min(50vw,660px);height:132%;border-radius:48% 0 0 50%;background:linear-gradient(145deg,rgba(117,183,255,.30),rgba(18,105,237,.13));clip-path:polygon(25% 0,100% 0,100% 100%,0 100%,10% 63%,0 36%);border-left:1px solid rgba(18,105,237,.12)}
body:not(.model-home) .hero-page>.wrap{position:relative;z-index:2;margin-left:max(24px,calc((100vw - 1180px)/2));margin-right:auto;width:min(820px,calc(100% - 48px))}
body:not(.model-home) .hero-page .eyebrow{display:inline-flex;padding:8px 13px;border-radius:999px;background:#edf4ff;color:#075fd6;font-family:Inter,system-ui,sans-serif;font-size:.72rem;font-weight:750;letter-spacing:.08em}
body:not(.model-home) .hero-page h1{max-width:14ch;margin:0 0 24px;color:#0a214d;font-family:Inter,system-ui,sans-serif;font-size:clamp(3.15rem,6.7vw,6.35rem);font-weight:760;line-height:.95;letter-spacing:-.06em}
body:not(.model-home) .hero-page h1::after{content:"";display:block;width:76px;height:5px;margin-top:27px;border-radius:8px;background:linear-gradient(90deg,#1269ed,#36b8f3)}
body:not(.model-home) .hero-page .lede{max-width:670px;margin:0;color:#52698d;font-size:clamp(1.04rem,1.5vw,1.25rem);line-height:1.7}
body:not(.model-home) .hero-stats{justify-content:flex-start;margin:44px 0 0}
body:not(.model-home) .hero-stats li{border-color:#cfddf0;text-align:left}body:not(.model-home) .hero-stats b{color:#1269ed;font-family:Inter,system-ui,sans-serif}
body:not(.model-home) section{border-color:#dbe6f4}
body:not(.model-home) section.alt{background:linear-gradient(180deg,#f1f6fd,#f7faff)}
body:not(.model-home) section.invert{background:linear-gradient(135deg,#0c2d67,#075dce 60%,#078bdc);--surface:#143a76;--surface-2:#174785;--ink:#fff;--text:#e0ecff;--muted:#bdd2f2;--border:rgba(255,255,255,.17);--primary:#fff;--primary-ink:#fff}
body:not(.model-home) .section-head h2{color:#0a214d;font-family:Inter,system-ui,sans-serif;font-size:clamp(2.3rem,4.3vw,4.55rem);font-weight:750;line-height:1;letter-spacing:-.052em}
body:not(.model-home) .section-head p{color:#657997}body:not(.model-home) .eyebrow,body:not(.model-home) .kicker{color:#075fd6}
body:not(.model-home) :where(.card,.plat,.plan,.tile,.bento>*,.steps li,.stats li,.pcard,.kpi,.lib-card,.box,.callout,.login-card){background:linear-gradient(145deg,#fff,#fafdff);border-color:#d8e4f4;box-shadow:0 17px 48px rgba(29,72,133,.075),inset 0 1px rgba(255,255,255,.9)}
body:not(.model-home) :where(.card,.plat,.plan,.tile,.bento>*,.lib-card):hover{transform:translateY(-5px);border-color:#8fb9f3;box-shadow:0 24px 64px rgba(28,85,168,.13)}
body:not(.model-home) :where(.card,.plat,.plan,.tile,.bento>*,.steps li,.stats li,.pcard,.kpi,.lib-card,.box) :where(h2,h3){color:#102953}
body:not(.model-home) .ic-box{background:#edf4ff;border-color:#d5e5fb;color:#1269ed}
body:not(.model-home) .btn-primary,body:not(.model-home) .plan-cta{background:linear-gradient(135deg,#1873f0,#0a5edb);color:#fff;border-color:#1269ed;box-shadow:0 14px 32px rgba(18,105,237,.18)}
body:not(.model-home) .btn:not(.btn-primary){background:#fff;color:#0b58c6;border-color:#bfd1ec}
body:not(.model-home) .lib-bar{background:rgba(255,255,255,.94);border-color:#d7e3f2;box-shadow:0 16px 42px rgba(27,77,146,.09)}
body:not(.model-home) :where(input,select,textarea,.lib-search,.lib-sel){background:#fff!important;border-color:#cfddef!important;color:#18355f!important}
body:not(.model-home) :where(input,select,textarea):focus{border-color:#1269ed!important;box-shadow:0 0 0 4px rgba(18,105,237,.10)!important}
body:not(.model-home) .lib-card img{filter:saturate(.9);transition:.3s ease}body:not(.model-home) .lib-card:hover img{filter:saturate(1.08)}
body:not(.model-home) .feature-strip,body:not(.model-home) .spec{background:#dbe6f4;border-color:#d6e2f2}body:not(.model-home) .feature-strip li,body:not(.model-home) .spec div{background:#fff;border-color:#d9e5f4}
body:not(.model-home) .table-wrap{border-color:#d7e3f2;background:#fff;box-shadow:0 20px 55px rgba(27,76,143,.08)}body:not(.model-home) table tr{border-color:#dbe5f2}body:not(.model-home) table th{background:#edf4fd;color:#173661}
body:not(.model-home) .faq details{background:#fff;border-color:#d7e3f2}body:not(.model-home) .faq details[open]{border-color:#8db8f3;box-shadow:0 14px 38px rgba(23,83,169,.08)}
body:not(.model-home) :where(.detail,.guide-sec,.body){color:#435a7c}body:not(.model-home) :where(.detail,.guide-sec,.body) :where(h2,h3){color:#0e2854}body:not(.model-home) :where(.detail,.guide-sec,.body) a{color:#075fd6}
body:not(.model-home) .guide-toc,body:not(.model-home) .aside{background:#f1f6fd;border-color:#d8e4f3}
body:not(.model-home) .ctaband{background:linear-gradient(128deg,#0d61d5,#0878e6 58%,#36b9ee);border-color:#1b71dd;color:#fff;box-shadow:0 30px 85px rgba(18,90,190,.22)}body:not(.model-home) .ctaband :where(h2,p){color:#fff}
body:not(.model-home) .site-foot{background:#07162f;border-color:#102c58;color:#9eb1cf}body:not(.model-home) .site-foot::before{content:"";position:absolute;inset:0;background:radial-gradient(760px 260px at 12% 0,rgba(45,135,255,.17),transparent 70%);pointer-events:none}body:not(.model-home) .site-foot .brand,body:not(.model-home) .site-foot a,body:not(.model-home) .site-foot h2{color:#e5efff}body:not(.model-home) .foot-word{color:#0b2042}
@media(max-width:940px){body:not(.model-home) .head-inner{width:min(100% - 30px,720px)}body:not(.model-home) .site-head,body:not(.model-home) .site-nav{background:#fff}body:not(.model-home) .hero-page{min-height:auto;padding:86px 0 70px}body:not(.model-home) .hero-page::after{right:-155px;top:21%;width:420px;height:82%;opacity:.62}body:not(.model-home) .hero-page h1{font-size:clamp(2.7rem,12vw,4.8rem)}body:not(.model-home) .hero-stats{display:grid;grid-template-columns:1fr 1fr;width:100%}body:not(.model-home) .hero-stats li{border-left:0;border-top:1px solid #cfddf0;padding:17px 0}}
@media(max-width:620px){body:not(.model-home) .hero-page>.wrap{width:calc(100% - 32px);margin-inline:16px}body:not(.model-home) section{padding-block:60px}body:not(.model-home) .section-head h2{font-size:2.35rem}}

/* Neutros de la marca — generados desde web/site.config.mjs. No editar a mano. */
:root{--bg:#f5f7fa; --surface:#ffffff; --surface-2:#eaeff7; --surface-3:#dde5f2; --ink:#0a1220; --text:#3c4757; --muted:#606d82; --border:#d7dfec;}
@media (prefers-color-scheme:dark){:root{--bg:#060911; --surface:#0e1520; --surface-2:#141d2c; --surface-3:#1b2739; --ink:#e6ecf6; --text:#a8b4c6; --muted:#7b899e; --border:#222f44;}}

/* Tokens de la marca — generados desde web/site.config.mjs. No editar a mano. */
:root{--case-display:none; --track-display:.06em; --glow:.7; --grain:.035; --h-font:var(--display); --h-track:-.018em; --h-weight:700;}
:root{--invert-bg:#071120; --invert-surface:#0e1b2e; --invert-ink:#ffffff; --invert-text:#a5b4ca; --invert-border:#1c2c44; --invert-primary:#4c8ef8; --invert-primary-ink:#8fbaff;}
@media (prefers-color-scheme:dark){:root{--invert-bg:#f3f6fb; --invert-surface:#ffffff; --invert-ink:#08121f; --invert-text:#465468; --invert-border:#d7dfec; --invert-primary:#1f6feb; --invert-primary-ink:#1557c0;}}
