/* ============================================================================
   Proce.SOS · landing comercial
   ----------------------------------------------------------------------------
   DIRECCION: «sala de control». Las palabras son de PRODUCT.md — «la sala de
   control interna de una oficina inmobiliaria» — y de ahi sale todo lo visual:
   etiquetas instrumentadas en monoespaciada con su filete, un libro mayor con
   separadores finos en vez de tarjetas, una plantilla densa de agentes, y una
   banda invertida para los limites. Nada de eso es decoracion: cada pieza
   corresponde a como se lee un panel de control de verdad.

   POR QUE EL CRISTAL SE QUEDA PERO DEJA DE SER EL FONDO DE TODO: la referencia
   del registro brand dice que el glassmorphism «signals template», y con 18
   losas identicas tenia razon. Pero su primera ley es SPECIFICITY: cada
   eleccion visual trazable a algo real del producto. Aqui el cristal ES el
   material de la herramienta que se vende, asi que no es la plantilla generica
   — es la muestra. Se reserva para las DOS piezas donde el visitante decide
   (los planes) y el cierre. El resto vive sobre la aurora desnuda, con filetes
   y tipografia. Eso da ademas el contraste que brand.md pide.

   POR QUE ESTE CSS DUPLICA LOS TOKENS DE LA APP Y NO LOS IMPORTA: este sitio se
   despliega APARTE (ver LEEME.md) y no comparte build con la herramienta, asi
   que no hay forma de importar `app/styles/tokens.css` sin un paso de
   compilacion, que es justo lo que este sitio no tiene. Los valores estan
   COPIADOS de los tokens reales; si se repinta la marca hay que repuntarlos
   aqui a mano. Se dice en vez de fingir que estan sincronizados.

   SIN GOOGLE FONTS A PROPOSITO: cargar Inter desde el CDN de Google convertiria
   a Google en un tercero que ve la IP de cada visitante, y eso rompe la
   afirmacion «este sitio no carga terceros ni pone cookies» sobre la que se
   sostiene no tener banner de consentimiento.
   ========================================================================= */

/* --- Fuentes AUTOALOJADAS ------------------------------------------------
   Servidas desde /fonts/, no desde Google. Cargarlas de fonts.googleapis.com
   convertiria a Google en un tercero que ve la IP de cada visitante, y este
   sitio se sostiene sobre no tener NINGUNO: por eso no hay banner de cookies
   (art. 22.2 LSSI) y por eso la seccion 4 de privacidad.html puede decir que
   no se carga nada de otro dominio. Mismo origen = ni tercero, ni cookies, ni
   banner. El CSP ya lo permite (font-src 'self').

   PRECISION (2026-09-10): el condicional de arriba es correcto pero incompleto.
   Con la CSP de este sitio (`style-src 'self' 'unsafe-inline'; font-src 'self'`,
   en vercel.json y .htaccess) una fuente de Google NO llegaria a ver ninguna IP:
   el navegador la bloquea antes de que la peticion salga — medido en la app, que
   declara la misma directiva, con `blockedReason: "csp"` y 0 peticiones recibidas
   por un tercero local contra 1 en el control positivo. LO QUE HACE FALTA SABER
   ES QUE ESO NO BASTA: la fuente simplemente no se veria, y el arreglo que
   alguien encuentra para «que cargue» es RELAJAR la CSP. Por eso el invariante
   es que no se escriba, y desde hoy lo vigila `__tests__/css-sin-terceros.test.ts`
   — este fichero estuvo FUERA de ese barrido hasta el 2026-09-10, que es cuando
   se descubrio que el test invocaba a este sitio como su hermano ejemplar sin
   llegar a mirarlo nunca.

   La nota vieja del LEEME decia que una fuente propia exigiria Google Fonts.
   Era falsa, y esa premisa es la que mantuvo la pagina en system-ui.

   Solo el subconjunto LATIN: cubre el español entero y el ingles. 103 KB en
   cinco ficheros, con sus licencias en /fonts/. El detalle y el porque de
   Spectral frente a Newsreader e Instrument Serif, en fonts/LEEME-fuentes.txt.

   `swap` a proposito: el texto se lee desde el primer fotograma con la
   fallback y salta cuando llega la real. Un `block` dejaria la pagina muda
   ~100ms, que es peor que un salto. */

@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-500-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-500-italic-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Public Sans";
  src: url("../fonts/publicsans-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Mono";
  src: url("../fonts/plexmono-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex Mono";
  src: url("../fonts/plexmono-500-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;

  /* Copiados de app/styles/tokens.css (tema claro). */
  /* PAPEL, no cristal. La direccion A cambia el material: superficies opacas
     y filetes, sin translucidez, sin frost y sin aurora. Todo lo que dependia
     de componer capas (el reflejo, el rim, `prefers-reduced-transparency`) se
     retiro con ellas: no queda nada que reducir. */
  --bg: #f2efe8;
  --surface: #fbfaf7;
  /* HOY VALE LO MISMO QUE `--surface`, y no es un duplicado olvidado: lo usan
     los dos elementos que FLOTAN sobre contenido (el enlace de saltar y el
     panel de contacto), que no pueden volverse translucidos aunque el material
     cambie. Con la hoja opaca coinciden; el dia que la superficie vuelva a ser
     translucida, este es el token que se queda opaco. */
  --surface-solid: #fbfaf7;
  --hundido: #f7f5f0;
  --text: #17140f;
  --text-muted: #4a4438;
  --text-faint: #6b6455;

  /* Las tres familias. El display es serif y el dato es monoespaciada: la
     jerarquia la lleva la LETRA, no el color. */
  --fuente-display: Spectral, "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --fuente-texto: "Public Sans", ui-sans-serif, "Helvetica Neue", Arial, sans-serif;
  --fuente-mono: "Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --accent: #d8a838;
  --accent-text: #3d2500;
  --accent-ink: #6c5216;
  /* `--warning-ink` estaba en #7a4f06 bajo el comentario «copiados de la app»,
     y el valor real de la app es #894b03: la nota era falsa. Corregido al de
     la app. (`--success-ink` vivia aqui declarado en los dos temas y sin un
     solo consumidor en toda la hoja; retirado.) */
  --warning-ink: #894b03;
  /* Los dos estados de la ficha. Se declaran aqui porque son SEMANTICOS: el
     verde dice «verificado» y el rojo «no consta», y ese par es lo unico de la
     pagina que usa color con significado. Los valores se midieron sobre
     `--surface`, que es su lecho real. */
  --ok-ink: #2f6540;
  --danger-ink: #9d3020;
  --danger-soft: rgba(157, 48, 32, 0.06);
  /* `--edge` NO sale de tokens.css: no existe alli. Es propio de esta hoja,
     para el canto de las tres losas y los dos filetes de cabecera y pie. */
  --edge: rgba(23, 20, 15, 0.16);
  /* Filete: mas presente que `--edge` porque aqui SUSTITUYE a la caja de una
     tarjeta. Un separador que no se ve deja la seccion sin estructura. */
  --filete: rgba(80, 72, 58, 0.26);
  /* Borde de un CONTROL, que no es lo mismo que un separador decorativo:
     WCAG 1.4.11 le pide 3:1 porque es la unica señal de que eso es pulsable.
     `--filete` mide 1,50:1 y vale para una raya que solo estructura, no para
     el canto de un boton. Valor derivado a mano contra el punto MAS CLARO de
     la aurora (el peor caso), no contra el `--bg` liso: 3,49:1 en claro. */
  --borde-control: #7d7568;

  /* La banda invertida. En claro es el ground OSCURO del producto, asi que la
     inversion usa el material real y no un gris inventado. */
  --banda-bg: #1b1812;
  --banda-text: #f3efe6;
  --banda-muted: #b2aa98;
  --banda-filete: rgba(240, 240, 235, 0.16);
  --banda-ink: #e8b84a;

  --radius: 22px;
  --ancho: 1160px;

  /* Escala tipografica. La razon 1.25 rige los pasos CENTRALES (cuerpo 17 ->
     medio 21 -> grande 26 en su minimo); la mono y el display se salen a
     proposito, arriba para que el titular tenga su momento y abajo porque una
     etiqueta instrumentada tiene que leerse pequeña. El comentario anterior
     decia «razon 1.25 entre pasos» a secas y solo lo cumplian dos de cuatro.

     SECUNDARIO Y NOTA son un escalon corto (17 -> 16 -> 15) y eso NO es la
     razon 1.25: la jerarquia entre cuerpo y secundario la lleva el COLOR
     (--text-muted contra --text), no el tamaño. Existen como token porque el
     valor estaba escrito a mano en SIETE reglas, y el mismo numero repetido se
     desincroniza. El limite de abajo es 16px para todo lo que se lee en
     secuencia; por debajo solo baja lo que es pie de algo (copyright, la nota
     del precio) o rotulo instrumentado, que no es cuerpo de lectura. */
  --t-mono: 12px;
  --t-nota: 15px;
  --t-secundario: 16px;
  --t-cuerpo: 17px;
  --t-medio: 21px;
  --t-grande: clamp(26px, 3.2vw, 34px);
  --t-display: clamp(40px, 7.4vw, 82px);

  /* Aire entre la entradilla de una seccion y el bloque que la sigue. Existe
     porque ese patron —`margin-top` + `border-top` sobre el filete— se repite
     CUATRO veces (.mayor, .limites, .plantilla, .incluye) y cada una tenia su
     propio clamp: 34/5/58, 34/5/56, 30/4/52 y 30/4/48. Cuatro valores para un
     solo gesto es deriva, no ritmo, y a 1440px se veian los cuatro a la vez.

     El valor NO se elige a ojo: es la MITAD del ritmo de `section`
     (clamp(54px, 8vw, 104px)) redondeada al suelo que ya tenian dos de las
     cuatro. 4vw es la mitad de 8vw y 52 es la mitad de 104, asi que el bloque
     respira exactamente la mitad que la seccion que lo contiene. */
  --aire-bloque: clamp(30px, 4vw, 52px);

  --curva: cubic-bezier(0.16, 1, 0.3, 1); /* ease-out-expo, sin rebote */
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    /* «Papel de noche»: el mismo sistema editorial con la tinta invertida.
       Superficies opacas, sin cristal y sin aurora, igual que en claro. */
    --bg: #14120e;
    --surface: #1c1a15;
    --surface-solid: #1c1a15;
    --hundido: #191710;
    --text: #f0ece3;
    --text-muted: #b6ae9c;
    --text-faint: #918a79;
    --accent: #e8b84a;
    --accent-text: #261a00;
    --accent-ink: #e8b84a;
    --warning-ink: #f6a61f;
    --ok-ink: #85c39a;
    --danger-ink: #e39280;
    --danger-soft: rgba(227, 146, 128, 0.09);
    --edge: rgba(240, 238, 232, 0.14);
    --filete: rgba(240, 240, 235, 0.20);
    --borde-control: #837b6c; /* 3:1 sobre el papel de noche, ya sin aurora */

    /* En oscuro la banda se ACLARA en vez de oscurecerse: invertir hacia el
       mismo lado no invierte nada. */
    --banda-bg: #f2efe8;
    --banda-text: #17140f;
    --banda-muted: #4c4636;
    --banda-filete: rgba(80, 72, 58, 0.24);
    --banda-ink: #6c5216;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* La cabecera es sticky y mide 68px, asi que sin esto un salto a un ancla
     (o el foco llegando con Shift+Tab) deja el destino DEBAJO de ella. Los
     84px son los 68 de la cabecera mas un respiro. Cubre a la vez los tres
     anclajes internos y la navegacion por teclado (WCAG 2.4.11). */
  scroll-padding-top: 84px;
}

body {
  margin: 0;
  /* GROUND PLANO. La aurora se retiro con el cristal: un resplandor de color
     detras de una pagina de papel pelea con lo editorial, y ademas era lo que
     obligaba a teselar cada medicion (`background-attachment: fixed` falsea
     una captura de pagina completa). Sin ella, el lecho de un texto es el
     token que tiene debajo y punto. */
  background: var(--bg);
  color: var(--text);
  font-family: var(--fuente-texto);
  font-size: var(--t-cuerpo);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  /* La Public Sans trae versalitas y numeros de caja alta reales. */
  font-feature-settings: "kern" 1;
}

img {
  max-width: 100%;
  height: auto;
}

h1,
h2,
h3 {
  margin: 0;
  font-family: var(--fuente-display);
  /* 500 y no 800: el fichero de Spectral que se sirve es el 500, asi que pedir
     700 u 800 haria que el navegador SINTETIZARA una negrita engordando los
     trazos. En un serif de contraste alto eso se ve, y ademas seria un peso
     que no existe. La presencia la da el tamaño, no el grosor. */
  font-weight: 500;
  /* Menos tracking negativo que un grotesco: un serif de display ya viene
     ajustado y apretarlo mas le come el contraste entre asta y remate. */
  letter-spacing: -0.018em;
  line-height: 1.06;
  /* Reparte las lineas de un titular en vez de dejar la ultima colgando. Es
     lo que resuelve el rag debil del h1 (ver su regla mas abajo). Un navegador
     que no lo soporte lo ignora y queda como estaba: cero riesgo. */
  text-wrap: balance;
}

/* Evita la VIUDA: una ultima linea con una sola palabra. Medido sobre las tres
   paginas en ocho anchos: 110 bloques con viuda antes, 70 despues, y cero
   desbordes nuevos. Tambien se ignora sin soporte. */
p,
li,
dd {
  text-wrap: pretty;
}

p {
  margin: 0;
}

/* `ol` ADEMAS de `ul`: el reset solo cubria `ul`, y la ficha del hero trajo
   el PRIMER <ol> del sitio -> se pinto con los marcadores del navegador
   («1. MANDATO — 3. COMERCIAL …», con los numeros de las rayas decorativas
   contando y colandose en una segunda linea) y con su `margin: 1em 0` por
   defecto. Se completa aqui y no en `.ficha-fases` para que el siguiente <ol>
   que alguien escriba no estrene la misma trampa.
   Quien use estas listas necesita `role="list"`: `list-style: none` le quita
   a Safari la semantica de lista. */
ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

.envoltorio {
  width: 100%;
  max-width: var(--ancho);
  margin: 0 auto;
  padding: 0 24px;
}

/* --- Salto al contenido (WCAG 2.4.1) -------------------------------------
   Fuera de pantalla hasta que recibe el foco. No se usa `display: none` ni
   `visibility: hidden` a proposito: eso lo sacaria del orden de tabulacion y
   el enlace dejaria de existir para quien lo necesita. */
.saltar {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 14px 22px;
  background: var(--surface-solid);
  color: var(--text);
  border: 1px solid var(--borde-control);
  border-radius: 0 0 var(--radius) 0;
  font-weight: 700;
  text-decoration: none;
}

.saltar:focus {
  left: 0;
}

/* --- Selector de idioma ---------------------------------------------------
   ES ↔ EN, y es un ENLACE, no un widget: cada idioma es su propia URL
   (`/` y `/en/`). Consecuencias buscadas, las tres:
   · el contenido sigue en el HTML, asi que funciona sin JavaScript y un
     rastreador ve la pagina traducida de verdad. Traducir con JS habria roto
     la regla dura de este sitio y habria dejado UNA sola URL para dos idiomas,
     que Google no puede indexar por separado.
   · NO se guarda la preferencia en ningun sitio. localStorage tambien es
     «almacenamiento» a efectos del art. 22.2 de la LSSI, y la frase «este sitio
     no pone cookies ni guarda nada» es la que sostiene no tener banner. Un
     enlace no guarda nada.
   · NO hay redireccion automatica por `navigator.language`: mandaria a un
     hispanohablante con el navegador en ingles a la version que no queria, y
     exigiria JS para servir contenido.
   El activo NO va relleno: la cabecera ya tiene el boton dorado y un segundo
   relleno le quitaria a ese su papel de unica accion. */
.idioma {
  display: flex;
  align-items: center;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  letter-spacing: 0.08em;
}

.idioma > * {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px de alto tambien en el que NO es enlace: si solo lo tuviera el enlace,
     los dos quedarian a distinta altura y el filete de en medio se veria corto. */
  min-height: 44px;
  padding: 0 10px;
}

.idioma > * + * {
  border-left: 1px solid var(--filete);
}

.idioma-on {
  color: var(--text);
  font-weight: 700;
}

.idioma a {
  color: var(--text-muted);
  text-decoration: none;
  /* Diana de 44x44 (WCAG 2.5.5). El `.idioma-on` no la necesita porque no es
     interactivo, y darsela ensancharia la cabecera sin ganar nada. */
  min-width: 44px;
  border-radius: 10px;
  transition: color 0.28s var(--curva);
}

.idioma a:hover,
.idioma a:focus-visible {
  color: var(--text);
}

.cabecera-acciones {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Entrar / Sign in. Misma forma que `.idioma a` —44px de diana (WCAG 2.5.5),
   color apagado que sube al pasar— para que la cabecera siga teniendo UN solo
   relleno: el CTA comercial. Si esto fuera un `.btn`, competiria con el.

   SOLO EN LAS DOS PORTADAS, y esta acotacion esta MEDIDA, no elegida: las
   cuatro paginas legales llevan un CTA largo («Volver al inicio» / «Back to
   home»), y con una cuarta pieza en la barra su cabecera —que es sticky, o sea
   permanente— pasa de 68 a 72,5px a 430 y 360, y a 320 en ingles de 68 a
   **95,8px**: tres lineas. Es el mismo defecto que esta hoja ya documenta unas
   lineas mas abajo para el CTA de la portada. A una pagina legal se llega desde
   el pie y ya tiene su boton de vuelta, asi que el coste no lo paga el
   beneficio. Si algun dia se quiere ahi, hay que acortar antes ese CTA. */
.acceso {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 10px;
  color: var(--text-muted);
  text-decoration: none;
  border-radius: 10px;
  /* «Sign in» son dos palabras y a 320/460px partia en dos lineas dentro
     del enlace («Sign / in»). No engordaba la barra, pero se leia roto. */
  white-space: nowrap;
  transition: color 0.28s var(--curva);
}

.acceso:hover,
.acceso:focus-visible {
  color: var(--text);
}

/* Matiz dentro de una linea de la lista de incluidos: dice el limite sin
   romper el ritmo de la lista. No baja de `--text-muted` (medido AA). */
.matiz {
  color: var(--text-muted);
}

/* --- Etiqueta instrumentada: monoespaciada + filete hasta el borde ---------
   Sustituye al «eyebrow» suelto. El filete es lo que la convierte en la marca
   de un instrumento en vez de un rotulo decorativo, y de paso estructura la
   seccion sin necesidad de meter nada en una caja. */
.rotulo {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 26px;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.rotulo::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--filete);
}


/* Marcador de dato PENDIENTE de rellenar. Se pinta en ambar y con borde para
   que el hueco SE VEA en la pagina renderizada: la unica proteccion real contra
   publicar el sitio con «[[CORREO]]» dentro es que sea imposible no verlo. Es
   el criterio de la pantalla de Captacion web de la app, que pinta «falta el
   NIF» en vivo en vez de dejar el hueco callado. */
/* EXCEPCION DELIBERADA a «0 clases muertas»: hoy no tiene sujeto porque los
   marcadores `[[ASI]]` estan todos rellenados, y existe precisamente para el
   dia que alguien vuelva a poner uno. Su valor es pintarlo en ambar ANTES de
   que se publique; borrarla dejaria ese fallo sin ninguna señal. No es un
   resto: es una red. */
.pendiente {
  display: inline;
  padding: 0 6px;
  border: 1px dashed var(--warning-ink);
  border-radius: 6px;
  color: var(--warning-ink);
  font-size: 0.9em;
  font-weight: 600;
  /* SIN `white-space: nowrap`: los marcadores legales son largos y con nowrap
     desbordaban 224px en un movil de 390 (medido). */
  overflow-wrap: anywhere;
}

/* --- Superficie. Ya no es una losa de cristal: es una hoja. ---------------
   El material entero cambio con la direccion A. Fuera el `backdrop-filter`,
   el reflejo especular del ::before y el rim: una hoja de papel no refracta
   lo que tiene detras. Queda un plano opaco con su canto y una sombra corta,
   que es como se apoya una hoja sobre otra.

   Con la translucidez se fueron tres cosas que dependian de ella y que ya no
   tienen sujeto: el bloque `@supports not (backdrop-filter)`, el de
   `prefers-reduced-transparency` y el token `--sheen`. No se «olvidaron»: no
   queda nada que reducir. */

.losa {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow:
    0 1px 2px rgba(23, 20, 15, 0.04),
    0 10px 26px rgba(23, 20, 15, 0.06);
}

@media (prefers-color-scheme: dark) {
  .losa {
    box-shadow: none;
  }
}

/* --- Botones -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px de diana (WCAG 2.5.5), que es el estandar que PRODUCT.md fija para
     todo el producto. Se consigue con el padding, no con un min-height que
     desalinearia el texto. */
  padding: 14px 26px;
  border: 1px solid transparent;
  border-radius: 999px;
  /* RESERVA ANTES DEL GRADIENTE, y las dos lineas hacen falta: un navegador
     sin `color-mix()` descarta la declaracion entera por invalida, y sin esta
     primera el unico CTA de la pagina se quedaria SIN relleno (texto marron
     sobre el fondo, ~1,1 de contraste). Uno que si lo soporte pisa la primera
     con la segunda y no cambia nada. */
  background: var(--accent);
  background: linear-gradient(135deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 78%, #ffffff) 100%);
  color: var(--accent-text);
  font: inherit;
  font-size: var(--t-cuerpo);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.28s var(--curva), box-shadow 0.28s var(--curva);
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 26px rgba(20, 16, 10, 0.16);
}

.btn.discreto {
  background: none;
  /* `--filete` (1,50:1) valia para un separador y no para el canto de un
     boton, que aqui es su UNICA señal de que es pulsable: WCAG 1.4.11 pide
     3:1 para el limite de un control. */
  border-color: var(--borde-control);
  color: var(--text);
}

.btn:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

/* --- Cabecera. Minima: no compite con el mensaje. ------------------------- */

.cabecera {
  position: sticky;
  top: 0;
  z-index: 10;
  /* OPACA. Antes era `--bg` al 88% con `blur(14px)`, que era el idioma del
     cristal; sobre papel, el contenido pasando difuminado por debajo de la
     barra al scrollear se lee como una mancha, no como profundidad. Un plano
     opaco con su filete es lo que hace una cabecera de documento. */
  background: var(--bg);
  border-bottom: 1px solid var(--filete);
}

.cabecera-fila {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 68px;
}

.marca {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  /* Diana de 44px tambien aqui: es un enlace. */
  padding: 11px 0;
  color: var(--text);
  font-weight: 800;
  letter-spacing: -0.03em;
  text-decoration: none;
  font-size: 19px;
}

.marca img {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  flex-shrink: 0;
}

/* La cabecera es STICKY, asi que lo que crezca aqui se lo come el viewport de
   forma permanente. Medido: el texto del boton envolvia a dos lineas y la
   cabecera pasaba de 69px a 84 por debajo de 375px, y a 110 a 320px, o sea un
   septimo de la pantalla de un movil pequeño ocupado para siempre. Se aprieta
   el boton en vez de esconderlo: la diana sigue por encima de 44px. */
@media (max-width: 430px) {
  .cabecera .btn {
    padding: 12px 16px;
    font-size: 15px;
  }
  .marca {
    font-size: 17px;
  }
  /* El selector de idioma es el TERCER elemento de una fila que ya iba justa, y
     medido a 320px hacia dos cosas a la vez: desbordar 4-9px y empujar el texto
     del boton a dos lineas, con la cabecera —que es sticky— pasando de 74 a
     97px. Se aprieta el toggle en vez de esconderlo o de sacarlo de la
     cabecera: quien llega a una landing en un idioma que no lee tiene que poder
     cambiarlo SIN scrollear hasta el pie.
     El que se aprieta es el rotulo del idioma ACTUAL, que no es interactivo; el
     enlace conserva sus 44x44 (WCAG 2.5.5) porque esa es la diana. */
  .idioma > * {
    padding: 0 4px;
  }
  .cabecera-acciones {
    gap: 2px;
  }
  .cabecera-fila {
    gap: 10px;
  }
}

/* A 320px ni apretando cabe todo: medido, el CTA se quedaba en 73px cuando
   «Pedir una demo» pide 144, asi que envolvia a dos lineas y la cabecera
   —sticky, o sea permanente— pasaba de 74 a 97px. En una pantalla de 568px de
   alto eso es un sexto ocupado para siempre.
   Se retira el NOMBRE de la marca y se conserva el logotipo, que sigue llevando
   a la portada.
   `clip-path` y no `display: none`: el <img> es decorativo (alt=""), asi que
   ocultarlo del arbol dejaria el enlace SIN NOMBRE ACCESIBLE. Asi el lector de
   pantalla sigue diciendo «Proce.SOS» y solo desaparece de la vista.

   ⚠️ EL UMBRAL ERA 340 Y AHORA ES 420, y el motivo es que su premisa cambio:
   ese 340 se calibro con TRES piezas en la barra (marca + idioma + CTA). El
   2026-09-07 entro una cuarta —«Entrar», la puerta a la app, que no existia— y
   medido, con ella la barra DESBORDA la pagina en horizontal: 14px a 390 y
   44px a 360, con el nombre puesto. El nombre pide ~94px y es lo unico
   decorativo de la fila; el logotipo se queda y sigue llevando a la portada. */
@media (max-width: 420px) {
  .marca-nombre {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* --- Hero ---------------------------------------------------------------- */

.hero {
  padding: clamp(56px, 9vw, 116px) 0 clamp(48px, 7vw, 92px);
}

/* ASIMETRICO a proposito: el titular ocupa dos tercios y el inventario del
   dolor cuelga a la derecha, mas pequeño y en monoespaciada. Es el «visual
   tension» de brand.md — un elemento grande junto a uno pequeño y tecnico — y
   evita el patron «titular + subtitular + dos botones» que la referencia marca
   como invisible. */
.hero-rejilla {
  display: grid;
  gap: clamp(30px, 4vw, 56px);
  /* 1.15/1 y no 1.55/1: la derecha ya no es una lista fina, es la ficha de un
     expediente y necesita ancho para que sus filas no envuelvan.
     Y `start` en vez de `end`: con `end` la columna derecha se pegaba al
     fondo y dejaba ~460px de vacio arriba (medido en la pagina publicada).
     Ese hueco se leia como un fallo, no como aire. */
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: start;
}

@media (max-width: 900px) {
  .hero-rejilla {
    /* `minmax(0, 1fr)` y NO `1fr`: el minimo automatico de una pista `1fr` es
       el MIN-CONTENT de lo que lleva dentro, asi que un hijo ancho no encoge
       la pista, la REVIENTA. Medido: la fila de fases de la ficha pide 369,7px
       de min-content y con `1fr` la columna se quedaba clavada en 371,7px a
       390, 360 y 320px por igual, empujando 6px de scroll horizontal a toda
       la pagina. El `0` de minimo es lo que deja que la columna encoja. */
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }
}

h1 {
  font-size: var(--t-display);
  /* CORRECCION DE UNA NOTA FALSA: aqui decia «con 20 rompe en dos», y medido
     NO era cierto en escritorio. A 1024-1440px el titular rompe en TRES lineas
     y la del medio queda en «en una», que es exactamente el rag debil que esta
     nota decia haber evitado. El motivo: `--t-display` se calcula con `vw`
     (el viewport) mientras el h1 vive en una columna de ~645px, asi que el
     `max-width: 20ch` (~820px a 82px) NO llega a aplicarse nunca: quien acota
     es la columna.
     Lo que lo resuelve de verdad es `text-wrap: balance` (en la regla comun de
     h1/h2/h3): a 1280px pasa de «La oficina entera / en una / herramienta.» a
     «La oficina / entera en una / herramienta.», sin tocar el tamaño del
     display. El `max-width` se conserva porque sigue acotando por encima de
     ~1500px, donde la columna si supera los 20ch. */
  max-width: 20ch;
}

/* La palabra que carga el titular. Ahora el enfasis lo hace la LETRA, no el
   color: la cursiva del serif. Es el gesto editorial de la direccion A, y de
   paso quita un uso de color como unico portador. El fichero de la cursiva de
   Spectral se sirve a proposito (23,6 KB) porque es lo que lo hace posible. */
.h1-acento {
  font-style: italic;
}

.hero-sub {
  margin-top: 26px;
  font-size: var(--t-medio);
  line-height: 1.45;
  color: var(--text-muted);
  max-width: 46ch;
}

.hero-cta {
  margin-top: 34px;
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.hero-dato {
  font-family: var(--fuente-mono);
  font-size: 13px;
  /* `--text-muted` y no `--text-faint`: sobre la aurora desnuda el faint media
     4,56 en oscuro, que pasa AA por 0,06 y es un margen de cuchillo para un
     rotulo que este pase introduce. La jerarquia la llevan ya la monoespaciada,
     las versalitas y el interletraje, no el color. Mismo criterio con el que se
     subio `.pnl-lbl` en el Panel de la app. */
  color: var(--text-muted);
}

/* El inventario del dolor: cuatro sitios que no se hablan. Es el dato mas
   especifico que tiene el producto y venia escrito en PRODUCT.md. */
/* `--aire-bloque` y no un numero a mano: es el mismo aire con el que abren
   `.mayor` y `.planes` tras la nota de seccion. Sin el, este bloque quedaba a
   HUECO CERO de la nota de arriba y su filete pasaba pegado a la ultima linea
   del parrafo: se leia como una colision, no como una separacion. */
.antes {
  margin-top: var(--aire-bloque);
  border-top: 1px solid var(--filete);
}

.antes-titulo {
  margin: 14px 0 4px;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.antes li {
  padding: 11px 0;
  border-bottom: 1px solid var(--filete);
  font-size: var(--t-secundario);
  color: var(--text-muted);
}

.antes li:last-child {
  border-bottom: 0;
}

.antes b {
  color: var(--text);
  font-weight: 600;
}

/* --- Cifras del hero -----------------------------------------------------
   Tres numeros y su rotulo. NO son metricas de negocio inventadas: los tres
   salen del producto y estan documentados — ocho agentes (`AGENTES_NAV`),
   diecinueve comunidades con tipos propios, y el invariante de que nada sale
   sin aprobacion humana. Un cero que es una BUENA noticia, y por eso se dice.

   Es el sustituto honesto de la prueba social que esta pagina no puede tener:
   no hay clientes, ni testimonios, ni casos. Lo que si hay es el producto. */

.cifras {
  display: flex;
  flex-wrap: wrap;
  gap: 12px clamp(28px, 4vw, 48px);
  margin-top: clamp(34px, 4vw, 54px);
  padding-top: 22px;
  border-top: 1px solid var(--filete);
}

/* La misma etiqueta instrumentada que `.rotulo` pero SIN el filete: dentro de
   la ficha no hay ancho que recorrer, y una raya de 6px no estructura nada. */
.rotulo-plano {
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.cifras li {
  display: block;
}

.cifra-num {
  display: block;
  font-family: var(--fuente-display);
  font-size: 30px;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.cifra-rot {
  display: block;
  margin-top: 6px;
  font-family: var(--fuente-mono);
  font-size: 10.5px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --- La ficha de un expediente -------------------------------------------
   LA PIEZA QUE FALTABA. La pagina vendia «veras el estado de un expediente» y
   no enseñaba ni una pantalla: se pedian 99 €/mes a ciegas. Esto no es una
   captura (envejeceria y pesaria); es la superficie dibujada con el marcado
   del propio sitio, asi que hereda tema, tipografia y accesibilidad.

   Los datos son DE MUESTRA y la pagina lo dice debajo. No hay ningun nombre
   ni direccion de una persona real: la referencia es inventada y el inmueble
   se describe sin numero de portal. */

.ficha {
  background: var(--surface);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  overflow: hidden;
}

@media (prefers-color-scheme: light) {
  .ficha {
    box-shadow:
      0 1px 2px rgba(23, 20, 15, 0.04),
      0 10px 26px rgba(23, 20, 15, 0.06);
  }
}

.ficha-cab,
.ficha-pie {
  padding: 16px clamp(18px, 2vw, 24px);
}

.ficha-cab {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--edge);
}

.ficha-ref {
  font-family: var(--fuente-mono);
  font-size: 13px;
  font-weight: 500;
}

.ficha-cuerpo {
  padding: 18px clamp(18px, 2vw, 24px) 0;
}

.ficha-inmueble {
  font-size: var(--t-secundario);
  font-weight: 600;
}

.ficha-meta {
  margin-top: 5px;
  font-family: var(--fuente-mono);
  font-size: 12px;
  color: var(--text-muted);
}

/* Las fases del expediente. Es la secuencia real del producto: Mandato ->
   comercializacion -> propuesta -> arras -> notaria -> cierre. */
.ficha-fases {
  display: flex;
  align-items: center;
  gap: 7px;
  /* ENVUELVE antes que esconder: sin `wrap` la fila pide 369,7px de min-content
     y en un movil de 390 las dos ultimas fases se iban fuera de la tarjeta. El
     `overflow-x: auto` de debajo las habria dejado tras un scroll lateral que
     nadie ve, y aqui la ultima fase («Cierre») es justo la que cuenta la
     historia. Con dos lineas se leen las cinco. */
  flex-wrap: wrap;
  row-gap: 9px;
  padding: 20px clamp(18px, 2vw, 24px);
  /* Red de debajo para un ancho absurdo: con `wrap` no llega a hacer falta a
     390 ni a 320, pero un zoom de texto grande si puede pedirlo. */
  overflow-x: auto;
}

.ficha-fase {
  font-family: var(--fuente-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}

.ficha-fase[aria-current="step"] {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 9px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 500;
}

.ficha-raya {
  flex-grow: 1;
  min-width: 10px;
  height: 1px;
  background: var(--filete);
}

.ficha-docs-cab {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 0 clamp(18px, 2vw, 24px) 12px;
}

.ficha-doc {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px clamp(18px, 2vw, 24px);
  border-top: 1px solid var(--edge);
  font-size: 14.5px;
}

.ficha-doc svg {
  flex-shrink: 0;
}

.ficha-doc-nombre {
  flex-grow: 1;
}

.ficha-doc-estado {
  font-family: var(--fuente-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ok-ink);
}

/* La fila que justifica la pieza entera: el documento que NO esta. */
.ficha-doc.falta {
  background: var(--danger-soft);
}

.ficha-doc.falta .ficha-doc-nombre {
  font-weight: 600;
}

.ficha-doc.falta .ficha-doc-estado,
.ficha-doc.falta svg {
  color: var(--danger-ink);
}

.ficha-pie {
  border-top: 1px solid var(--edge);
  background: var(--hundido);
}

.ficha-incidencia {
  font-family: var(--fuente-mono);
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--danger-ink);
}

.ficha-texto {
  margin-top: 7px;
  font-size: 14.5px;
  line-height: 1.5;
}

.ficha-destino {
  margin-top: 9px;
  font-family: var(--fuente-mono);
  font-size: 11.5px;
  color: var(--text-muted);
}

.ficha-muestra {
  margin-top: 12px;
  font-family: var(--fuente-mono);
  font-size: 11.5px;
  color: var(--text-muted);
}

/* --- Secciones ----------------------------------------------------------- */

/* El RITMO de las bandas de la pagina. Ojo: esto es lo que hace que la ficha
   del hero NO pueda ser un <section> — al serlo heredaba 102,4px de padding
   vertical y la tarjeta abria con una franja vacia que se leia como un
   desajuste, no como aire. Es un <div> a proposito (ver su comentario). */
section {
  padding: clamp(54px, 8vw, 104px) 0;
}

/* Ritmo VARIADO, no el mismo padding en todas: la ley compartida lo pide
   explicitamente, y la seccion del precio es la que decide, asi que respira
   mas que las demas. */
#precio {
  padding: clamp(66px, 10vw, 132px) 0;
}

h2 {
  font-size: var(--t-grande);
  max-width: 24ch;
}

.seccion-nota {
  margin-top: 16px;
  color: var(--text-muted);
  max-width: 58ch;
}

/* --- Libro mayor: sustituye a la rejilla de tres tarjetas iguales --------- */

.mayor {
  margin-top: var(--aire-bloque);
  border-top: 1px solid var(--filete);
}

.mayor-fila {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) minmax(0, 1.35fr);
  gap: clamp(16px, 3vw, 40px);
  align-items: start;
  padding: clamp(24px, 3.4vw, 38px) 0;
  border-bottom: 1px solid var(--filete);
}

@media (max-width: 820px) {
  .mayor-fila {
    grid-template-columns: 3rem minmax(0, 1fr);
    gap: 14px 18px;
  }
  /* El cuerpo pasa a la segunda columna, bajo el titulo, en vez de estrujarse
     en un tercio: envolver antes que comprimir. */
  .mayor-cuerpo {
    grid-column: 2;
  }
}

.mayor-num {
  font-family: var(--fuente-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--accent-ink);
  padding-top: 0.35em;
}

.mayor-titulo {
  font-size: var(--t-medio);
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.2;
}

.mayor-cuerpo {
  color: var(--text-muted);
  max-width: 52ch;
}

/* --- Plantilla de agentes: densa y tipografica, no ocho cajas iguales ----- */

.plantilla {
  margin-top: var(--aire-bloque);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  column-gap: clamp(28px, 5vw, 72px);
  border-top: 1px solid var(--filete);
}

/* La columna del rol es 8.5rem y no 7.5 POR EL TAMAÑO DE SU LETRA: al subir
   .agente-rol de 11px a 12px un segundo rol pasaba a envolver («CEO ·
   Direccion» se sumaba a «Voz · Speed-to-Lead»). Medido a 1280 y 900: con
   8.5rem vuelve a envolver uno solo, sin desborde y sin mover el alto de la
   seccion a 1280. Si alguien vuelve a tocar ese font-size, hay que remedir
   esta columna: las dos cosas van juntas. */
.agente {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: 6px 20px;
  padding: 17px 0;
  border-bottom: 1px solid var(--filete);
}

.agente-nombre {
  font-size: var(--t-medio);
  font-weight: 700;
  /* -0.022em y no -0.024: es el interletraje que ya usan los otros TRES
     titulares de este tamaño (.mayor-titulo, .limite h3, .legal-cuerpo h2).
     Era el unico valor suelto de la familia; los -0.028em de h1/h2 son otro
     escalon (tipo grande) y se quedan. */
  letter-spacing: -0.022em;
  line-height: 1.15;
}

.agente-rol {
  grid-column: 1;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-ink);
  padding-top: 0.5em;
}

.agente-que {
  grid-column: 2;
  font-size: var(--t-secundario);
  color: var(--text-muted);
}

@media (max-width: 560px) {
  .agente {
    grid-template-columns: 1fr;
    gap: 3px;
  }
  .agente-rol,
  .agente-que {
    grid-column: 1;
    padding-top: 0;
  }
}

/* --- Precio: una TARIFA por tamano de oficina, no una fila de planes. -----
   El precio dejo de ser unico el 2026-08-24: va por tramos segun el numero de
   ASESORES ACTIVOS de la oficina, que es lo que mueve el coste (los
   expedientes escalan con ellos y el supervisor documental es la linea mas
   grande). Ver lib/facturacion/tramos.ts.

   POR QUE UNA TABLA Y NO TRES TARJETAS. Con tres precios publicados, la salida
   por costumbre es la tabla de tres columnas con la del medio destacada, que
   es EXACTAMENTE el patron de plantilla invisible que este pase prohibe (y el
   motivo de la decision «dos planes, no tres»). Aqui el objeto es otro: los
   datos son bidimensionales de verdad —tramo x periodo— asi que van en un
   <table> con sus cabeceras de fila y de columna. Es una tarifa, como el anexo
   de precios de un contrato, no un escaparate de planes.

   Y por eso tampoco hay columna destacada: la recomendacion la lleva escrita
   la cabecera del anual («dos meses gratis»), que es un hecho, no una
   pegatina. */

.tarifa-losa {
  margin-top: clamp(32px, 4vw, 54px);
  padding: clamp(22px, 2.6vw, 34px) clamp(20px, 2.6vw, 34px);
  /* ACOTADA a proposito. A todo el ancho del contenedor (1112px) quedaban 270px
     de vacio entre el tramo y su precio mensual y otros 430 hasta el anual: la
     fila dejaba de leerse de un tiron. Con esta medida el bloque se lee como lo
     que es, una tarifa, y de paso da la asimetria que el resto de la seccion
     (prosa a 58ch) ya tiene. */
  max-width: 780px;
}

.tarifa {
  width: 100%;
  border-collapse: collapse;
  /* Cifras alineadas en columna: sin esto los importes bailan de fila a fila
     y una tarifa deja de leerse de un vistazo. */
  font-variant-numeric: tabular-nums;
}

.tarifa caption {
  caption-side: top;
  text-align: left;
  padding-bottom: 16px;
  color: var(--text-muted);
  font-size: var(--t-nota);
}

.tarifa thead th {
  padding: 0 0 12px;
  border-bottom: 1px solid var(--filete);
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: right;
  vertical-align: bottom;
}

.tarifa-ahorro {
  display: block;
  margin-top: 4px;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
  text-transform: none;
}

.tarifa tbody th,
.tarifa tbody td {
  padding: 18px 0;
  border-bottom: 1px solid var(--filete);
  text-align: right;
  vertical-align: baseline;
}

.tarifa tbody tr:last-child th,
.tarifa tbody tr:last-child td {
  border-bottom: 0;
  padding-bottom: 0;
}

/* La primera columna es el SUJETO de cada fila (el tamano de la oficina), no
   un dato: se alinea a la izquierda como el texto que es.
   VA AQUI, DESPUES de la regla general de celda, y no antes: las dos tienen la
   misma especificidad (0,2,0), asi que a igualdad manda la ultima. Escrita
   arriba, el `text-align: right` de las celdas se la comia y las etiquetas de
   tramo salian pegadas a la columna del medio. */
.tarifa thead th:first-child,
.tarifa tbody th {
  text-align: left;
}

.tarifa tbody th {
  font-weight: 600;
  font-size: var(--t-secundario);
  padding-right: 16px;
}

.tarifa-cifra {
  font-family: var(--fuente-display);
  /* 500 por lo mismo que los titulares: el unico fichero de Spectral que se
     sirve es el 500, y pedir mas lo sintetiza. */
  font-weight: 500;
  font-size: clamp(26px, 3.2vw, 36px);
  letter-spacing: -0.018em;
  line-height: 1;
}

/* El tramo que no se contrata solo NO lleva cifra, y no es que falte: por
   encima de esa cartera hay que dimensionar la instalacion. Va en el tono del
   texto secundario para que no se lea como un precio tachado. */
.tarifa-medida td {
  color: var(--text-muted);
  font-size: var(--t-secundario);
}

/* A partir de aqui las tres columnas no caben sin apretar los importes contra
   su etiqueta, asi que cada tramo pasa a ser un BLOQUE: el tamano manda y los
   dos periodos van debajo, cada uno con su rotulo. Se conserva el <table> —los
   datos siguen siendo tabulares y el lector de pantalla sigue leyendo sus
   cabeceras—: lo unico que cambia es como se pintan. */
@media (max-width: 620px) {
  .tarifa thead {
    /* `clip` y no `display:none`: ocultarlo del todo se lleva tambien las
       cabeceras de columna del arbol de accesibilidad, y son las que dicen si
       una cifra es al mes o al ano. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .tarifa tbody tr {
    display: block;
    padding: 16px 0;
    border-bottom: 1px solid var(--filete);
  }

  .tarifa tbody tr:last-child {
    border-bottom: 0;
    padding-bottom: 0;
  }

  .tarifa tbody th,
  .tarifa tbody td {
    display: block;
    padding: 0;
    border-bottom: 0;
    text-align: left;
  }

  .tarifa tbody th {
    padding-bottom: 10px;
  }

  /* El rotulo del periodo lo pone el CSS con `data-periodo`: en esta forma la
     cifra se queda sin su cabecera de columna a la vista. */
  .tarifa tbody td::before {
    content: attr(data-periodo);
    display: block;
    margin-bottom: 2px;
    font-family: var(--fuente-mono);
    font-size: var(--t-mono);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
  }

  .tarifa tbody td + td {
    margin-top: 12px;
  }

  /* La fila «a medida» no tiene periodo que rotular: sin esto su ::before
     pintaria un bloque vacio con su margen. */
  .tarifa-medida td::before {
    content: none;
  }

  .tarifa-cifra {
    font-size: 30px;
  }
}

/* La regla del anual y el alcance de los tramos: dos hechos que valen para
   TODAS las filas, asi que se dicen una vez debajo y no seis veces dentro de
   la tabla. */
.tarifa-nota {
  margin-top: 22px;
  color: var(--text-muted);
  font-size: var(--t-secundario);
  max-width: 58ch;
}

.tarifa-nota b {
  color: var(--text);
  font-weight: 600;
}

/* Lo que incluye NO es un plan, asi que sale de la fila de planes: dejarlo como
   tercera columna es el patron «tres tarifas» que la referencia marca. */
.incluye {
  margin-top: var(--aire-bloque);
  display: grid;
  /* DOS columnas: con tres y siete items caian 3/3/1 y varias lineas dejaban
     una palabra huerfana en la suya. Con dos van 4/3 y casi ninguna envuelve. */
  grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
  gap: 2px clamp(28px, 5vw, 72px);
  border-top: 1px solid var(--filete);
  padding-top: 22px;
  /* El contador vive en el CSS y no en el HTML: añadir o quitar una linea de
     la lista no obliga a renumerar a mano ni en las dos versiones de idioma. */
  counter-reset: incluye;
}

.incluye li {
  position: relative;
  padding: 7px 0 7px 32px;
  font-size: var(--t-secundario);
  color: var(--text-muted);
}

/* Un GUION como viñeta era el eslabon debil de este bloque: una raya de 7px
   no marca nada. Numerado en monoespaciada, la lista se lee como un inventario
   —que es lo que es— y de paso dice cuantas cosas entran en el precio. */
.incluye li::before {
  counter-increment: incluye;
  content: counter(incluye, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.62em;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--accent-ink);
}

/* El periodo de prueba NO es un dato al pie: es el termino que decide, asi que
   se lee como una frase y no como una anotacion tecnica. Antes iba en la mono
   diminuta de `.hero-dato` y quedaba huerfano al final de la seccion. */
.precio-pie {
  margin-top: 28px;
  padding-top: 22px;
  border-top: 1px solid var(--filete);
  font-size: var(--t-medio);
  font-weight: 600;
  letter-spacing: -0.018em;
}

.precio-pie b {
  color: var(--accent-ink);
  font-weight: 700;
}

/* --- Banda invertida: los limites. El punto de vista de la pagina. -------
   Es el UNICO bloque que invierte, y ahi esta su fuerza: brand.md pide un solo
   momento visual bien ejecutado en vez de diez medianos. Va a sangre porque
   una banda con margenes no invierte nada, parece una tarjeta grande. */
.banda {
  background: var(--banda-bg);
  color: var(--banda-text);
  padding: clamp(60px, 9vw, 116px) 0;
}

.banda .rotulo {
  color: var(--banda-ink);
}
.banda .rotulo::after {
  background: var(--banda-filete);
}
.banda .seccion-nota {
  color: var(--banda-muted);
}

.limites {
  margin-top: var(--aire-bloque);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  column-gap: clamp(30px, 5vw, 76px);
  border-top: 1px solid var(--banda-filete);
}

.limite {
  padding: 26px 0;
  border-bottom: 1px solid var(--banda-filete);
}

.limite h3 {
  font-size: var(--t-medio);
  letter-spacing: -0.022em;
  margin-bottom: 10px;
}

.limite p {
  color: var(--banda-muted);
  font-size: var(--t-secundario);
  max-width: 46ch;
}

.limite p + p {
  margin-top: 8px;
}

/* --- Cierre -------------------------------------------------------------- */

.cierre {
  padding: clamp(60px, 8vw, 110px) 0;
}

.cierre-losa {
  padding: clamp(34px, 5vw, 66px);
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: clamp(26px, 4vw, 56px);
  align-items: center;
}

@media (max-width: 860px) {
  .cierre-losa {
    grid-template-columns: 1fr;
  }
}

.cierre-losa h2 {
  max-width: 20ch;
}

.cierre-contacto {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-end;
  text-align: right;
}

@media (max-width: 860px) {
  .cierre-contacto {
    align-items: flex-start;
    text-align: left;
  }
}

/* --- Un solo boton, con la ventana de opciones -----------------------------
   SIN JS EL PANEL SE VE Y EL DISPARADOR NO EXISTE, y ese orden es la decision:
   este es el UNICO camino de contacto de la pagina, asi que no puede quedarse
   detras de un boton muerto si el script no carga (bloqueado, 404, red). El JS
   pone `js-contacto` en <html>, y esa clase es la que a la vez ENSEÑA el
   disparador y ESCONDE el panel. Es el mismo criterio, y el mismo sentido, que
   `js-reveal`: la clase que oculta la pone el script, nunca el HTML. */

.contacto {
  position: relative;
  /* Bloque y no inline: asi el panel puede medir al menos lo que la columna,
     que es lo que lo mantiene dentro de pantalla en un movil. */
  display: block;
  width: 100%;
}

.contacto-trigger {
  display: none;
}

.js-contacto .contacto-trigger {
  display: inline-flex;
}

/* Sin JS: los dos enlaces, en vertical, debajo del texto. */
.contacto-panel {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--edge);
  border-radius: 16px;
  /* OPACO a proposito, no la losa translucida: un panel que flota sobre otro
     contenido y deja leer lo de debajo se lee como un fallo de pintado, no
     como un material. Y anidar una losa dentro de otra es justo lo que este
     sitio no hace. */
  background: var(--surface-solid);
  overflow: hidden;
}

.js-contacto .contacto-panel {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 20;
  text-align: left;
  /* El ancho es EL DE SU COLUMNA, no un tope calculado sobre el viewport.
     Medido: con `max-width: min(340px, calc(100vw - 34px))` el panel se salia
     25px a 320px, porque ese calculo supone que arranca pegado al borde y
     arranca en x=59 (el padding del envoltorio mas el de la losa). Atado a la
     columna cabe por construccion: la columna ya esta dentro de la losa.

     El tope de 420px es para el otro extremo: por debajo de 860px la rejilla
     del cierre colapsa a UNA columna y el panel se iba a 724px de ancho para
     dos filas de texto. Solo puede encoger, asi que no reabre el desborde. */
  width: 100%;
  max-width: 420px;
  box-shadow: 0 18px 40px rgba(20, 16, 10, 0.22);
  opacity: 0;
  /* `visibility` y no solo `opacity`: con opacity 0 los dos enlaces siguen en
     el orden de tabulacion y se podria aterrizar con el teclado en un panel
     invisible. */
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity 0.2s var(--curva),
    transform 0.2s var(--curva),
    visibility 0.2s;
}

.js-contacto .contacto-panel[data-abierto="true"] {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.contacto-opcion {
  display: block;
  padding: 13px 18px;
  color: var(--text);
  text-decoration: none;
  transition: background 0.2s var(--curva);
}

.contacto-opcion + .contacto-opcion {
  border-top: 1px solid var(--edge);
}

.contacto-opcion:hover {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.contacto-opcion:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: -2px;
}

.contacto-via {
  display: block;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.contacto-dato {
  display: block;
  margin-top: 3px;
  font-size: var(--t-secundario);
  font-weight: 600;
  /* El correo son 33 caracteres y no tiene ningun punto de corte en UAX#14 (ni
     la @ ni los puntos lo son), asi que sin esto desborda su fila en cuanto el
     panel se estrecha. La regla equivalente vivia en la linea suelta de datos
     que este panel sustituye. */
  overflow-wrap: anywhere;
}


/* --- Pie ----------------------------------------------------------------- */

/* Copyright y dos enlaces: es pie de pagina, no cuerpo de lectura. */
.pie {
  padding: 32px 0 40px;
  border-top: 1px solid var(--edge);
  font-size: var(--t-nota);
  color: var(--text-muted);
}

.pie-fila {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  align-items: center;
  justify-content: space-between;
}

.pie a {
  color: var(--text-muted);
  /* Diana de 44px sin mover el texto de sitio. El `min-width` es por el enlace
     «Inicio» de las dos legales, que media 35px de ancho: el padding vertical
     ya daba los 44 de alto, pero la anchura la fija el texto y esa palabra se
     quedaba corta. Los otros tres enlaces del pie ya pasan de 44, asi que no
     los mueve. */
  display: inline-block;
  min-width: 44px;
  text-align: center;
  padding: 12px 0;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.pie a:hover {
  color: var(--text);
}

/* --- Entrada escalonada -------------------------------------------------- */

/* DEFENSIVO: la clase que activa el `opacity: 0` la pone el JS, no el HTML, asi
   que si el script no carga la pagina se ve entera en vez de quedarse en blanco
   para siempre. Medido con el JS desactivado: 0 bloques invisibles. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.72s var(--curva), transform 0.72s var(--curva);
  transition-delay: var(--retardo, 0ms);
}

.js-reveal .reveal.visible {
  opacity: 1;
  transform: none;
}

/* `opacity: 0` NO saca del orden de tabulacion, asi que con el teclado se
   podia aterrizar en un enlace de un bloque aun invisible: el foco existe y no
   se ve. Al recibir el foco, el bloque se revela en el acto. */
.js-reveal .reveal:focus-within {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Solo se apaga el DESPLAZAMIENTO, que es lo intrusivo. La aparicion se queda:
   `prefers-reduced-motion` viene activado de serie en muchos Windows y apagar
   el reveal entero ahi no aporta nada. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .js-reveal .reveal {
    transform: none;
    transition: opacity 0.3s linear;
    transition-delay: 0ms;
  }
  .btn:hover {
    transform: none;
  }
  /* El panel sigue apareciendo (si no, no habria forma de saber que se abrio);
     lo que se apaga es el desplazamiento, que es lo intrusivo. */
  .js-contacto .contacto-panel {
    transform: none;
    transition: opacity 0.2s linear, visibility 0.2s;
  }
}

/* --- Paginas legales ----------------------------------------------------- */

.legal {
  padding: clamp(44px, 6vw, 78px) 0 clamp(40px, 6vw, 72px);
}

.legal h1 {
  font-size: var(--t-grande);
  max-width: 24ch;
}

.legal-cuerpo {
  max-width: 68ch;
}

.legal-cuerpo h2 {
  margin-top: 40px;
  margin-bottom: 12px;
  font-size: var(--t-medio);
  letter-spacing: -0.022em;
  /* `max-width` propio: el de `h2` (24ch) esta calibrado para los 26-34px del
     display de la portada, y aqui la letra son 21px, asi que partia titulos
     cortos en dos lineas usando menos de la mitad del ancho disponible. */
  max-width: 44ch;
}

.legal-cuerpo p {
  margin-bottom: 14px;
  color: var(--text-muted);
}

.legal-cuerpo dl {
  margin: 0 0 14px;
  border-top: 1px solid var(--filete);
}

.legal-cuerpo dt {
  padding-top: 12px;
  font-family: var(--fuente-mono);
  font-size: var(--t-mono);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* `--text-muted` y no `--text-faint`. Medido con el metodo del pixel: sobre
     la aurora desnuda el faint daba 4,25-4,30 en oscuro, POR DEBAJO de AA, y
     estas son las etiquetas de los datos legales obligatorios (NIF, domicilio,
     correo). Es exactamente el motivo que la regla de `.hero-dato` ya tiene
     escrito 450 lineas mas arriba; este era el unico sitio que se quedo con el
     token flojo. Con muted: 6,1 en oscuro. */
  color: var(--text-muted);
}

/* Nota al pie de un bloque legal. Existia en el marcado de aviso-legal.html
   SIN ninguna regla (un gancho huerfano: no se ve, asi que sobrevive a todo y
   hace creer que hay estilo donde no hay ninguno). Ahora dice lo que es: una
   aclaracion, un paso por debajo del cuerpo pero sin bajar de AA.
   Va en --t-secundario y no en --t-nota pese al nombre: son 23 palabras que se
   leen en secuencia, o sea un parrafo. El nombre de la clase describe su papel
   en la pagina, no su tamaño. */
.legal-nota {
  font-size: var(--t-secundario);
  color: var(--text-muted);
}

.legal-cuerpo dd {
  margin: 2px 0 0;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--filete);
}

.legal-fecha {
  margin-top: 14px;
  font-family: var(--fuente-mono);
  font-size: 13px;
  color: var(--text-muted);
}

.legal-cuerpo a {
  color: var(--accent-ink);
}

/* El correo del bloque de datos es el UNICO contenido de su <dd>, o sea que no
   es un enlace dentro de una frase: no le aplica la excepcion de objetivo
   inline y medía 19px de alto. Con el padding llega a los 44 del estandar, y
   solo afecta a ese <dd> (uno por pagina). Los enlaces que SI van dentro de un
   parrafo (el de la AEPD) se quedan como estan, que es lo correcto. */
.legal-cuerpo dd > a:only-child {
  display: inline-block;
  padding: 12px 0;
}

/* --- Modo de alto contraste de Windows ------------------------------------
   `forced-colors` sustituye los COLORES pero no los GRADIENTES, asi que sin
   esto el relleno del CTA sobrevive mientras su texto lo cambia el sistema: el
   boton principal de la pagina puede quedar ilegible. Se le devuelve el par de colores del sistema y se le da un canto,
   que es lo que ahi identifica a un control. */
@media (forced-colors: active) {
  .btn {
    background: ButtonFace;
    color: ButtonText;
    border-color: ButtonText;
    forced-color-adjust: none;
  }
  .btn:focus-visible {
    outline: 2px solid Highlight;
  }
  .losa {
    border-color: CanvasText;
  }
  /* Los filetes estructuran la pagina; en modo forzado un rgba() puede caer a
     transparente y la seccion se queda sin division. */
  .rotulo::after,
  .antes li,
  .mayor-fila,
  .agente,
  .limite,
  .incluye,
  .precio-pie,
  .legal-cuerpo dd {
    border-color: CanvasText;
  }
}
