/* ==========================================================================
   NIEFY · hoja de estilo única de todo el producto.

   Antes eran dos —una para el área privada y otra para la landing— y no podían
   cargarse juntas: solo CUATRO clases chocaban (.btn .lead .sr-only .trust),
   pero ambas repintaban los mismos ELEMENTOS (body, a, button, p, h1..h3) y
   declaraban tokens distintos en `:root`. Concatenarlas sin más habría repintado
   la app con la paleta de la landing, o al revés, según cuál quedara última.

   La solución NO es renombrar 116 clases de la landing: es ACOTARLA. Todas sus
   reglas cuelgan de `body.nf-landing`, tokens incluidos —las propiedades
   personalizadas heredan, así que declararlas en el body alcanza a todo lo que
   hay dentro—. Fuera de la landing esas reglas no existen.

   Lo global a propósito: los @keyframes (una animación no tiene ámbito) y el
   respeto a `prefers-reduced-motion`.

   Orden: 1) el producto (área cliente y backoffice), 2) la landing acotada.
   La landing va DESPUÉS para que, a igual especificidad, gane en su terreno.

   Quien edite la landing debe recordar el ámbito: una regla nueva sin
   `body.nf-landing` delante se aplicaría también al área privada.
   ========================================================================== */

/* =========================================================================
   NIEFY · Sistema de diseño
   Tokens documentados en docs-tech/design-tokens.md. Editar SOLO los tokens de
   marca de abajo; el resto del CSS los consume por alias (no fijar colores a mano).
   Paleta (rediseño «CoinBase», F0/F1): degradado morado→rosa #7C3AED→#EC4899. Radio 16px
   (pastilla en botones). Tema claro/oscuro por [data-theme="dark"]. Editar SOLO los tokens.
   ========================================================================= */

/* Oculta elementos con x-cloak hasta que Alpine inicializa (evita parpadeo del preview). */
[x-cloak] { display: none !important; }

/* Texto solo para lectores de pantalla (accesibilidad). */
.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;
}

/* ═══ LAS TIPOGRAFÍAS DE MARCA, AUTOALOJADAS (20/09) ════════════════════════════════════════════════════

   Courier Prime para los titulares y Nunito para el cuerpo, las dos bajo SIL Open Font License 1.1. Los
   ficheros y el porqué completo, en `public/fonts/LEEME.md`.

   NO SE CARGAN DE GOOGLE, y no es una preferencia técnica: pedirle la fuente a `fonts.gstatic.com` envía la
   IP de cada visitante a un tercero sin contrato del art. 28 (PD-05), en un producto alojado en la UE
   precisamente por RGPD. Hasta hoy la salida era no cargarlas y quedarse con la cadena de respaldo, con el
   resultado de que la web se veía DISTINTA EN CADA MÁQUINA — que es lo que se pidió arreglar. Autoalojarlas
   da la cara exacta sin la petición externa.

   `font-display: swap` a propósito: el texto se lee desde el primer instante con la fuente de respaldo y
   cambia de cara al llegar la buena. La alternativa —esperar a la fuente— deja la página muda unos cientos de
   milisegundos, y aquí lo que hay que leer es un precio y unas condiciones.

   Los `unicode-range` se copian de Google tal cual, y son lo que hace que el navegador NO baje el latino
   extendido si la página no lo usa. Nunito es VARIABLE: un fichero por alfabeto cubre de 400 a 700, y por eso
   su peso se declara como rango. */
@font-face {
    font-family: 'Courier Prime';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/courier-prime-400-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: 'Courier Prime';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/courier-prime-400-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: 'Courier Prime';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/fonts/courier-prime-700-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: 'Courier Prime';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/fonts/courier-prime-700-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: 'Nunito';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/nunito-var-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: 'Nunito';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/nunito-var-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 {
    /* === Tipografía === */
    /* NUNITO DELANTE, y la pila del sistema detrás (20/09).
       La aplicación usaba solo la pila del sistema, o sea que se veía con una letra distinta en cada máquina
       —San Francisco en un Mac, Segoe en Windows, Roboto en Android—: distinto cuerpo, distinta altura de x
       y distinto ancho para el mismo texto. Es la misma familia que ya usaba el cuerpo de la portada, así que
       además deja de haber un salto de tipografía al entrar en el área privada desde la web.
       La pila se queda detrás: es lo que se lee mientras la fuente llega (`font-display: swap`) y lo que
       cubre los alfabetos que no traemos. */
    --font-sans: 'Nunito', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-serif: var(--font-sans); /* alias: titulares con la misma familia, en negrita 700 */

    /* === Degradado de marca (firma «CoinBase») === */
    --grad-a: #7C3AED;        /* violeta */
    --grad-b: #EC4899;        /* rosa/magenta */
    --grad: linear-gradient(135deg, var(--grad-a) 0%, var(--grad-b) 100%);
    --grad-btn: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%); /* botones: casi horizontal, reparte morado→rosa a lo ancho (evita que el rosa se corte en la esquina redondeada) */

    /* === Tokens de color de marca (fuente de verdad) === */
    --primary: #7C3AED;       /* Violeta principal: nav, titulares, enlaces, estados «en curso» */
    --primary-dark: #6D28D9;  /* Violeta oscuro: hover, footer, fin del gradiente del nav */
    --accent: #EC4899;        /* Rosa: acento/CTA secundario, destacados */
    --accent-dark: #DB2777;   /* Rosa oscuro: hover */

    /* === Neutros (tema claro) === */
    --bg: #ffffff;            /* Fondo blanco base (cards) */
    --bg-alt: #EFE6F8;        /* Fondo lila suave (secciones alternas, filas alternas): visible sobre blanco */
    --page: #F2E9F9;          /* Fondo de página lila (más presente para que las cards blancas destaquen) */
    --text: #1E1B2E;          /* Texto principal (tinta índigo) */
    /* Texto secundario. Estaba en #6B6880, que sobre BLANCO daba 5,36:1 —correcto— pero sobre las bandas
       y recuadros lilas (`--bg-alt`, `--page`) caía a 4,43 y 4,54, por DEBAJO del 4,5 que pide AA. No era
       que «se distinguiera poco»: no llegaba al mínimo justo donde más se usa, en las filas alternas y en
       los recuadros de las tarifas. Ahora es 7,0:1 en el peor de los tres fondos. */
    --text-muted: #5A5670;
    --border: #D6C9E9;        /* Bordes de cards e inputs (lila visible, no fantasma) */
    --line: var(--border);    /* Alias: líneas/separadores */

    /* Gradiente del hero = degradado de marca */
    --hero-gradient: var(--grad);

    /* === Alias internos hacia los tokens de marca (compatibilidad de componentes) === */
    --surface: var(--bg);
    --surface-2: var(--bg-alt);
    --ink: var(--text);
    --muted: var(--text-muted);
    --border-strong: #C3B3DC;
    --navy: var(--primary-dark);
    --navy-2: var(--primary);
    --gold: var(--accent);
    --gold-soft: #F9A8D4;     /* rosa claro: subrayado activo del nav */
    --primary-hover: var(--primary-dark);
    --primary-active: #5B21B6;
    --primary-weak: #F1E9FE;  /* violeta muy claro: chips/hover suave */
    --accent-ink: #7C3AED;    /* violeta como TEXTO/enlace: accesible sobre fondo claro (se aclara en dark) */
    --on-primary: #ffffff;

    /* Relleno del botón SECUNDARIO: violeta oscuro de marca (decisión de Antonio, 03/08). Contraste con texto
       blanco 7,10:1, holgadamente AA.
       OJO al elegir otro: este valor es el mismo que `--primary-dark`, o sea el HOVER del primario, y está a
       1,3° de hue del primario. La jerarquía queda por tono (más oscuro), no por color, así que un primario
       con el puntero encima se ve igual que un secundario en reposo. La prueba de navegador de la jerarquía
       compara los dos fondos y sigue en verde —son valores distintos— pero eso ya no demuestra que se
       distingan a simple vista. Si algún día se quiere separar de verdad, hace falta OTRO hue. */
    --secondary: #6D28D9;
    --secondary-hover: #5B21B6;   /* = --primary-active */

    /* === Semánticos (estado; hex modernizados, siguen siendo status, no marca) === */
    --success: #157F3C;       /* verde AA como relleno (texto blanco) */
    --success-ink: #157F3C;   /* verde como TEXTO sobre fondo suave (se aclara en dark) */
    --success-weak: #E7F8F0;
    --warning: #B54708;       /* ámbar oscuro AA como texto/borde sobre fondo claro */
    --warning-ink: #B54708;
    --warning-weak: #FEF3E7;
    --amber-badge: #F5B301;      /* badge ámbar SÓLIDO (reprogramada/solapamiento): ámbar-gold vivo, no marrón */
    --amber-badge-ink: #3A2406;  /* texto oscuro sobre el ámbar vivo (contraste 8:1) */
    --danger: #C4142E;        /* rojo AA: relleno (texto blanco) y texto sobre fondo suave */
    --danger-ink: #C4142E;
    --danger-hover: #A20E26;
    --danger-weak: #FFECEF;
    --info: #7C3AED;          /* «en curso» = violeta (como el kit) */
    --info-weak: #F1E9FE;

    /* === Radios, sombras, anillo de foco === */
    --r-xs: 8px;
    --r-sm: 12px;  /* inputs */
    --r: 16px;     /* cards, botones */
    --r-lg: 20px;
    --r-pill: 999px;  /* badges y pastillas (idioma, chips) */
    --r-btn: 14px;    /* botones: rectángulo redondeado (estilo Coinbase, más fino que la pastilla) */

    /* Altura común de TODO control interactivo de tamaño normal: campos, desplegables y botones.
       Iban por libre —el campo salía a 49px por su relleno y el botón tenía 42 de mínimo—, así que al
       ponerlos en la misma línea los bordes no casaban. Ya había dos parches en esta hoja peleándose con
       el mismo síntoma en sitios distintos. Con un solo número, cualquier control que se añada encaja. */
    --h-control: 48px;
    --shadow-sm: 0 1px 2px rgba(30, 27, 46, .05);
    --shadow: 0 6px 22px rgba(80, 40, 140, .12);  /* sombra tintada de violeta, algo más marcada para separar cards */
    --shadow-lg: 0 12px 32px -8px rgba(80, 40, 140, .28);  /* menús flotantes (select/date), drawer, hover de card */
    --shadow-nav: 0 6px 24px -10px rgba(124, 58, 237, .55);
    /* Sombra estándar de botón: anillo fino (define el borde y lo separa del fondo, sin la costura de un
       border real) + elevación tintada de violeta. Variante hover más marcada. */
    --shadow-btn: 0 0 0 1px rgba(90, 40, 140, .10), 0 4px 14px -3px rgba(124, 58, 237, .42);
    --shadow-btn-hover: 0 0 0 1px rgba(90, 40, 140, .14), 0 8px 22px -3px rgba(124, 58, 237, .5);
    --ring: 0 0 0 3px rgba(124, 58, 237, .5);

    --maxw: 980px;
}

/* === Tema oscuro (índigo profundo) — opt-in por [data-theme="dark"] en <html> === */
:root[data-theme="dark"] {
    --bg: #281846;
    --bg-alt: #362555;
    --page: #140A20;
    --text: #F3EEFB;
    --text-muted: #A99FC4;
    --border: #493860;
    --border-strong: #5C4878;
    --surface: var(--bg);
    --surface-2: var(--bg-alt);
    --ink: var(--text);
    --muted: var(--text-muted);
    --line: var(--border);
    --primary-weak: #2E1D4E;
    --info-weak: #2E1D4E;
    /* En oscuro el violeta de marca se mantiene: sobre índigo el secundario ya se separa del card por el
       propio relleno. Mismas cifras de contraste que en claro con el texto blanco. */
    --secondary: #6D28D9;
    --secondary-hover: #5B21B6;
    --accent-ink: #C4B5FD;   /* violeta claro: enlaces/etiquetas legibles sobre índigo (contraste AA) */
    --success-ink: #6EE7A8;  /* verde claro: texto/borde legible sobre índigo */
    --warning-ink: #FDBA74;
    --danger-ink: #FDA4AF;
    --success-weak: rgba(18, 183, 106, .16);
    --warning-weak: rgba(247, 144, 9, .16);
    --danger-weak: rgba(246, 61, 104, .16);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow: 0 8px 24px rgba(0, 0, 0, .45);
    --shadow-lg: 0 16px 40px -10px rgba(0, 0, 0, .6);
    --ring: 0 0 0 3px rgba(124, 58, 237, .6);
    --shadow-btn: 0 0 0 1px rgba(124, 58, 237, .45), 0 5px 18px -4px rgba(0, 0, 0, .5);
    --shadow-btn-hover: 0 0 0 1px rgba(124, 58, 237, .6), 0 9px 24px -4px rgba(0, 0, 0, .6);
}
/* En oscuro los titulares van en texto claro (el violeta no contrasta sobre índigo). */
:root[data-theme="dark"] h1,
:root[data-theme="dark"] h2,
:root[data-theme="dark"] h3 { color: var(--text); }

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.6;
    color: var(--text);
    background: var(--page);
    -webkit-font-smoothing: antialiased;
    /* Sticky footer: la página ocupa al menos el alto de la ventana y el contenido crece
       para empujar el footer al pie aunque haya poco contenido. */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

h1, h2, h3 {
    font-family: var(--font-sans);
    color: var(--accent-ink);
    font-weight: 700;
    letter-spacing: -.2px;
    margin: 0 0 .5rem;
}
h1 { font-size: 2.7rem; line-height: 1.25; }      /* 43.2px / 54px */
h2 { font-size: 1.9rem; line-height: 1.25; margin-top: .25rem; }  /* 30.4px / 38px */
h3 { font-size: 1.15rem; line-height: 1.25; }     /* 18.4px / 23px */

p { margin: 0 0 .6rem; }

a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

code, pre { font-family: ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; }

/* ----------------------------------------------------------------------- */
/* Navegación                                                              */
/* ----------------------------------------------------------------------- */
.nf-nav {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    padding: .7rem 1.25rem;
    background: linear-gradient(180deg, var(--navy-2), var(--navy));
    box-shadow: var(--shadow-nav);
}
/* Grupo de enlaces: ocupa el resto del ancho en escritorio (la barra .spacer empuja idioma/usuario). */
.nf-nav__links {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    flex: 1;
}
/* Botón hamburguesa: oculto en escritorio, visible bajo el breakpoint. */
.nf-nav__burger {
    display: none;
    align-items: center;
    justify-content: center;
    margin-left: auto;
    width: 44px;
    min-height: 40px;
    padding: 0;
    color: #fff;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: var(--r-sm);
    box-shadow: none;
}
.nf-nav__burger:hover { background: rgba(255, 255, 255, .16); }
.nf-nav a {
    color: rgba(255, 255, 255, .82);
    font-size: .9rem;
    font-weight: 500;
    text-decoration: none;
    padding: .35rem .1rem;
    border-bottom: 2px solid transparent;
    transition: color .15s ease, border-color .15s ease;
}
/* Enlaces del menú con icono + etiqueta */
.nf-nav__links > a,
.nf-nav button.link { display: inline-flex; align-items: center; gap: .45rem; }
.nf-ico { flex: 0 0 auto; opacity: .85; vertical-align: middle; }
.nf-nav__links > a:hover .nf-ico,
.nf-nav__links > a.is-active .nf-ico { opacity: 1; }
.nf-nav a:hover { color: #fff; text-decoration: none; }
.nf-nav a.is-active { color: #fff; border-bottom-color: var(--gold-soft); }
.nf-brand {
    font-family: var(--font-serif);
    font-weight: 700;
    font-size: 1.2rem;
    color: #fff !important;
    letter-spacing: .3px;
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    border: 0 !important;
}
/* El logo va BLANCO sobre las superficies oscuras. Es violeta y rosa, los mismos tonos del degradado de
   la barra, así que encima se perdía: la península se distinguía a duras penas y la palabra «NIEFY»
   desaparecía del todo. `brightness(0)` lo aplana a negro y `invert(1)` lo pasa a blanco, conservando la
   silueta y la transparencia — el mismo tratamiento que ya usaba el pie de la landing. */
.nf-brand-logo { height: 30px; width: auto; display: block; filter: brightness(0) invert(1); }

/* Wordmark bicolor «Paper» + «Bridge» (mismos tonos que el logo). Bicolor solo sobre fondos claros;
   sobre barras moradas (nav pública, footer) y en modo oscuro se pinta en blanco para contraste. */
.nf-nav .spacer { margin-left: auto; }
.nf-nav form { display: inline; margin: 0; }
.nf-nav button.link {
    background: none;
    border: 0;
    color: rgba(255, 255, 255, .82);
    cursor: pointer;
    font: inherit;
    font-size: .9rem;
    padding: 0;
    box-shadow: none;
}
.nf-nav button.link:hover { color: #fff; transform: none; }
.nf-nav .user {
    font-size: .8rem;
    color: rgba(255, 255, 255, .6);
    border-left: 1px solid rgba(255, 255, 255, .14);
    padding-left: 1rem;
}
/* Selector de idioma: pastilla partida por la mitad (ES | EN), mitad activa resaltada. */
.nf-lang {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid rgba(255, 255, 255, .4);
    border-radius: var(--r-sm); /* 8px, cuadrado como el landing (no pastilla redonda) */
    overflow: hidden;
}
.nf-lang a {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .4px;
    padding: .22rem .62rem;
    color: rgba(255, 255, 255, .82);
    border: 0;
    line-height: 1.5;
    transition: background .15s ease, color .15s ease;
}
.nf-lang a + a { border-left: 1px solid rgba(255, 255, 255, .25); }
.nf-lang a:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.nf-lang a.active { background: var(--gold); color: #1b1206; }
.nf-dot {
    background: var(--gold);
    color: #1b1206;
    border-radius: 1rem;
    padding: .05rem .45rem;
    font-size: .7rem;
    font-weight: 700;
    margin-left: .25rem;
}

/* ----------------------------------------------------------------------- */
/* Contenedor y tarjetas                                                   */
/* ----------------------------------------------------------------------- */
.nf-wrap {
    width: 100%;
    max-width: var(--maxw);
    margin: 1.75rem auto 3rem;
    padding: 0 1.1rem;
    flex: 1 0 auto; /* crece para empujar el footer al pie */
}
.nf-wrap > h1:first-child { margin-bottom: 1rem; }

.nf-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 1.8rem;
    margin-bottom: 1.1rem;
    box-shadow: var(--shadow);
    transition: box-shadow .2s ease;
}
.nf-card:hover { box-shadow: var(--shadow-lg); }
.nf-card h2 { margin-top: 0; }

/* Cabecera de tarjeta: título a la izquierda + acción (botón) a la derecha, con separación garantizada
   del contenido siguiente (evita que el botón quede pegado/solapado a la primera fila o al título). */
.nf-cardhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: .6rem;
    margin-bottom: 1rem;
}
.nf-cardhead:last-child { margin-bottom: 0; } /* cuando la cabecera es el único contenido (p. ej. tarjeta de pestañas) */
.nf-cardhead > h1, .nf-cardhead > h2, .nf-cardhead > h3 { margin: 0; }

/* Variantes semánticas de tarjeta (consumen tokens; evitan colores hex inline repetidos). */
.nf-card--success { border-color: var(--success-ink); background: var(--success-weak); }
.nf-card--success > h2 { color: var(--success-ink); }
.nf-card--danger  { border-color: var(--danger-ink); }
.nf-card--danger > h2 { color: var(--danger-ink); }
/* Tarjeta informativa. Iba rellena de `--info-weak` (#F1E9FE) y vive SOBRE la página (#F2E9F9): son casi el
   mismo lila, así que sobre el fondo desaparecía —«no se ven, tienen el mismo color de fondo»—. Es el mismo
   defecto que ya se corrigió en `.nf-alert` (#26) y que esta clase se quedó sin heredar.
   La familia `info` está pensada para ir sobre tarjetas BLANCAS; aquí lo que separa es SER tarjeta (blanca,
   contra la página lila) más un filo de acento que dice que es informativa. */
.nf-card--info {
    background: var(--surface);
    border-color: color-mix(in srgb, var(--primary) 30%, transparent);
    border-left: 4px solid var(--accent-ink);
}

/* Tarjeta de expediente en la landing del cliente (C10): cabecera + pista de siguiente paso + acción. */
.nf-exp-card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.nf-exp-card__ref { font-size: 1.2rem; font-weight: 700; }
.nf-exp-card__hint { display: flex; align-items: flex-start; gap: .45rem; margin: .9rem 0; padding: .65rem .85rem; background: var(--info-weak); border: 1px solid var(--border); border-radius: var(--r-sm); color: var(--accent-ink); font-size: .92rem; }
.nf-exp-card__hint .nf-ico { flex: 0 0 auto; margin-top: .15rem; opacity: 1; }
.nf-exp-empty { text-align: center; }
.nf-exp-empty .nf-ico { color: var(--accent-ink); opacity: .45; margin-bottom: .3rem; }

/* Código QR (MFA) y bloque de códigos de recuperación. */
.nf-qr { max-width: 200px; }
.nf-codes { background: var(--surface-2); padding: .75rem; border-radius: var(--r-sm); font-size: .85rem; margin: .35rem 0 0; overflow-x: auto; }

/* Tarjeta de notificación sin leer: barra azul a la izquierda. */
.nf-card--unread { border-left: 4px solid var(--primary); }

/* Notas internas (EXP-03): aviso ámbar, visible solo para el despacho. */
/* Notas internas (EXP-03, solo despacho): tono violeta suave (marca/interno), no ámbar de aviso. */
.nf-note-card { border-color: color-mix(in srgb, var(--primary) 22%, transparent); background: var(--info-weak); }
.nf-note-card .nf-note-aviso { color: var(--accent-ink); font-size: .8rem; }
.nf-note-item { display: flex; gap: .6rem; align-items: flex-start; border-top: 1px solid color-mix(in srgb, var(--primary) 16%, transparent); padding: .5rem 0; font-size: .9rem; }
.nf-note-item__meta { margin: .2rem 0 0; font-size: .75rem; color: var(--muted); }

/* ----------------------------------------------------------------------- */
/* Formularios                                                             */
/* ----------------------------------------------------------------------- */
label {
    display: block;
    font-size: .82rem;
    font-weight: 700;
    color: var(--ink);
    margin: .85rem 0 .3rem;
    letter-spacing: .2px;
}
input, select, textarea {
    width: 100%;
    min-height: var(--h-control);
    padding: .7rem .9rem;
    font: inherit;
    /* DESPUÉS de `font: inherit`, y no antes: ese atajo REESCRIBE el interlineado con el heredado, así que
       una regla puesta más arriba no llegaba nunca. Con el 1.6 del texto corrido el contenido del campo
       medía 48,7px y se pasaba de la altura común por un pelo — lo justo para que su borde quedara por
       encima del botón de al lado. Ajustado, la altura la decide el token y no el redondeo. */
    line-height: 1.2;
    font-size: .95rem;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    accent-color: var(--primary); /* tinta los controles nativos (select, range, date…) en violeta, no el azul del navegador */
    transition: border-color .15s ease, box-shadow .15s ease;
}
textarea { line-height: 1.55; }
input::placeholder, textarea::placeholder { color: var(--muted); opacity: .7; }
/* Selección de texto en violeta de marca (por defecto sería azul del navegador). */
::selection { background: color-mix(in srgb, var(--primary) 24%, transparent); }
/* Foco por teclado visible y de marca (violeta) en enlaces y elementos sin foco propio. Botones/inputs
   conservan su anillo (box-shadow var(--ring)): su regla más específica gana sobre esta. */
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Estado de campo activo, independiente de si el foco vino de teclado o puntero: solo el color de borde. */
input:focus, select:focus, textarea:focus { border-color: var(--accent-ink); }
/* El ANILLO de foco es solo por teclado (:focus-visible), alto contraste y separado; sustituye al outline por
   defecto en inputs. Con foco por puntero no se dibuja anillo (no se suprime el outline globalmente). */
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; box-shadow: var(--ring); }
/* 20 px y no los 13 del navegador. Medido el 13/09 en el recorrido de compra: la casilla de aceptar las
   condiciones salía a 13×13, por debajo de los 24 que pide la WCAG 2.5.8 como objetivo mínimo, y quien
   recorrió la compra NO LA VIO —creyó que la web estaba rota y dijo «no funciona»—.
   Va en la regla global porque el tamaño lo ponía `min-height: 0` para TODAS: arreglarlo solo en una pantalla
   habría dejado el resto igual de pequeñas y la siguiente queja llegaría desde otra. */
input[type=checkbox], input[type=radio] {
    width: auto;
    min-height: 0;
    inline-size: 20px;
    block-size: 20px;
    accent-color: var(--accent-ink);
    cursor: pointer;
}
/* Opciones del desplegable nativo: evita el AZUL del sistema en la opción resaltada/seleccionada donde el
   navegador lo permite (Chromium/Firefox en Linux/Windows). En macOS el popup es 100% nativo y no es estilable
   por CSS (ahí solo un desplegable propio lo cambiaría). */
select option { background: var(--surface); color: var(--ink); }
select option:checked { background: var(--primary-weak); color: var(--accent-ink); font-weight: 600; }

/* Desplegable propio <x-select> (sustituye al <select> nativo para tokenizar el popup, sin azul del SO). */
.nf-select { position: relative; width: 100%; }
.nf-select__native { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; }
.nf-select__btn {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    font: inherit; font-size: .95rem; font-weight: 400; letter-spacing: 0; text-align: left;
    color: var(--ink); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm);
    padding: .7rem .9rem; min-height: var(--h-control); line-height: 1.2;
    box-shadow: none; cursor: pointer;
}
.nf-select__btn:hover { background: var(--surface); border-color: var(--border-strong); transform: none; filter: none; }
.nf-select__btn:active { background: var(--surface); transform: none; filter: none; }
.nf-select__btn:focus-visible { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
.nf-select__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Móvil = prefijo + número. El prefijo iba a un 44% FIJO de la celda y el número se quedaba con lo que
   sobrara: en la rejilla de tres columnas eran 98 px y el placeholder salía cortado («Número d»). Ahora los
   dos tienen un ancho base propio y, si no caben, el número baja de línea en vez de estrujarse. */
.nf-tel { display: flex; gap: .5rem; flex-wrap: wrap; }
.nf-tel > .nf-select { flex: 0 1 6.5rem; min-width: 0; }
.nf-tel > input { flex: 1 1 8rem; min-width: 0; }
.nf-select__chev { flex: 0 0 auto; color: var(--muted); transition: transform .15s ease; }
.nf-select__chev.is-open { transform: rotate(180deg); }
/* El menú ya no es la lista: es el contenedor del BUSCADOR + la lista. El scroll baja a la lista para que el
   campo de búsqueda no se vaya hacia arriba al recorrer las opciones, que es justo cuando hace falta. */
.nf-select__menu {
    position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 4px);
    margin: 0; padding: 0;
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg); overflow: hidden;
}
.nf-select__lista { margin: 0; padding: .3rem; list-style: none; max-height: 300px; overflow-y: auto; }
.nf-select__buscar {
    display: flex; align-items: center; gap: .45rem;
    padding: .5rem .6rem; border-bottom: 1px solid var(--border);
    color: var(--ink-soft);
}
.nf-select__buscar input {
    flex: 1; min-width: 0; border: 0; background: transparent; padding: 0;
    font: inherit; font-size: .92rem; color: var(--ink); outline: none;
}
.nf-select__buscar input::placeholder { color: var(--ink-soft); }
/* No es una opción: ni se elige ni se resalta al pasar por encima. */
.nf-select__vacio { color: var(--ink-soft); font-style: italic; cursor: default; }
.nf-select__menu li { padding: .5rem .7rem; border-radius: var(--r-xs); cursor: pointer; font-size: .92rem; color: var(--ink); }
.nf-select__menu li.is-focus { background: var(--primary-weak); }
.nf-select__menu li.is-active { color: var(--accent-ink); font-weight: 600; }
/* Variante compacta / en línea (antes .nf-select-sm sobre el <select>; ahora sobre el envoltorio). */
.nf-select.nf-select-sm { width: auto; }
.nf-select.nf-select-sm .nf-select__btn { padding: .35rem .55rem; font-size: .82rem; min-height: 32px; }

/* Selector de fecha propio <x-date> (calendario Alpine; sin datepicker nativo del SO). */
.nf-date { position: relative; width: 100%; }
/* Escribir la fecha y elegir mes/año: sin esto el calendario solo avanzaba de mes en mes y una fecha de
   nacimiento quedaba a cientos de clics. */
/* El popover son TRES zonas —escribir · navegar · calendario— y se separan de verdad: escribir y elegir en
   el calendario son dos caminos distintos para lo mismo, y amontonarlos hacía que el campo de texto pareciera
   parte de la barra de mes y año. Cada zona pone su propio padding (el contenedor lo deja a 0) y la primera
   va sobre fondo tenue con un filo debajo, que es lo que las separa sin meter una línea suelta. */
.nf-date__type { padding: .65rem .75rem; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.nf-date__typelbl { display: block; margin-bottom: .3rem; font-size: .68rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.nf-date__txt { width: 100%; min-height: 36px; font-variant-numeric: tabular-nums; }
.nf-date__sel { display: flex; gap: .35rem; align-items: center; flex: 1; min-width: 0; justify-content: center; }
.nf-date__mes { flex: 1 1 auto; min-width: 0; }
.nf-date__anio { flex: 0 0 4.6rem; text-align: center; }
.nf-date__mes, .nf-date__anio { padding: .3rem .45rem; font-size: .86rem; min-height: 34px; border-radius: var(--r-xs); border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-weight: 600; }
.nf-date__mes:focus, .nf-date__anio:focus, .nf-date__txt:focus { outline: none; box-shadow: var(--ring); border-color: var(--primary); }
/* Dirección de envío del poder en la pantalla de documentos: es un dato para COPIAR en un sobre, así que va
   en bloque, con su etiqueta y sin justificar. */
.nf-buzon { margin: .5rem 0 .7rem; padding: .55rem .7rem; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-xs); }
.nf-buzon__lbl { display: block; font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: .2rem; }
.nf-buzon__dir { font-style: normal; white-space: pre-line; font-size: .9rem; color: var(--ink); }
/* LAS CLÁUSULAS DESTACADAS DEL PASO DE CONDICIONES, en una sola lista (`.nf-claves`).

   Antes eran tres bloques con su borde de color, su titular y su párrafo: lo fundamental en ámbar, los
   requisitos en ámbar y el desistimiento en azul. Tres barras de colores seguidas no jerarquizan nada —se
   leen como tres avisos— y entre titulares, entradillas y pies gastaban seis líneas en presentar seis.

   Sin caja ni borde: la tarjeta que las envuelve ya es el documento. Lo único que separa una cláusula de la
   siguiente es una línea fina, que es lo que las hace contables de un vistazo sin numerarlas. */
.nf-claves { list-style: none; margin: .5rem 0 1.4rem; padding: 0; }
.nf-claves li { display: flex; align-items: flex-start; gap: .6rem; padding: .6rem 0; border-top: 1px solid var(--line); line-height: 1.45; }
.nf-claves li:last-child { border-bottom: 1px solid var(--line); }
.nf-claves > li > .nf-ico { flex: 0 0 auto; margin-top: .15rem; color: var(--muted); }
/* La media línea de detalle, debajo y en gris. Solo la lleva la del dinero: las demás se leen enteras en su
   titular, y el detalle de todas está en el clausulado, a un clic. */
.nf-claves .meta { display: block; margin-top: .15rem; }
/* Comparación del paso «Notario»: lo que cuesta y tarda por cada vía. En rejilla y no en tabla porque son
   dos o tres pares y una <table> traería cabeceras que aquí no dicen nada. */
.nf-compara { display: flex; flex-wrap: wrap; gap: .5rem .9rem; margin: .3rem 0 .7rem; }
.nf-compara > div { flex: 1 1 10rem; padding: .45rem .6rem; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-xs); }
.nf-compara dt { font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.nf-compara dd { margin: .1rem 0 0; font-size: .95rem; color: var(--ink); }
.nf-compara dd .meta { display: block; font-size: .8rem; }
.nf-date__native { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; }
.nf-date__btn { justify-content: space-between; }
.nf-date__ico { flex: 0 0 auto; color: var(--muted); }
.nf-date__ph { color: var(--muted); opacity: .75; }
.nf-date__pop {
    position: absolute; z-index: 40; top: calc(100% + 4px); left: 0;
    width: 288px; max-width: calc(100vw - 2rem);
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg); padding: 0; overflow: hidden;
}
.nf-date__bar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .6rem .75rem .4rem; }
.nf-date__title { font-weight: 700; font-size: .9rem; color: var(--ink); text-transform: capitalize; }
.nf-date__nav {
    display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; min-height: 0;
    padding: 0; background: transparent; color: var(--muted); border: 1px solid var(--border); border-radius: var(--r-xs); box-shadow: none;
}
.nf-date__nav:hover { background: var(--primary-weak); color: var(--primary); border-color: var(--border-strong); transform: none; filter: none; }
.nf-date__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; padding: 0 .75rem .75rem; }
.nf-date__dow { text-align: center; font-size: .64rem; font-weight: 700; text-transform: uppercase; color: var(--muted); padding: .2rem 0; }
.nf-date__day {
    aspect-ratio: 1; min-height: 0; padding: 0; font-size: .82rem; font-weight: 500;
    background: transparent; color: var(--ink); border: 0; border-radius: var(--r-xs); box-shadow: none; cursor: pointer;
}
.nf-date__day:hover { background: var(--primary-weak); color: var(--primary); transform: none; filter: none; }
.nf-date__day.is-today { box-shadow: inset 0 0 0 1.5px var(--border-strong); }
.nf-date__day.is-sel { background: var(--grad); color: #fff; font-weight: 700; }
.nf-date__day.is-sel:hover { background: var(--grad); color: #fff; filter: brightness(1.05); }
.nf-date__day.is-blank { visibility: hidden; pointer-events: none; }
.nf-date__time { display: flex; align-items: center; justify-content: center; gap: .3rem; padding: .6rem .75rem .75rem; border-top: 1px solid var(--border); }
.nf-date__t { width: 3.4rem; text-align: center; padding: .35rem; }
.nf-date__colon { font-weight: 700; color: var(--muted); }

/* Panel de copia programada (backups): estado prominente + formulario de configuración. */
.nf-sched__head { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.nf-sched__icon { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; flex: 0 0 auto; border-radius: 50%; background: var(--surface-2); color: var(--muted); }
.nf-sched--on .nf-sched__icon { background: var(--success-weak); color: var(--success-ink); }
.nf-sched__txt { flex: 1 1 240px; min-width: 0; }
.nf-sched__txt strong { font-size: 1.02rem; }
.nf-sched__cfgbtn { flex: 0 0 auto; }
.nf-sched--on { border-color: color-mix(in srgb, var(--success) 35%, transparent); border-left: 4px solid var(--success); }
.nf-sched__form { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); }
/* Interruptor (toggle) accesible; el estado sigue al checkbox real (:has), instantáneo. */
.nf-switch { display: inline-flex; align-items: center; gap: .55rem; cursor: pointer; font-weight: 600; }
.nf-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.nf-switch__track { position: relative; width: 40px; height: 22px; border-radius: 999px; background: var(--border-strong); transition: background .15s ease; flex: 0 0 auto; }
.nf-switch__knob { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: var(--shadow-sm); transition: transform .15s ease; }
.nf-switch:has(input:checked) .nf-switch__track { background: var(--primary); }
.nf-switch:has(input:checked) .nf-switch__knob { transform: translateX(18px); }
.nf-switch input:focus-visible + .nf-switch__track { box-shadow: var(--ring); }

/* Selector de archivo: el botón nativo es feo y no pega; lo reestilizamos al sistema (botón primario). */
input[type=file] {
    padding: .35rem .5rem;
    background: var(--surface-2);
    color: var(--muted);
    font-size: .9rem;
    cursor: pointer;
}
input[type=file]::file-selector-button {
    font: inherit;
    font-weight: 600;
    font-size: .88rem;
    margin: 0 .8rem 0 0;
    padding: .5rem 1rem;
    border: 0;
    border-radius: 6px;
    background: var(--primary);
    color: #fff;
    cursor: pointer;
    transition: background .15s ease;
}
input[type=file]::file-selector-button:hover { background: var(--accent); color: var(--primary-dark); }
input[type=file]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Radios en tarjeta (p. ej. alcance de la copia de seguridad). */
.nf-radios { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .35rem; }
.nf-radio { display: inline-flex; align-items: center; gap: .45rem; padding: .5rem .85rem; border: 1px solid var(--border);
    border-radius: var(--r-sm); background: var(--surface); cursor: pointer; font-weight: 600; font-size: .9rem; }
.nf-radio input { width: auto; margin: 0; accent-color: var(--accent-ink); }
/* Resaltado activo: SOLO el radio realmente marcado (instantáneo). No se usa la clase .is-active del servidor
   porque con wire:model diferido queda obsoleta y resaltaría dos a la vez (el viejo no se desmarcaba). */
.nf-radio:has(input:checked) { border-color: var(--accent-ink); background: var(--primary-weak); color: var(--accent-ink); }
/* Fieldset sin marco para agrupar radios con su título (legend con apariencia de etiqueta). */
.nf-fieldset-plain { border: 0; padding: 0; margin: 0; min-width: 0; }
.nf-fieldset-plain > legend { display: block; font-size: .82rem; font-weight: 700; color: var(--ink); margin: 0 0 .3rem; padding: 0; letter-spacing: .2px; }

/* Campo apilado etiqueta+control (formularios de backoffice: gestión de consulados, etc.). */
.nf-labelfield { display: flex; flex-direction: column; gap: .3rem; }
.nf-labelfield > span { font-size: .82rem; font-weight: 700; color: var(--ink); letter-spacing: .2px; }

/* Lista clave/valor para fichas (datos de contacto del consulado). */
.nf-datalist { display: grid; gap: .5rem; margin: 0; }
.nf-datalist > div { display: grid; grid-template-columns: minmax(110px, 170px) 1fr; gap: .1rem 1rem; }
.nf-datalist dt { margin: 0; font-size: .82rem; font-weight: 700; color: var(--muted); }
.nf-datalist dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 640px) { .nf-datalist > div { grid-template-columns: 1fr; } }

/* Acción destructiva (botón de borrado): tinta de peligro sin relleno. */
/* `.nf-danger` (texto rojo sobre botón claro) se retiró en B-4.4: sus dos únicos usos iban acompañados de
   `.btn-ghost`, que declara `color:#fff` más abajo en esta misma hoja y por orden de cascada la ganaba
   SIEMPRE. O sea que el rojo no llegó a pintarse nunca, y esos dos borrados se veían como una acción normal.
   Ahora todo lo destructivo usa `.nf-confirm__danger` (relleno rojo), que ya era el criterio en 10 de 12. */

/* ----------------------------------------------------------------------- */
/* Botones                                                                 */
/* ----------------------------------------------------------------------- */
button, .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    background: var(--grad-btn);
    color: #fff;
    border: 0;
    border-radius: var(--r-btn);
    padding: .72rem 1.5rem;
    font-family: var(--font-sans);
    font-size: .92rem;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: .2px;
    cursor: pointer;
    min-height: var(--h-control);
    box-shadow: var(--shadow-btn);
    transition: background .15s ease, transform .06s ease, box-shadow .15s ease, opacity .15s ease;
}
button, .btn, .nf-back { text-decoration: none; }
button:hover, .btn:hover, .nf-back:hover { text-decoration: none; }
/* Micro-interacción del landing: el botón se eleva 1px al pasar el ratón. */
button:hover, .btn:hover, .nf-back:hover { transform: translateY(-1px); }
button:hover, .btn:hover { background: var(--grad-btn); filter: brightness(1.04); box-shadow: var(--shadow-btn-hover); }
/* Iconos chevron de los botones de navegación: opacidad plena y ajuste óptico de 1px
   para centrarlos con el texto (que no tiene descendentes). */
.btn .nf-ico, .nf-back .nf-ico { opacity: 1; transform: translateY(1px); }
button:active, .btn:active { background: var(--grad-btn); filter: brightness(.95); transform: translateY(1px); box-shadow: var(--shadow-btn); }
button:focus-visible, .btn:focus-visible { outline: none; box-shadow: var(--ring); }
button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; }

/* Botones con fondo semántico (success/danger/slate) conservan texto blanco. */
button[style*="--success"], button[style*="--danger"],
button[style*="#dc2626"], button[style*="#64748b"], button[style*="#2563eb"],
.nf-doc__accept .btn, .nf-doc__rejrow .btn, .nf-confirm__danger { color: #fff; }

/* Botones que sustituyen el degradado por un fondo sólido: sombra neutra, no la tintada de violeta. */
button[style*="--success"], button[style*="--danger"],
button[style*="#dc2626"], button[style*="#64748b"], button[style*="#2563eb"],
.nf-doc__accept .btn, .nf-doc__rejrow .btn, .nf-confirm__danger { box-shadow: var(--shadow-sm); }
.btn-outline { box-shadow: none; }

/* Botón azul (acción de navegación: abrir / volver) */
.btn-primary { background: var(--primary); color: #fff; border-color: transparent; }
.btn-primary:hover { background: var(--primary-dark); color: #fff; }

/* Enlace "volver atrás" con apariencia de botón azul */
.nf-back {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .42rem .9rem;
    min-height: 36px;
    background: var(--primary);
    color: #fff;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    font-size: .85rem;
    font-weight: 600;
    box-shadow: var(--shadow-sm);
}
.nf-back:hover { background: var(--primary-dark); color: #fff; text-decoration: none; }

/* Avisos / flash unificados (semánticos, con icono) */
.nf-alert {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .8rem 1rem;
    border: 1px solid var(--border);
    border-left-width: 4px;
    border-radius: var(--r-sm);
    margin-bottom: 1.1rem;
    font-size: .92rem;
}
.nf-alert__icon { flex: 0 0 auto; margin-top: .1rem; }
.nf-alert__body { flex: 1; min-width: 0; }
.nf-alert--success { background: var(--success-weak); border-color: color-mix(in srgb, var(--success) 28%, transparent); border-left-color: var(--success-ink); color: var(--success-ink); }
.nf-alert--danger  { background: var(--danger-weak);  border-color: color-mix(in srgb, var(--danger) 28%, transparent);  border-left-color: var(--danger-ink);  color: var(--danger-ink); }
.nf-alert--warning { background: var(--warning-weak); border-color: color-mix(in srgb, var(--warning) 28%, transparent); border-left-color: var(--warning-ink); color: var(--warning-ink); }
.nf-alert--info    { background: var(--info-weak);    border-color: color-mix(in srgb, var(--primary) 22%, transparent); border-left-color: var(--accent-ink); color: var(--accent-ink); }
.nf-alert strong { color: inherit; }
/* Igual que `strong`: dentro de un aviso, el texto secundario toma la TINTA DEL AVISO. `.meta` trae el gris
   violáceo de la app y, sobre el ámbar de un `warning`, cantaba como de otra pantalla.
   Y a plena opacidad: atenuarlo al 82 % lo dejaba en 3,66:1 sobre el ámbar claro, por debajo de AA. La
   jerarquía ya la dan el tamaño (.82rem) y el peso frente al titular; oscurecerlo encima solo costaba
   legibilidad. Lo caza `tests/browser/specs/aviso-altas.spec.js`. */
.nf-alert .meta { color: inherit; }
/* Aviso con acción: el cuerpo dice qué pasa y el botón, qué hacer. El botón se centra respecto al bloque de
   texto (que tiene dos líneas) en vez de alinearse arriba como el icono. En estrecho baja debajo y ocupa el
   ancho, porque estrujado entre el texto y el borde no se acierta a pulsarlo.

   OJO con el color: `--info-weak` (#F1E9FE) y `--page` (#F2E9F9) son casi el MISMO lila, así que un aviso
   `info` sobre el fondo de página desaparece — está pensado para ir sobre tarjetas blancas. Sobre la página
   hay que usar ámbar (`warning`), que es la única familia cálida de un sistema morado. Ver el titular abajo. */
/* Con la MISMA sombra que las tarjetas: el fondo lila de la página existe para que lo elevado destaque, y
   este aviso tiene que jugar en esa liga y no quedarse plano contra ella. */
.nf-alert--accion { flex-wrap: wrap; box-shadow: var(--shadow); }
.nf-alert__accion { flex: 0 0 auto; align-self: center; margin-left: auto; }
/* El recuento es lo que se escanea: se lee antes que la explicación, así que pesa más que el cuerpo. */
.nf-alert__titular { display: block; font-size: 1.02rem; line-height: 1.3; }
@media (max-width: 560px) {
    .nf-alert__accion { margin-left: 0; width: 100%; }
    .nf-alert__accion .btn { width: 100%; justify-content: center; }
}

/* Tarjeta del NIE emitido — el hito de éxito que el cliente espera.
   Lleva el DEGRADADO DE MARCA, no el verde de «operación correcta»: el verde es el color con el que la app
   dice «esto ha ido bien» en avisos y validaciones, y este no es un aviso de sistema, es el final del
   recorrido y lo que el cliente ha venido a comprar. Reutiliza el mismo idioma que `.nf-pricecard.featured`
   —relleno de la superficie sobre el borde y el degradado asomando por el filo—, que ya es como esta hoja
   destaca lo importante. */
.nf-nie {
    border: 2px solid transparent;
    background: linear-gradient(var(--surface), var(--surface)) padding-box, var(--grad) border-box;
}
.nf-nie__head { display: flex; align-items: center; gap: .5rem; color: var(--primary); }
.nf-nie__head h2 { margin: 0; color: var(--primary); }
.nf-nie__num {
    font-size: 2rem; font-weight: 800; letter-spacing: .08em; color: var(--primary);
    margin: .5rem 0 .3rem; font-variant-numeric: tabular-nums;
}
/* El número en degradado. Va detrás de un @supports porque recortar el fondo al texto exige `color:
   transparent`: donde no se soporte, el número quedaría INVISIBLE —y es el dato por el que existe la
   pantalla—. Sin el @supports, el fallo no es que se vea feo, es que no se ve. `width: fit-content` para que
   el morado→rosa se reparta sobre las nueve cifras y no sobre el ancho entero de la tarjeta. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
    .nf-nie__num {
        width: fit-content;
        background: var(--grad-btn);
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
    }
}

/* Botón secundario (slate, acciones de menor jerarquía) */
.btn-secondary { background: #5B5670; color: #fff; border-color: transparent; }
.btn-secondary:hover { background: #494458; color: #fff; }

/* Botón secundario sobre fondo oscuro (hero/footer): contorno blanco. */
.btn-outline {
    background: transparent;
    color: #fff;
    border: 2px solid rgba(255, 255, 255, .7);
    border-radius: var(--r);
}
.btn-outline:hover { background: rgba(255, 255, 255, .12); }

/* ----------------------------------------------------------------------- */
/* Insignias (estados, etiquetas)                                          */
/* ----------------------------------------------------------------------- */
.nf-badge {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .2rem .6rem;
    border-radius: 1rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .2px;
    background: var(--surface-2);
    color: var(--ink);
    border: 1px solid var(--border);
}
/* Variantes semánticas por estado (color() de la máquina de estados). */
.nf-badge--gray  { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); }
.nf-badge--slate { background: var(--border); color: var(--text); border-color: var(--border-strong); }
.nf-badge--blue  { background: var(--primary); color: #fff; border-color: transparent; }
.nf-badge--amber { background: var(--amber-badge); color: var(--amber-badge-ink); border-color: transparent; font-weight: 700; }
/* Distintivo que vive EN UNA FILA DE BOTONES, ocupando el sitio de uno: la misma altura que `.btn-sm` para
   que el borde de abajo cuadre. Sin esto la píldora queda 12 px más baja y la fila se lee descuadrada, que
   es justo lo que delata que un elemento se añadió después. No cambia color ni forma: solo la caja. */
.nf-badge--accion { min-height: 36px; padding-inline: .85rem; }
/* Botón × dentro de un badge (p. ej. eliminar grupo de firma) y select compacto para acciones en línea. */
.nf-badge__x { background: none; border: 0; cursor: pointer; color: inherit; font-size: 1.05em; line-height: 1; padding: 0 0 0 .25rem; opacity: .7; }
.nf-badge__x:hover { opacity: 1; }
.nf-badge--green { background: var(--success); color: #fff; border-color: transparent; font-weight: 700; }

/* Grupos de firma (poderes) del caso familiar (H-1): chips legibles y manejables, en vez de badges diminutos.
   Cada chip muestra el poder, sus firmantes y un botón de borrar con superficie de clic decente (≥28px). */
.nf-firma-grupos { display: flex; flex-wrap: wrap; gap: .5rem; align-items: flex-start; }
.nf-firma-grupo {
    display: flex; flex-direction: column; gap: .3rem;
    padding: .45rem .55rem .5rem .7rem;
    border-radius: .7rem;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    min-width: 160px; max-width: 260px;
}
.nf-firma-grupo__head { display: flex; align-items: center; gap: .5rem; }
.nf-firma-grupo__label { display: inline-flex; align-items: center; gap: .35rem; font-weight: 700; color: var(--ink); font-size: .9rem; }
.nf-firma-grupo__count { color: var(--text); font-size: .78rem; white-space: nowrap; }
.nf-firma-grupo__x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; flex: 0 0 auto; margin-left: auto;
    border-radius: .5rem; border: 1px solid var(--border);
    background: var(--surface); color: var(--text);
    cursor: pointer; line-height: 1; transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.nf-firma-grupo__x:hover { background: var(--danger); color: #fff; border-color: transparent; }
.nf-firma-grupo__x:focus-visible { box-shadow: var(--ring); outline: none; }
/* Lista de firmantes dentro del chip: nombres uno por línea, legibles. */
.nf-firma-grupo__firmantes { margin: 0; padding: 0 0 0 1.3rem; font-size: .82rem; color: var(--text); line-height: 1.4; }
.nf-firma-grupo__firmantes li { margin: .05rem 0; }
.nf-firma-grupo__firmantes--vacio { list-style: none; padding-left: 0; font-style: italic; opacity: .75; }
.nf-firma-grupo--alerta { background: var(--amber-badge); color: var(--amber-badge-ink); border-color: var(--amber-badge-ink); }
.nf-firma-grupo--alerta .nf-firma-grupo__label,
.nf-firma-grupo--alerta .nf-firma-grupo__count,
.nf-firma-grupo--alerta .nf-firma-grupo__firmantes { color: var(--amber-badge-ink); }
.nf-firma-grupo--alerta .nf-firma-grupo__x { background: rgba(0,0,0,.06); border-color: transparent; color: var(--amber-badge-ink); }

/* Registro de accesos a documentos (DOC-09): rejilla para alinear los badges en columna y legibilidad. */
.nf-acceso {
    display: grid;
    grid-template-columns: minmax(120px, 1.4fr) 124px minmax(130px, 1.3fr) auto;
    gap: .45rem .9rem; align-items: center;
    padding: .6rem 0; border-top: 1px solid var(--border);
}
.nf-acceso:first-of-type { border-top: 0; }
.nf-acceso__doc { font-weight: 600; color: var(--ink); }
.nf-acceso__user { color: var(--ink); font-size: .9rem; overflow-wrap: anywhere; }
.nf-acceso__fecha { text-align: right; white-space: nowrap; }
.nf-acceso .nf-badge { width: 100%; justify-content: center; }
@media (max-width: 640px) {
    .nf-acceso { grid-template-columns: 1fr auto; gap: .2rem .6rem; padding: .7rem 0; }
    .nf-acceso__accion { grid-column: 2; grid-row: 1; }
    .nf-acceso__user { grid-column: 1 / -1; }
    .nf-acceso__fecha { grid-column: 1 / -1; text-align: left; }
    .nf-acceso .nf-badge { width: auto; }
}
.nf-badge--red   { background: var(--danger); color: #fff; border-color: transparent; font-weight: 700; }

/* Semáforo de SLA (EXP-06). */
.nf-sla {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: .15rem;
    vertical-align: middle;
}
.nf-sla--verde { background: #22c55e; }
.nf-sla--ambar { background: #f59e0b; }
.nf-sla--rojo  { background: #ef4444; box-shadow: 0 0 0 3px rgba(239, 68, 68, .18); }
.nf-sla--sin_sla { background: var(--border-strong); }

/* Visor de documentos (modal con iframe) */
.nf-modal { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 1.2rem; background: rgba(23, 11, 38, .55); }
.nf-modal-box { background: #fff; border-radius: var(--r); width: min(960px, 100%); height: min(86vh, 100%); display: flex; flex-direction: column; overflow: hidden; box-shadow: var(--shadow); }
.nf-modal-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: .65rem .9rem .65rem 1.1rem; border-bottom: 1px solid var(--border); }
.nf-modal-head strong { font-family: var(--font-serif); }
.nf-modal-box iframe { flex: 1; width: 100%; border: 0; background: var(--surface-2); }
/* Documentos que son imagen (p. ej. pasaporte no normalizado): se ajustan al visor sin desbordar. */
.nf-modal-box img.nf-modal-media { flex: 1; width: 100%; min-height: 0; object-fit: contain; background: var(--surface-2); }
.nf-modal-close { background: var(--surface-2); color: var(--ink); border: 1px solid var(--border-strong); min-height: 34px; padding: .35rem .8rem; font-size: .85rem; }
.nf-modal-close:hover { background: var(--border); }

/* Modal de FICHA: el visor de documentos quiere alto fijo y fondo blanco; una ficha de datos quiere crecer lo
   que ocupe y respetar el tema. Misma caja exterior, distinto interior. */
.nf-modal-box--ficha {
    background: var(--surface);
    color: var(--ink);
    height: auto;
    max-height: min(86vh, 100%);
    width: min(680px, 100%);
}
.nf-modal-box--ficha .nf-modal-cuerpo { padding: 1rem 1.1rem 1.2rem; overflow-y: auto; }

/* EL NOMBRE DEL CLIENTE en las filas del backoffice.

   Iba en `meta`: mismo tamaño y mismo gris que los días de SLA o la sede, así que el dato por el que de
   verdad se busca una fila —«el expediente de Fulano»— pesaba lo mismo que el relleno. La referencia sirve
   para CITAR un expediente; el nombre, para ENCONTRARLO, y es lo que el ojo recorre.

   Tinta normal y algo más de cuerpo, no negrita: en una fila que ya lleva estado, nivel y a veces urgencia,
   un cuarto elemento en negrita volvería a dejarlo todo al mismo nivel, que es el problema de partida. */
.nf-row__nombre { font-size: .95rem; color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── EL CUESTIONARIO, DESPUÉS DEL PASAPORTE (20/09, V-08) ───────────────────────────────────────────────

   Desde que el pasaporte va primero, esta pantalla deja de ser un dictado y pasa a ser una COMPROBACIÓN: lo
   que dice la MRZ llega puesto y lo que falta se señala. Dos marcas, y dicen cosas distintas a propósito.

   EL HUECO: un halo del color de marca alrededor del bloque entero —etiqueta incluida—, porque un borde de
   color alrededor de una casilla sin su rótulo no dice cuál falta. Halo y no borde rojo: no es un error, es
   un sitio donde todavía no has escrito, y teñir de error algo que nadie ha hecho mal es regañar por
   adelantado. Se apaga al escribir.

   LO LEÍDO: un filo lateral discreto, sin halo. Aquí no hay nada que hacer —está puesto— y lo único que se
   quiere decir es de dónde salió, para que el cliente sepa qué está comprobando y qué ha escrito él. */
.nf-hueco {
    border-radius: var(--r-sm, 10px);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent);
    /* El halo se pinta FUERA del bloque, así que sin este aire se solapa con el campo de al lado en la
       rejilla de dos columnas. */
    margin: -.35rem; padding: .35rem;
    transition: box-shadow .25s ease;
}
.nf-leido { border-left: 2px solid color-mix(in srgb, var(--primary) 45%, transparent); padding-left: .55rem; }

/* Y en movimiento reducido, sin transición: el halo aparece y desaparece, que es lo que informa. */
@media (prefers-reduced-motion: reduce) {
    .nf-hueco { transition: none; }
}

/* Botón "ver" discreto en filas de documento */
a.nf-ver { cursor: pointer; }

/* Servicio contratado: banda que acompaña al stepper durante todo el alta. Es la decisión que el cliente ya
   ha tomado, así que se lee como una elección confirmada (tinta y filo de marca) y no como un párrafo más.
   Ocupa el 100 % en vez de un ancho fijo: así casa con la card de cada paso, que no siempre mide igual. */
.nf-servicio {
    width: 100%; margin: 0 0 .9rem;
    border: 1px solid var(--border); border-left: 4px solid transparent; border-radius: var(--r-sm);
    /* Doble fondo: el relleno blanco (el mismo `--surface` de las cards, así el tema oscuro sigue valiendo)
       pinta sobre el borde, y el degradado de marca asoma por el filo izquierdo. */
    background:
        linear-gradient(var(--surface), var(--surface)) padding-box,
        var(--grad) border-box;
}
/* La cabecera es el disparador del desplegable: un <button> real (teclado y lectores de pantalla de serie),
   al que hay que quitarle los estilos de botón de la app. */
.nf-servicio__head {
    display: flex; align-items: center; gap: .7rem; width: 100%;
    padding: .7rem .95rem;
    background: none; border: 0; border-radius: var(--r-sm);
    font: inherit; color: inherit; text-align: left; cursor: pointer;
    box-shadow: none;
}
.nf-servicio__head:hover { background: var(--primary-weak); }
.nf-servicio__head:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
.nf-servicio__chevron { flex: none; display: inline-flex; color: var(--muted); transition: transform .18s ease; }
.nf-servicio__chevron.is-open { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .nf-servicio__chevron { transition: none; } }
.nf-servicio__ico { flex: none; display: inline-flex; color: var(--accent-ink); }

/* Cuerpo desplegado: lo que incluye el nivel. */
.nf-servicio__cuerpo { padding: 0 .95rem .8rem; border-top: 1px solid var(--border); margin-top: -1px; padding-top: .75rem; }
.nf-servicio__lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.nf-servicio__lista li { display: flex; align-items: flex-start; gap: .45rem; font-size: .92rem; color: var(--text); }
.nf-servicio__lista li svg { flex: none; margin-top: .18rem; color: var(--success-ink, var(--accent-ink)); }
.nf-servicio__nota { margin: .6rem 0 0; font-size: .86rem; color: var(--muted); font-style: italic; }
.nf-servicio__txt { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
/* Micro-etiqueta en versalitas: identifica el dato sin necesitar dos puntos, que habría que meter en cada
   traducción y quedaría suelto si el idioma cambia la puntuación. */
.nf-servicio__label { color: var(--muted); font-size: .74rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; line-height: 1.2; }
.nf-servicio__nombre { color: var(--accent-ink); font-weight: 700; font-size: 1.3rem; line-height: 1.25; }
.nf-servicio__extra { margin-left: auto; flex: none; color: var(--muted); font-size: .88rem; white-space: nowrap; }
@media (max-width: 480px) {
    .nf-servicio__extra { display: none; }
}

/* ── Fila desplegable de listado (Consulados, y cualquier lista larga que venga después) ────────────────
   Misma familia visual que `.nf-servicio`, pero para LISTAS: lo que identifica cada elemento se ve plegado
   y el detalle se abre bajo demanda. Con veinte países en el catálogo, una tarjeta desplegada por consulado
   obligaba a hacer scroll para comparar dos.

   El disparador es un <button> que ocupa la fila entera: superficie grande, `aria-expanded` real y un solo
   tabulador por elemento. Las acciones (editar, eliminar) van FUERA de él —un botón dentro de otro botón no
   es HTML válido y los lectores de pantalla lo anuncian mal—, en su propia caja a la derecha.

   El chevron gira con una clase en lugar de intercambiar dos iconos con `x-show`: un solo nodo, sin salto
   de maquetación al alternar, y respeta `prefers-reduced-motion` como el resto de la hoja. */
.nf-desp {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.nf-desp + .nf-desp { margin-top: .5rem; }
.nf-desp:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.nf-desp:has(.nf-desp__head[aria-expanded="true"]) { border-color: var(--primary); box-shadow: var(--shadow-sm); }

.nf-desp__fila { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; padding: .35rem .5rem .35rem .35rem; }

.nf-desp__head {
    flex: 1 1 260px;
    display: flex;
    align-items: center;
    gap: .6rem;
    min-width: 0;
    padding: .5rem .6rem;
    border: 0;
    border-radius: var(--r-xs);
    background: transparent;
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.nf-desp__head:hover { background: var(--primary-weak); }
/* Foco visible SIEMPRE, también con el ratón: es la única señal de dónde está quien navega por teclado, y
   aquí la fila entera es el disparador. */
.nf-desp__head:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }

.nf-desp__chevron { flex: none; display: inline-flex; color: var(--muted); transition: transform .18s ease; }
.nf-desp__head[aria-expanded="true"] .nf-desp__chevron { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .nf-desp__chevron { transition: none; } }

/* La bandera es DECORATIVA: el nombre y el código van al lado y son los que se leen. En Windows, además, no
   hay tipografía de banderas y se ven las dos letras — otra razón para que nunca cargue sola con el dato. */
.nf-desp__bandera { flex: none; display: inline-flex; }

/* Bandera: proporción 4:3 con un filo tenue, porque muchas llevan blanco en el borde y sin él se derraman
   sobre el fondo de la fila. El radio pequeño la asienta con el resto de las pastillas. */
.nf-bandera {
    display: inline-block;
    width: 20px;
    height: 15px;
    object-fit: cover;
    border-radius: 2px;
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
    flex: none;
}

.nf-desp__txt { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.nf-desp__nombre { font-weight: 700; color: var(--ink); line-height: 1.25; overflow-wrap: anywhere; }
.nf-desp__sub { color: var(--muted); font-size: .78rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.nf-desp__marcas { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; flex: none; }
.nf-desp__acciones { display: flex; gap: .4rem; flex-wrap: wrap; flex: none; margin-left: auto; }

.nf-desp__cuerpo { padding: .75rem .95rem .9rem; border-top: 1px solid var(--border); }

@media (max-width: 640px) {
    .nf-desp__acciones { margin-left: 0; width: 100%; }
    .nf-desp__head { flex-basis: 100%; }
}

/* Barra de filtros de un listado: la misma caja que un formulario, separada de los resultados. */
.nf-filtros { display: flex; gap: .8rem; flex-wrap: wrap; align-items: flex-end; }
.nf-filtros > * { flex: 1 1 180px; min-width: 0; }
.nf-filtros__ancho { flex: 2 1 260px; }
.nf-filtros__pie { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin-top: .8rem; }

/* Selector de archivo: el input nativo pinta su botón en el idioma del NAVEGADOR («Choose File»), no en el de
   la app. Se oculta —sin quitarlo del foco por teclado— y el <label> hace de botón, que sí se traduce. */
/* Es un CAMPO, no un botón suelto: misma caja que un input o un desplegable —borde, radio, fondo y la altura
   del token— con el botón dentro y el nombre del archivo como su contenido.
   Igualar solo la ALTURA (lo anterior: `min-height: 48px`) no arreglaba la fila. El ojo no compara alturas,
   compara cajas: al lado de un desplegable con borde, el selector era una pastilla rosa de 36 px flotando
   sobre el fondo de la tarjeta con un texto gris detrás, así que las dos mitades de la fila no se leían como
   la misma cosa aunque midieran igual. */
.nf-file {
    display: flex; align-items: center; gap: .6rem; flex-wrap: nowrap;
    min-height: var(--h-control);
    padding: 0 .5rem 0 .45rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}
/* El foco del input oculto se pinta en la CAJA, que es la que se ve, y no solo alrededor del botón. */
.nf-file:focus-within { border-color: var(--accent-ink); }
.nf-file__input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.nf-file__input:focus-visible + label { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.nf-file label { cursor: pointer; margin: 0; }
/* El nombre del archivo se recorta con puntos suspensivos en vez de partirse: dentro de una caja de altura
   fija, un nombre largo la estiraba y volvía a descuadrar la fila que esto viene a cuadrar. */
.nf-file__nombre {
    color: var(--muted); font-size: .9rem;
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Niveles de servicio en /admin/tarifas: cada nivel es un bloque con SUS tarifas y SUS reglas dentro, en vez
   de repartirlos entre un resumen y una lista plana de identificadores. */
.nf-nivel { border: 1px solid var(--border); border-left: 4px solid var(--primary); border-radius: var(--r-sm); padding: .8rem .95rem; margin-bottom: .8rem; }
.nf-nivel__head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .5rem; }
.nf-nivel__tarifas { background: var(--surface-2); border-radius: var(--r-sm); padding: .5rem .7rem; }
.nf-nivel__tarifa { display: flex; align-items: center; gap: .6rem; padding: .2rem 0; }
.nf-nivel__tarifa span { flex: 1; min-width: 0; color: var(--text); font-size: .9rem; }
.nf-nivel__reglas { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.nf-nivel__reglas li { display: flex; align-items: center; gap: .45rem; font-size: .9rem; color: var(--text); }

/* En estrecho la fila de precio SE PARTE. Iba en una sola línea con tres piezas —concepto, importe y el
   botón de cambiarlo— y el botón no puede encogerse por debajo de su propio texto, así que desbordaba la
   tarjeta y se montaba encima del importe. No era que el texto se solapase: era el botón saliéndose.
   Ahora el concepto ocupa su renglón y el importe y su acción van debajo, con el botón al final. */
@media (max-width: 640px) {
    .nf-nivel__tarifa { flex-wrap: wrap; row-gap: .15rem; }
    .nf-nivel__tarifa span { flex: 1 1 100%; }
    .nf-nivel__tarifa .btn { margin-left: auto; }
    /* Misma historia en la cabecera del nivel: nombre y distintivos por un lado, acciones por otro. */
    .nf-nivel__head > div:last-child { margin-left: auto; }
}

/* Indicador de pasos (onboarding) */
.nf-steps { display: flex; align-items: center; gap: .55rem; margin-bottom: 1.4rem; flex-wrap: wrap; padding: .3rem 0; }
/* Variante centrada para el alta. No se centra `.nf-steps` a secas porque la usa también la pantalla de la
   extensión de la tasa 790, que no entra en este cambio. */
.nf-steps--centrado { justify-content: center; }
.nf-step { display: inline-flex; align-items: center; gap: .5rem; color: var(--muted); font-size: .88rem; }
.nf-step .n {
    width: 30px; height: 30px; border-radius: 50%; flex: none;
    background: var(--surface); border: 2px solid var(--border-strong); color: var(--muted);
    display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: .82rem;
}
.nf-step.done { color: var(--accent-ink); }
.nf-step.done .n { background: var(--grad); color: #fff; border-color: transparent; }
.nf-step.on { color: var(--accent-ink); font-weight: 700; }
.nf-step.on .n { background: var(--grad); color: #fff; border-color: transparent; box-shadow: 0 0 0 4px var(--primary-weak); animation: pbStepPulse 2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .nf-step.on .n { animation: none; } }
/* Paso al que se puede VOLVER. Es un <a>, así que hay que devolverle el aspecto de rótulo (sin subrayado)
   y, a cambio, dejar claro que se puede pulsar: cursor, realce al pasar por encima y foco visible. Sin esto
   un enlace y un rótulo inerte se veían exactamente igual y nadie descubriría que se puede retroceder. */
.nf-step--volver { text-decoration: none; cursor: pointer; border-radius: 999px; padding: .1rem .35rem; margin: -.1rem -.35rem; }
.nf-step--volver:hover { color: var(--primary); background: var(--primary-weak); }
.nf-step--volver:hover .n { transform: scale(1.06); }
.nf-step--volver .n { transition: transform .15s ease; }
.nf-step--volver:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .nf-step--volver:hover .n { transform: none; } }

.nf-steps .sep { flex: 1; height: 2px; background: var(--border-strong); max-width: 48px; min-width: 16px; border-radius: 2px; }
.nf-steps .nf-step.done + .sep { background: var(--primary); }

/* Rejilla de formulario y secciones */
.nf-grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 1rem; }
/* Fila de campos de formulario (evita el estilo inline repetido en todos los formularios). */
.nf-formrow { display: flex; gap: 1rem; flex-wrap: wrap; }
/* Un botón puesto DIRECTAMENTE en una fila de campos se alinea con el borde inferior de estos y no se
   estira a lo alto de la fila. Sin esto, meter la acción junto a sus campos daba un botón deformado, así
   que se acababa mandando a su propio renglón. */
.nf-formrow > button { align-self: flex-end; flex: none; }
/* Fieldset con marco punteado + leyenda (p. ej. datos profesionales del agente). */
.nf-fieldset { border: 1px dashed var(--line); border-radius: var(--r-sm); padding: .5rem .8rem .8rem; margin-top: .6rem; min-width: 0; }
.nf-fieldset > legend { padding: 0 .4rem; }
/* Fila de cita solapada (calendario): tinte de aviso, sin acoplarse al padding de la tarjeta. */
.nf-row--overlap { background: var(--warning-weak); }
.nf-section { font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); margin: 1.3rem 0 .2rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.nf-section.first { border-top: 0; padding-top: 0; margin-top: .2rem; }

/* Landing pública (catálogo) — hero con gradiente de marca y texto claro. */
.nf-hero {
    text-align: center;
    padding: 3rem 1.4rem 2.4rem;
    margin-bottom: 1.4rem;
    background: var(--hero-gradient);
    border-radius: var(--r-lg);
    color: #fff;
}
.nf-hero h1 { font-size: 2.7rem; color: #fff; margin-bottom: .5rem; }
.nf-hero .lead { font-size: 1.12rem; color: rgba(255, 255, 255, .85); max-width: 600px; margin: 0 auto 1.6rem; }
/* CTA del hero: botón de degradado (como el resto) con un anillo blanco fino que lo separa del fondo
   degradado del hero + una sombra proyectada más oscura para dar forma. */
.nf-hero .big {
    font-size: 1rem;
    padding: .85rem 1.85rem;
    min-height: 52px;
    box-shadow: 0px 0px 8px 1px rgba(255, 255, 255, .4), 0 8px 24px -5px #ec4899;
}
.nf-hero .big:hover { box-shadow: 0px 0px 12px 2px rgba(255, 255, 255, .55), 0 11px 28px -5px #ec4899; }
/* CTA de tarjeta de precio: ancho completo al pie de la tarjeta. */
.nf-pricecard .btn { width: 100%; }
.nf-hero .trust { color: rgba(255, 255, 255, .7); font-size: .85rem; margin-top: 1rem; }

/* Pie de página (token: fondo azul oscuro, texto atenuado). */
/* Footer sobre fondo tinta oscuro (en ambos temas) para que el logo morado→rosa luzca y contraste;
   marca a la izquierda, tagline + copyright a la derecha (se apilan en móvil). */
.nf-footer {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .7rem 1.6rem;
    flex-wrap: wrap;
    background: #1A1526;
    color: rgba(255, 255, 255, .62);
    padding: 1.35rem 1.6rem;
    font-size: .85rem;
}
[data-theme="dark"] .nf-footer { background: #100B1B; border-top: 1px solid rgba(255, 255, 255, .06); }
.nf-footer a { color: rgba(255, 255, 255, .82); }
.nf-footer a:hover { color: #fff; text-decoration: none; }
.nf-footer__brand {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-family: var(--font-serif);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: .2px;
}
.nf-footer__logo { height: 26px; width: auto; display: block; filter: brightness(0) invert(1); }
.nf-footer__meta { display: flex; flex-direction: column; gap: .15rem; text-align: right; }
.nf-footer__meta p { margin: 0; }
.nf-footer__copy { color: rgba(255, 255, 255, .45); font-size: .8rem; }
/* La versión desplegada: monoespaciada y más apagada que el resto del pie. Es un dato de diagnóstico, no
   información para el cliente — tiene que poder leerse cuando se busca y desaparecer cuando no. */
.nf-footer__version { font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-size: .72rem; opacity: .55; letter-spacing: .02em; }
@media (max-width: 560px) {
    .nf-footer { justify-content: center; text-align: center; }
    .nf-footer__meta { text-align: center; }
}
.nf-values { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: .9rem; margin-bottom: 1.1rem; }
.nf-values .nf-card { margin-bottom: 0; }
.nf-values h3 { color: var(--accent-ink); margin-bottom: .3rem; }
.nf-values p { font-size: .9rem; color: var(--text); margin: 0; }
.nf-price { font-family: var(--font-serif); font-size: 2.5rem; font-weight: 700; color: var(--accent-ink); line-height: 1; }
.nf-price small { font-size: 1rem; color: var(--muted); font-family: var(--font-sans); font-weight: 400; }
.nf-pricelist { list-style: none; padding: 0; margin: 1rem 0; }
.nf-pricelist li { display: flex; justify-content: space-between; padding: .5rem 0; border-top: 1px solid var(--border); font-size: .92rem; }
.nf-pricelist li strong { font-variant-numeric: tabular-nums; }
/* Fila de total del carrito: destacada (borde más marcado, importe en azul de marca). */
.nf-pricelist li.nf-pago-total { border-top: 2px solid var(--border-strong); font-size: 1.05rem; padding-top: .7rem; margin-top: .15rem; font-weight: 700; }
.nf-pricelist li.nf-pago-total strong { color: var(--accent-ink); }

/* Pricing con tarjeta destacada (apariencia del landing) */
.nf-section-title { text-align: center; margin: .5rem 0 1.4rem; }
.nf-pricing {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.5rem;
    align-items: stretch;
    margin-bottom: 1.4rem;
}
.nf-pricecard {
    display: flex;
    flex-direction: column;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 1.8rem;
    box-shadow: var(--shadow);
}
.nf-pricecard h3 { color: var(--accent-ink); }
.nf-pricecard .price { font-size: 2.3rem; font-weight: 700; color: var(--accent-ink); line-height: 1; margin: .8rem 0; }
.nf-pricecard .price small { font-size: 1rem; font-weight: 400; color: var(--text-muted); }
.nf-pricecard ul { list-style: none; text-align: left; padding: 0; margin: 1rem 0 1.6rem; flex-grow: 1; }
.nf-pricecard li { position: relative; padding: .35rem 0 .35rem 1.6rem; font-size: .93rem; color: var(--text-muted); }
.nf-pricecard li::before { content: "✓"; position: absolute; left: 0; color: var(--accent-dark); font-weight: 700; }
.nf-pricecard.featured {
    border: 2px solid transparent;
    background: linear-gradient(var(--surface), var(--surface)) padding-box, var(--grad) border-box;
    position: relative;
}
.nf-pricecard.featured::after {
    content: attr(data-badge);
    position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
    background: var(--grad); color: #fff;
    font-size: .75rem; font-weight: 700; padding: .2rem .8rem; border-radius: var(--r-pill); white-space: nowrap;
}
.nf-pricenote { text-align: center; color: var(--text-muted); font-size: .85rem; margin-bottom: 1.4rem; }

/* FAQ acordeón (apariencia del landing) */
.nf-faq { margin-bottom: 1.4rem; }
.nf-faq__item { border-bottom: 1px solid var(--border); }
.nf-faq__item summary {
    cursor: pointer; padding: 1.1rem 0; font-weight: 600; color: var(--accent-ink);
    list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
.nf-faq__item summary::-webkit-details-marker { display: none; }
.nf-faq__item summary::after { content: "+"; font-size: 1.4rem; color: var(--accent-dark); flex-shrink: 0; }
.nf-faq__item[open] summary::after { content: "–"; }
.nf-faq__answer { padding: 0 0 1.2rem; color: var(--text-muted); font-size: .95rem; }

/* KPIs del cuadro de mando */
/* (bloque .nf-stats/.nf-stat eliminado: sustituido por .nf-tiles/.nf-tile, sin usos en vistas) */

/* Título de sección con icono (como el menú); el icono escala con el tamaño del título. */
.nf-sectitle { display: flex; align-items: center; gap: .55rem; }
.nf-sectitle .nf-ico { color: var(--accent-ink); flex: 0 0 auto; width: .95em; height: .95em; }

/* Barras horizontales (por estado, cuellos, carga) */
.nf-barline { display: flex; align-items: center; gap: .6rem; margin: .45rem 0; font-size: .85rem; }
.nf-barline .k { width: 160px; flex-shrink: 0; color: var(--text); }
.nf-barline .track { flex: 1; height: 11px; background: var(--surface-2); border-radius: 6px; overflow: hidden; border: 1px solid var(--border); }
/* `display:block` NO es decorativo (B-4.5): el relleno es un <span> y el `.track` que lo contiene no es
   contenedor flex, así que sin esto queda INLINE y el navegador ignora su width/height — caja medida de 0×0
   con el width bien calculado en el HTML. Las tres gráficas del cuadro de mando salían vacías, con todas las
   barras idénticas midieran lo que midieran. */
.nf-barline .fill { display: block; height: 100%; border-radius: 6px; background: var(--primary); }
.nf-barline .fill.gray  { background: #A79FBE; }
.nf-barline .fill.slate { background: #7E7797; }
.nf-barline .fill.blue  { background: var(--primary); }
.nf-barline .fill.amber { background: #f59e0b; }
.nf-barline .fill.green { background: #22c55e; }
.nf-barline .fill.red   { background: #ef4444; }
.nf-barline .v { width: 44px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink); }

/* Lista de filas (bandejas, calendario) */
.nf-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    padding: .7rem 0;
    border-top: 1px solid var(--border);
}
.nf-row:first-of-type { border-top: 0; }
.nf-row .ref { font-weight: 700; color: var(--ink); }
.meta, .nf-row .meta { color: var(--muted); font-size: .82rem; }
.nf-row .grow { margin-left: auto; }

/* Botones secundarios compactos (acciones por documento) */
.btn-sm { min-height: 36px; padding: .4rem .85rem; font-size: .84rem; box-shadow: none; }
/* Botón secundario: relleno propio (no blanco), texto blanco, con icono descriptivo.
   Durante un tiempo esta regla declaró `var(--primary)` —lo MISMO que `.btn-primary`, salvo el font-weight—,
   así que no había jerarquía: «Eliminar caso» pesaba igual que la acción principal de su pantalla (B-4.4).
   Ahora sale de `--secondary`, que se ajusta en la paleta y no aquí.
   El nombre «ghost» es herencia del kit original y ya no describe el aspecto; se conserva por los 74 usos. */
.btn-ghost { background: var(--secondary); color: #fff; border-color: transparent; font-weight: 600; }
.btn-ghost:hover { background: var(--secondary-hover); color: #fff; }
.btn-ghost .nf-ico { opacity: 1; }

/* Checklist documental: una tarjeta por documento, con icono de estado y acciones a la derecha */
.nf-doclist { display: flex; flex-direction: column; gap: .55rem; margin-top: 1rem; }
.nf-doc {
    display: flex; align-items: center; gap: .85rem; flex-wrap: wrap;
    padding: .75rem .9rem; border: 1px solid var(--border);
    border-left: 4px solid var(--border-strong); border-radius: var(--r-sm); background: var(--surface);
}
/* Fondo en un tono claro del color del borde, como acento (visible pero suave). */
.nf-doc--ok      { border-left-color: var(--success-ink); background: var(--success-weak); }
.nf-doc--rej     { border-left-color: var(--danger-ink); background: var(--danger-weak); }
.nf-doc--pend    { border-left-color: var(--warning-ink); background: var(--warning-weak); }
.nf-doc--missing { border-left-style: dashed; background: var(--surface-2); }
.nf-doc__icon {
    flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 800; font-size: .95rem; line-height: 1;
    background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}
.nf-doc--ok      .nf-doc__icon { background: var(--success-weak); color: var(--success-ink); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.nf-doc--rej     .nf-doc__icon { background: var(--danger-weak); color: var(--danger-ink); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.nf-doc--pend    .nf-doc__icon { background: var(--warning-weak); color: var(--warning-ink); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
.nf-doc__main { flex: 1 1 200px; min-width: 0; overflow-wrap: anywhere; }
.nf-doc__name { font-weight: 700; color: var(--ink); }
.nf-doc__meta { font-size: .8rem; color: var(--muted); margin-top: .1rem; }
.nf-doc__meta .nf-err { display: block; margin-top: .15rem; }
.nf-doc__actions { display: flex; gap: .4rem; flex-wrap: wrap; margin-left: auto; }
.nf-doc__actions a { text-decoration: none; }

/* Variante de revisión (gestor): tarjeta apilada con cabecera + zona de rechazo inferior */
.nf-doclist--review { gap: .9rem; }
.nf-doc--review { flex-direction: column; align-items: stretch; gap: 0; padding: 0; overflow: hidden; box-shadow: var(--shadow-sm); }
/* Cabecera: icono + título a la izquierda, estado (badge + versión) a la derecha. */
.nf-doc__bar { display: flex; align-items: center; gap: .6rem; padding: .7rem .95rem; }
.nf-doc--review .nf-doc__name { font-size: 1.02rem; flex: 1 1 auto; min-width: 0; }
.nf-doc__status { margin-left: auto; display: flex; align-items: center; gap: .45rem; flex: 0 0 auto; }
/* Toolbar de botones justo debajo del título. */
.nf-doc__toolbar { display: flex; gap: .4rem; flex-wrap: wrap; padding: 0 .95rem .65rem; }
.nf-doc__toolbar .btn { text-decoration: none; }
.nf-doc__body { padding: 0 .95rem .85rem; }
.nf-doc__body .nf-doc__meta:first-child { margin-top: 0; }
/* Botones de acción positivos/negativos (aceptar/rechazar). */
.btn-ok { background: var(--success); color: #fff; border-color: transparent; }
.btn-ok:hover { background: #15803d; color: #fff; }
.btn-ko { background: var(--danger); color: #fff; border-color: transparent; }
.btn-ko:hover { background: var(--danger-hover); color: #fff; }
.nf-doc__reject {
    margin-top: .55rem; border: 1px solid var(--border); background: var(--surface-2);
    border-radius: var(--r-sm); padding: .8rem;
}
.nf-doc__reject > label { display: block; font-weight: 700; font-size: .82rem; color: var(--ink); margin-bottom: .4rem; }
.nf-doc__rejrow { display: flex; gap: .55rem; flex-wrap: wrap; align-items: stretch; margin-bottom: .55rem; }
.nf-doc__rejrow select { flex: 1 1 160px; min-width: 0; }
.nf-doc__rejrow .btn { flex: 0 0 auto; }

/* Editor de formato sencillo (barra + textarea) */
.nf-editor { border: 1px solid var(--border-strong); border-radius: var(--r-sm); overflow: hidden; background: var(--surface); }
.nf-editor:focus-within { border-color: var(--accent-ink); }
.nf-editor:has(:focus-visible) { box-shadow: var(--ring); }
.nf-editor__bar { display: flex; gap: .15rem; padding: .25rem .35rem; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.nf-editor__bar button {
    min-height: 28px; padding: .1rem .55rem; font-size: .85rem; line-height: 1;
    background: transparent; color: var(--ink); border: 1px solid transparent;
    box-shadow: none; border-radius: .35rem;
}
.nf-editor__bar button:hover { background: var(--border); }
.nf-editor__toggle { margin-left: auto; font-size: .78rem !important; font-weight: 600; color: var(--muted) !important; }
.nf-editor__toggle.is-active { background: var(--primary) !important; color: var(--on-primary) !important; }
.nf-editor__preview { border-top: 1px dashed var(--border-strong); padding: .55rem .65rem; background: var(--surface-2); }
.nf-editor__previewlabel { display: block; font-size: .68rem; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--muted); margin-bottom: .25rem; }
.nf-editor__empty { color: var(--muted); font-style: italic; }
.nf-editor textarea {
    width: 100%; border: 0; padding: .55rem .65rem; resize: vertical; min-height: 2.6rem;
    font-family: var(--font-sans); font-size: .9rem; color: var(--ink); background: var(--surface);
}
.nf-editor textarea:focus { outline: none; }

/* ── Editor de la DIRECCIÓN DE ENVÍO del poder (/admin/tarifas) ─────────────────────────────────────────
   Hermano de `.nf-editor`: mismo marco y misma barra, pero los botones no insertan marcas en el texto sino
   que cambian CÓMO SE IMPRIME el bloque. El recuadro de vista previa imita el PAPEL, no el panel: se queda
   en blanco con tinta oscura también en modo noche, y con serifa, porque lo que reproduce es la carta que
   sale por la impresora — un preview que se adapta al tema deja de ser un preview. */
.nf-dir { border: 1px solid var(--border-strong); border-radius: var(--r-sm); overflow: hidden; background: var(--surface); }
.nf-dir:focus-within { border-color: var(--accent-ink); }
.nf-dir__bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .9rem;
    padding: .35rem .45rem; border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.nf-dir__eje { display: flex; align-items: center; gap: .15rem; }
.nf-dir__ejelbl { font-size: .68rem; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--muted); margin-right: .25rem; }
.nf-dir__op {
    min-height: 28px; padding: .1rem .55rem; font-size: .8rem; line-height: 1;
    background: transparent; color: var(--ink); border: 1px solid var(--border); box-shadow: none; border-radius: .35rem;
}
.nf-dir__op:hover { background: var(--border); }
.nf-dir__op.is-active { background: var(--primary); color: var(--on-primary); border-color: transparent; }
.nf-dir textarea {
    width: 100%; border: 0; padding: .55rem .65rem; resize: vertical; min-height: 4.4rem;
    font-family: var(--font-sans); font-size: .9rem; color: var(--ink); background: var(--surface);
}
.nf-dir textarea:focus { outline: none; }
.nf-dir__preview { border-top: 1px dashed var(--border-strong); padding: .55rem .65rem; background: var(--surface-2); }
.nf-dir__lbl { display: block; font-size: .68rem; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--muted); margin-bottom: .35rem; }
.nf-dir__paper {
    background: #fff; color: #111; border: 1px solid #d7d7d7; border-radius: .25rem;
    padding: .85rem 1rem; font-family: 'DejaVu Serif', Georgia, serif;
    /* El interlineado de la página abriría los renglones y la dirección se vería más suelta de lo que se
       imprime; el del documento lo pone el estilo en línea que viene de `cssBuzon()`. */
    line-height: 1.35;
}
.nf-dir__vacio { color: #767676; font-style: italic; font-size: 11px; }

/* Los DOS MODELOS de la carta de instrucciones. Se listan como filas y no como pestañas a propósito: no son
   dos vistas de lo mismo, son dos documentos que conviven, y hay que poder descargar los dos seguidos para
   compararlos sin perder de vista cuál es cuál. */
.nf-modelos { margin-top: 1.5rem; padding-top: 1.1rem; border-top: 1px solid var(--border); }
.nf-modelos__tit { font-size: 1rem; margin: 0 0 .2rem; color: var(--ink); }
.nf-modelo {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
    margin-top: .7rem; padding: .7rem .85rem;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2);
}
.nf-modelo__txt { display: flex; flex-direction: column; gap: .2rem; min-width: 260px; flex: 1; }
.nf-modelo__nom { font-weight: 700; color: var(--ink); }
.nf-modelo__dsc { font-size: .85rem; color: var(--muted); }
.nf-modelo__niv { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .15rem; }
/* Oculto a la vista pero no al lector de pantalla ni al teclado. Existe porque el patrón «botón que en
   realidad es un <label> de un <input type=file>» se repite por la ficha de revisión, y llevaba esas siete
   declaraciones escritas a mano en cada sitio: una de ellas mal copiada y el selector de archivo reaparece. */
/* Un TEMA dentro del recuadro de documentos: el EX-15, el poder, la tasa. El recuadro era una pila plana
   de filas y párrafos grises en la que el único título que había se veía igual que los rótulos de las filas,
   así que no se podía saber qué colgaba de qué. El título va con su regla superior —salvo el primero, que ya
   la tiene del recuadro— porque lo que separa los bloques es la línea, no el hueco: con solo margen, un
   párrafo de ayuda largo se lee como si perteneciera al bloque siguiente. */
/* Entrega estimada. Va destacada y con la fecha en grande porque es LA pregunta del cliente: en una ficha
   llena de estados y documentos, una línea gris más se pierde. */
.nf-entrega { border-left: 3px solid var(--primary); }
.nf-entrega__lbl { margin: 0; font-size: .72rem; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--muted); }
.nf-entrega__fecha { margin: .15rem 0 0; font-size: 1.35rem; font-weight: 800; color: var(--accent-ink); }

/* Discrepancias entre lo declarado y el pasaporte (DOC-08). En ÁMBAR y no en rojo: no es un error del
   cliente —el cotejo de una MRZ es tolerante y se equivoca— sino algo que hay que verificar; en rojo se leería
   como «has hecho algo mal» y lo que se le pide es que compare. */
.nf-discrep__tit { display: flex; align-items: center; gap: .4rem; margin: 0 0 .4rem; font-weight: 700; }
.nf-discrep__lista { margin: 0; padding-left: 1.1rem; display: grid; gap: .2rem; }
.nf-discrep__pie { margin: .5rem 0 0; font-size: .88rem; }
/* La marca bajo la casilla concreta: es la que convierte «hay discrepancias» en «mira ESTE campo». */
.nf-discrep__campo { display: block; margin-top: .25rem; font-size: .82rem; line-height: 1.35; color: var(--warning-ink); }

/* (Aquí vivían `.nf-requisitos` y `.nf-desistimiento`, dos bloques con barra de color propios del paso de
   condiciones. Los dos se fundieron en `.nf-claves` el 19/09; el desistimiento dejó además su explicación
   pegada a la casilla que renuncia a él, que es la de abajo. `git log -S nf-desistimiento`.) */

/* La casilla de «empezad ya»: fondo propio y sangrada bajo la de aceptar, para que se lea como lo que es
   —otra decisión, opcional— y no como una segunda línea de la misma. */
.nf-empezar-ya { display: flex; align-items: flex-start; gap: .5rem; margin: .6rem 0 0 1.4rem; padding: .55rem .7rem; background: var(--surface-2); border-radius: 6px; }
.nf-empezar-ya input { margin-top: .2rem; flex: 0 0 auto; }
/* `font-weight` explícito: `label` lo pone en 700 para toda la etiqueta, así que la nota —que es la letra
   pequeña de la casilla— salía en negrita y con el mismo peso que la frase que hay que decidir. */
.nf-empezar-ya .meta { display: block; margin-top: .2rem; line-height: 1.4; font-weight: 400; }

/* La casilla OBLIGATORIA, la que abre la compra.
   Iba suelta en una línea mientras las dos OPCIONALES —empezar ya, marketing— vivían cada una en su
   recuadro. O sea que lo que hay que marcar para comprar parecía menos importante que lo que no hace falta,
   y ese es el orden al revés: el ojo va primero a las cajas.
   Se le da su propio bloque, con más peso que las opcionales —el filete de marca a la izquierda— para que
   sea lo primero que se ve al llegar aquí. No es adorno: es la pantalla que hay que poder enseñar ante una
   disputa (ONB-03, R-05), y un consentimiento que pasa desapercibido es el que se discute después. */
.nf-acepto {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    margin: 1rem 0 0;
    padding: .8rem .9rem;
    background: var(--primary-weak);
    border-left: 4px solid var(--primary);
    border-radius: 6px;
    font-weight: 600;
    cursor: pointer;
}

.nf-acepto input { flex: 0 0 auto; margin-top: .1rem; }

/* Veredicto del código postal en el alta. Va en verde o en rojo y con su icono, no solo en gris: es la
   respuesta a «¿me podéis atender?», y de ella depende que la persona siga o se vaya. */
.nf-postcode { display: flex; align-items: flex-start; gap: .4rem; margin: .5rem 0 0; font-size: .88rem; line-height: 1.4; }
.nf-postcode .nf-ico { flex: 0 0 auto; margin-top: .1rem; }
.nf-postcode--ok { color: var(--success-ink); font-weight: 600; }
.nf-postcode--ko { color: var(--danger-ink); }

/* Aviso de Bloq Mayús junto al campo de contraseña. Va en el tono de ADVERTENCIA y no en el de error: no se
   ha equivocado nadie todavía, es una tecla puesta, y pintarlo de rojo diría que algo ha fallado cuando lo
   que hace falta es que se note antes de enviar. */
.nf-mayus {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: .35rem 0 0;
    font-size: .85rem;
    font-weight: 600;
    color: var(--warning-ink);
}

.nf-mayus .nf-ico { flex: 0 0 auto; }

.nf-bloquedoc { padding-top: .9rem; margin-top: .9rem; border-top: 1px solid var(--border); }
.nf-bloquedoc:first-of-type { padding-top: 0; margin-top: .2rem; border-top: 0; }
.nf-bloquedoc__tit {
    font-size: .82rem; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
    color: var(--muted); margin: 0 0 .55rem;
}

.nf-doc__rejacciones { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-top: .6rem; }

.nf-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;
}

.nf-modelo__badge {
    font-size: .72rem; font-weight: 600; padding: .12rem .5rem; border-radius: 999px;
    background: var(--border); color: var(--ink);
}

/* Botón de acento (ámbar) — equivalente al botón por defecto, para usar como .btn explícito */
.btn-gold { background: var(--grad); color: #fff; border-color: transparent; }
.btn-gold:hover { filter: brightness(1.06); }
.btn-gold:active { filter: brightness(.95); }

/* Pestañas simples (gestión de usuarios: internos / clientes) */
.nf-tabs { display: inline-flex; gap: .3rem; flex-wrap: wrap; }
.nf-tab { display: inline-flex; align-items: center; gap: .35rem; background: transparent; color: var(--accent-ink);
    border: 1px solid var(--line); padding: .4rem .85rem; border-radius: var(--r-sm); cursor: pointer; font-weight: 600; }
.nf-tab:hover { background: var(--page); }
.nf-tab.is-active, .nf-tab.is-active:hover { background: var(--primary); color: #fff; border-color: var(--accent-ink); }
/* Enlace de texto inline (toggles, ayudas) */
/* Enlace de texto en línea. Resetea el chrome de <button> (si no, hereda el fondo degradado del botón base y
   queda texto violeta sobre el degradado, ilegible). */
.nf-link { background: none; border: 0; padding: 0; min-height: 0; box-shadow: none; font: inherit; color: var(--accent-ink); text-decoration: underline; cursor: pointer; font-weight: 600; }
.nf-link:hover { background: none; filter: none; transform: none; color: var(--primary-dark); text-decoration: underline; }

/* Cabecera de la ficha del expediente: referencia a la izquierda y estado/progreso/exportar pegados al borde
   derecho (arriba), ocupando todo el ancho de la tarjeta. */
.nf-exp-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.nf-exp-head__id { flex: 1 1 220px; min-width: 0; }
.nf-exp-head__meta { display: flex; flex-direction: column; align-items: flex-end; gap: .2rem; margin-left: auto; text-align: right; }
@media (max-width: 640px) {
    /* align-items:flex-start para que el badge no se estire (a su ancho); solo el botón a ancho completo. */
    .nf-exp-head__meta { align-items: flex-start; text-align: left; width: 100%; margin-left: 0; }
    .nf-exp-head__meta .btn { width: 100%; justify-content: center; }
}

/* Pestañas de una ficha larga (revisión del expediente). En escritorio, barra de botones; en móvil, un
   desplegable (.nf-tab-select) que ocupa menos y es más cómodo de tocar. */
.nf-tabs--ficha { display: flex; gap: .35rem; margin-bottom: 1.1rem; flex-wrap: wrap; }
.nf-tabs--ficha .nf-tab { flex: 1 0 auto; justify-content: center; white-space: nowrap; }
/* Desplegable de secciones propio (no nativo): el botón es azul oscuro con texto blanco y la lista respeta
   los bordes redondeados del diseño (lo que un <select> nativo no permite). */
.nf-tab-select { display: none; position: relative; margin-bottom: 1.1rem; }
.nf-tab-select__btn {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: .6rem;
    background: var(--primary); color: #fff; font-weight: 600; border: 1px solid var(--primary);
    border-radius: var(--r-sm); padding: .8rem 1rem; cursor: pointer; box-shadow: none;
}
.nf-tab-select__btn:hover { background: var(--primary-dark); }
.nf-tab-select__btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.nf-tab-select__chev { flex: 0 0 auto; transition: transform .18s ease; }
.nf-tab-select__chev.is-open { transform: rotate(180deg); }
.nf-tab-select__menu {
    list-style: none; margin: .4rem 0 0; padding: .35rem; position: absolute; z-index: 30; left: 0; right: 0;
    background: var(--surface); border: 1.5px solid var(--primary); border-radius: var(--r);
    box-shadow: var(--shadow-lg);
}
.nf-tab-select__menu li { margin: 0; }
.nf-tab-select__menu button {
    width: 100%; text-align: left; background: transparent; color: var(--ink); border: 0; box-shadow: none;
    padding: .7rem .8rem; border-radius: var(--r-sm); font-weight: 600; cursor: pointer;
}
.nf-tab-select__menu button:hover { background: var(--page); }
.nf-tab-select__menu button.is-active { background: var(--primary); color: #fff; }
@media (max-width: 640px) {
    .nf-tabs--ficha { display: none; }
    .nf-tab-select { display: block; }
}

/* Ficha de expediente (cliente): barra superior con "volver" a la izquierda y el menú de secciones a la derecha. */
.nf-ficha-top { display: flex; justify-content: space-between; align-items: center; gap: .8rem 1.2rem; flex-wrap: wrap; margin-bottom: 1rem; }
.nf-ficha-top .nf-tabs--ficha,
.nf-ficha-top .nf-tab-select { margin-bottom: 0; }
.nf-ficha-title { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: .2rem 0 1.2rem; }
@media (max-width: 640px) {
    /* En móvil el desplegable ocupa toda la fila bajo el botón "volver". */
    .nf-ficha-top .nf-tab-select { flex: 1 1 100%; }
}

/* Confirmación inline en la interfaz (sin diálogos nativos) */
.nf-confirm { display: inline-flex; align-items: center; }
.nf-confirm__panel { display: inline-flex; align-items: center; gap: .5rem; flex-wrap: wrap; padding: .3rem .5rem; border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); background: var(--danger-weak); border-radius: var(--r-sm); }
.nf-confirm__msg { font-size: .82rem; color: var(--ink); font-weight: 600; }
.nf-confirm__btns { display: inline-flex; gap: .35rem; }
/* Cifra del reembolso en la tarjeta de cancelar: es el dato con el que se decide, va antes del botón. */
.nf-reembolso { margin: .6rem 0 .8rem; display: flex; flex-direction: column; gap: .15rem; }
.nf-reembolso .meta { font-size: .82rem; }
.nf-confirm__danger { background: var(--danger); color: #fff; border-color: transparent; }
.nf-confirm__danger:hover { background: var(--danger-hover); }

/* Botón compacto de borrar nota interna */
/* Botón "X" de eliminar nota: sutil en reposo (no azul), rojo sólido al pasar el cursor (claro y legible). */
.nf-note-del {
    flex: 0 0 auto; min-height: 30px; padding: .1rem .6rem; font-size: 1.05rem; line-height: 1; font-weight: 700;
    background: var(--primary); color: #fff; border: 1px solid var(--primary); box-shadow: none;
}
.nf-note-del:hover,
.nf-note-del:focus-visible { background: var(--danger); color: #fff; border-color: var(--danger-ink); }

/* Filas de "Documentos generados": título + acciones. En móvil, el título va en una línea y los botones en
   otra (repartidos a lo ancho). */
.nf-genrow { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; padding: .7rem 0; border-top: 1px solid var(--border); }
.nf-genrow:first-of-type { border-top: 0; }
.nf-genrow__label { flex: 1 1 auto; min-width: 140px; font-weight: 700; color: var(--ink); }
.nf-genrow__actions { display: flex; gap: .4rem; flex-wrap: wrap; }
.nf-genrow__actions .btn { text-decoration: none; }
@media (max-width: 640px) {
    .nf-genrow { flex-direction: column; align-items: stretch; }
    .nf-genrow__actions { width: 100%; }
    .nf-genrow__actions .btn { flex: 1 1 0; justify-content: center; }
}

/* Mensajería interna del expediente (NOT-02): hilo tipo timeline con filtros (rol/fecha) y color por rol. */
/* Barra de filtros: panel tintado con etiquetas en versalitas, como el resto de la app (nf-data/nf-section). */
/* Herramientas de «Mi cuenta»: tarjetas-enlace (facturas, notificaciones, privacidad, seguridad). */
.nf-herramientas { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1rem 0 1.4rem; }
.nf-herramienta {
    display: flex; align-items: flex-start; gap: .8rem;
    padding: 1rem 1.1rem; border: 1px solid var(--border); border-radius: var(--r);
    background: var(--surface); box-shadow: var(--shadow); color: var(--ink); text-decoration: none;
    transition: border-color .15s ease, box-shadow .15s ease, transform .06s ease;
}
.nf-herramienta:hover { border-color: var(--primary); box-shadow: var(--shadow-lg); transform: translateY(-1px); text-decoration: none; }
.nf-herramienta__ico { flex: 0 0 auto; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: var(--primary-weak); color: var(--accent-ink); }
.nf-herramienta__txt { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.nf-herramienta__tit { display: flex; align-items: center; gap: .45rem; font-weight: 700; font-size: .95rem; }
.nf-herramienta__sub { font-size: .84rem; color: var(--muted); }

/* Personas de la cuenta (titular + familiares): quién tramita bajo esta cuenta. */
.nf-personas { list-style: none; margin: .6rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.nf-personas li { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; padding: .6rem .7rem; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); }
.nf-personas__nombre { font-weight: 700; font-size: .95rem; }
.nf-personas li .btn { margin-left: auto; }

/* Rótulo del buscador del hilo: da nombre al bloque de filtros (expediente + rol + fecha). */
.nf-msg-buscador { margin: 1rem 0 -.2rem; font-size: .8rem; font-weight: 800; color: var(--accent-ink); }
.nf-msg-filtros {
    display: flex; gap: .8rem; flex-wrap: wrap; align-items: flex-end;
    margin: .7rem 0 1rem; padding: .85rem .9rem;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
}
.nf-msg-filtros > div { display: flex; flex-direction: column; gap: .25rem; flex: 1 1 160px; }
.nf-msg-filtros label { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.nf-msg-filtros select, .nf-msg-filtros input { padding: .5rem .7rem; background: var(--surface); }
/* MISMA ALTURA para todo lo que va en la fila. Cada control traía la suya (el desplegable propio ~47px por su
   padding, el botón «limpiar» 36 por .btn-sm) y la barra quedaba con los bordes a distintas alturas. */
.nf-msg-filtros .nf-select__btn,
.nf-msg-filtros .nf-date__btn,
.nf-msg-filtros .btn {
    min-height: 40px; padding-top: 0; padding-bottom: 0; font-size: .88rem;
}
.nf-msg-filtros .btn { flex: 0 0 auto; align-self: flex-end; }
@media (max-width: 640px) {
    .nf-msg-filtros > div { flex-basis: 100%; }
    .nf-msg-filtros .btn { width: 100%; justify-content: center; }
}
.nf-msg-tl { max-height: 460px; overflow-y: auto; padding-right: .3rem; }
.nf-msg-form { margin-top: 1rem; }
/* Expediente al que pertenece lo que se escribe: va DENTRO del formulario, no en una pantalla aparte. */
.nf-msg-destino { display: flex; flex-direction: column; gap: .25rem; max-width: 22rem; margin-bottom: .6rem; }
.nf-msg-destino label { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.nf-msg-destino .nf-select__btn { min-height: 40px; padding-top: 0; padding-bottom: 0; font-size: .88rem; }
/* Chip del expediente en cada mensaje: es lo que separa el hilo único de la cuenta por expediente. */
.nf-chat__exp {
    font-size: .62rem; font-weight: 700; letter-spacing: .03em; padding: .08rem .42rem; border-radius: 999px;
    background: var(--primary-weak); color: var(--accent-ink); text-decoration: none;
}
.nf-chat__exp:hover { background: var(--border-strong); text-decoration: none; }
.nf-msg-tl .nf-fmt { font-size: .92rem; color: var(--ink); }
/* Etiqueta de ROL del remitente: cliente en verde, despacho en azul (el punto del timeline va a juego). */
.nf-chat__rol { font-size: .62rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: .08rem .42rem; border-radius: 999px; }
.nf-chat__rol--cliente  { background: var(--success-weak); color: var(--success-ink); }
.nf-chat__rol--despacho { background: var(--info-weak); color: var(--accent-ink); }

/* Tabla de datos etiqueta/valor (ficha del solicitante) */
.nf-data { width: 100%; border-collapse: collapse; }
.nf-data td { padding: .55rem .7rem; vertical-align: top; border-top: 1px solid var(--border); font-size: .95rem; }
.nf-data tr:first-child td { border-top: 0; }
/* Fila alterna para localizar datos de un vistazo. */
.nf-data tr:nth-child(even) { background: var(--surface-2); }
/* Etiqueta: pequeña, en versalitas y atenuada; se lee como rótulo, no como dato. */
.nf-data td:first-child {
    color: var(--text-muted);
    width: 34%;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding-top: .72rem;
    line-height: 1.3;
}
/* Valor: oscuro y con peso, para que destaque sobre la etiqueta. */
.nf-data td:last-child { color: var(--ink); font-weight: 600; }
.nf-data td:last-child .meta { font-weight: 400; }

/* Paginación */
.nf-pagination { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: .4rem; margin-top: 1.1rem; }
.nf-pagination__info { font-size: .85rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.nf-pagination__nav { display: inline-flex; align-items: center; gap: .25rem; min-height: 34px; padding: .3rem .6rem; border: 1px solid var(--border-strong); border-radius: var(--r-sm); background: var(--surface); color: var(--ink); font-size: .85rem; cursor: pointer; }
.nf-pagination__nav:hover:not([disabled]) { background: var(--surface-2); }
.nf-pagination__nav[disabled] { opacity: .45; cursor: default; }
.nf-pagination__pages { display: inline-flex; align-items: center; gap: .25rem; list-style: none; margin: 0; padding: 0; }
.nf-pagination__link { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; min-height: 34px; padding: 0 .5rem; border: 1px solid transparent; border-radius: var(--r-sm); background: transparent; color: var(--ink); font-size: .85rem; font-variant-numeric: tabular-nums; line-height: 1; cursor: pointer; }
.nf-pagination__link:hover:not(.is-current) { background: var(--surface-2); }
.nf-pagination__link.is-current { background: var(--grad); color: #fff; font-weight: 700; cursor: default; }
.nf-pagination__ellipsis { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; min-height: 34px; color: var(--text-muted); }
@media (max-width: 560px) { .nf-pagination__navtext { display: none; } }

/* Overlays: menú de acciones (role=menu), popover rico (role=dialog) y tooltip (role=tooltip). Menú y popover
   usan el atributo popover NATIVO; Alpine los ancla con position:fixed (de ahí inset:auto sobre el UA). */
[popover].nf-menu__panel, [popover].nf-pop__panel { inset: auto; border: 0; padding: 0; overflow: visible; }
.nf-menu, .nf-pop { display: inline-flex; }
.nf-menu__panel {
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg); padding: .3rem; min-width: 180px;
}
.nf-menu__panel [role="menuitem"] {
    display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left;
    background: transparent; border: 1px solid transparent; box-shadow: none; color: var(--ink);
    padding: .5rem .6rem; border-radius: .4rem; font-size: .9rem; font-weight: 500; cursor: pointer;
}
.nf-menu__panel [role="menuitem"]:hover,
.nf-menu__panel [role="menuitem"]:focus-visible { background: var(--primary-weak); color: var(--accent-ink); outline: none; }
.nf-menu__panel [role="menuitem"][disabled] { opacity: .5; cursor: default; }
.nf-pop__panel {
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg); padding: 1rem; max-width: 320px; color: var(--ink);
}
.nf-tip { position: relative; display: inline-flex; }
.nf-tip__bubble {
    position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 6px; z-index: 60;
    background: var(--ink); color: var(--surface); font-size: .78rem; line-height: 1.3;
    padding: .3rem .55rem; border-radius: 6px; max-width: 240px; width: max-content;
    pointer-events: none; box-shadow: var(--shadow);
}

/* Calendario (mes / semana / día) — CIT-03 */
.nf-cal__bar { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; justify-content: space-between; }
.nf-cal__nav { display: inline-flex; gap: .35rem; }
.nf-cal__title { font-size: 1.15rem; color: var(--accent-ink); font-weight: 700; }
.nf-cal__views { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--r-sm); overflow: hidden; }
.nf-cal__views button { background: var(--surface); color: var(--text-muted); border: 0; box-shadow: none; min-height: 34px; padding: .35rem .85rem; font-size: .84rem; border-radius: 0; }
.nf-cal__views button + button { border-left: 1px solid var(--border-strong); }
.nf-cal__views button:hover { background: var(--surface-2); }
.nf-cal__views button.is-active { background: var(--primary); color: #fff; }
.nf-cal__views button.is-active:hover { background: var(--primary-dark); }

.nf-cal-scroll { overflow-x: auto; }
.nf-cal {
    display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px;
    background: var(--border); border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden;
    margin-top: 1rem;
}
.nf-cal__dow { background: var(--surface-2); padding: .45rem; text-align: center; font-size: .72rem; font-weight: 700; text-transform: uppercase; color: var(--text-muted); letter-spacing: .3px; }
.nf-cal__day { background: var(--surface); min-height: 98px; padding: .35rem; display: flex; flex-direction: column; gap: .2rem; }
.nf-cal--semana .nf-cal__day { min-height: 230px; }
.nf-cal__day.is-out { background: var(--bg-alt); }
.nf-cal__day.is-out .nf-cal__num { opacity: .45; }
.nf-cal__day.is-today { background: var(--primary-weak); }
.nf-cal__num { font-size: .8rem; font-weight: 700; color: var(--ink); align-self: flex-start; }
.nf-cal__day.is-today .nf-cal__num { background: var(--primary); color: #fff; min-width: 22px; height: 22px; padding: 0 5px; border-radius: 11px; display: inline-flex; align-items: center; justify-content: center; }
.nf-cal__evt {
    display: block; font-size: .72rem; line-height: 1.25; padding: .15rem .35rem; border-radius: 4px;
    background: var(--surface-2); color: var(--ink); text-decoration: none; border-left: 3px solid var(--border-strong);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nf-cal__evt b { font-variant-numeric: tabular-nums; }
/* Color del evento por ESTADO de la cita (coherente con los badges de día/lista): confirmada=verde,
   reprogramada=ámbar, solicitada=violeta, anulada=gris. Tokens weak+ink (adaptan a claro/oscuro). */
.nf-cal__evt--green { background: var(--success-weak); color: var(--success-ink); border-left-color: var(--success); }
.nf-cal__evt--amber { background: color-mix(in srgb, var(--amber-badge) 16%, var(--surface)); color: var(--ink); border-left-color: var(--amber-badge); }
.nf-cal__evt--blue  { background: var(--info-weak);    color: var(--accent-ink);  border-left-color: var(--primary); }
.nf-cal__evt--gray  { background: var(--surface-2);    color: var(--muted);       border-left-color: var(--border-strong); }
/* Solapamiento: prioriza el aviso ámbar sobre el color de estado (va después para ganar la cascada). */
.nf-cal__evt.is-overlap { background: color-mix(in srgb, var(--amber-badge) 16%, var(--surface)); color: var(--ink); border-left-color: var(--amber-badge); }
.nf-cal__evt:hover { filter: brightness(.97); text-decoration: none; }
/* Hitos del expediente (poder verificado / apostilla recibida): se distinguen de las citas (C9). */
.nf-cal__evt--hito { background: var(--page); color: var(--muted); border-left-style: dashed; border-left-color: var(--navy); }
@media (max-width: 680px) { .nf-cal { min-width: 640px; } }

/* Timeline / informe de actividad (EXP-02) */
.nf-timeline { list-style: none; margin: 1rem 0 0; padding: 0; position: relative; }
.nf-timeline::before { content: ''; position: absolute; left: 7px; top: 4px; bottom: 4px; width: 2px; background: var(--border); }
.nf-timeline__item { position: relative; display: flex; gap: .85rem; padding: .5rem 0; }
.nf-timeline__dot { position: relative; z-index: 1; flex: 0 0 auto; width: 16px; height: 16px; margin-top: .15rem; border-radius: 50%; background: var(--muted); border: 3px solid var(--surface); box-shadow: 0 0 0 1px var(--border); }
.nf-timeline__dot--blue  { background: var(--primary); }
.nf-timeline__dot--green { background: var(--success); }
.nf-timeline__dot--red   { background: var(--danger); }
.nf-timeline__dot--amber { background: #d97706; }
.nf-timeline__dot--slate { background: #7E7797; }
.nf-timeline__body { flex: 1; min-width: 0; }
.nf-timeline__head { display: flex; gap: .5rem; flex-wrap: wrap; align-items: baseline; }
.nf-timeline__title { font-weight: 700; color: var(--ink); }
.nf-timeline__detail { color: var(--muted); font-size: .88rem; }
.nf-timeline__meta { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-top: .15rem; }
.nf-timeline__meta time { font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Render del texto con formato sencillo */
.nf-fmt > :first-child { margin-top: 0; }
.nf-fmt > :last-child { margin-bottom: 0; }
.nf-fmt p { margin: .25rem 0; }
.nf-fmt ul { margin: .25rem 0; padding-left: 1.2rem; }
.nf-fmt li { margin: .1rem 0; }

/* ----------------------------------------------------------------------- */
/* Mensajes / feedback                                                     */
/* ----------------------------------------------------------------------- */
.nf-err { color: var(--danger-ink); font-size: .82rem; font-weight: 600; }
/* Captcha del registro. El widget lo pinta Cloudflare dentro de un iframe cuyo tamaño decide él, así que lo que
   se puede hacer desde aquí es DARLE SITIO: centrado y con marco.
   Suelto quedaba como una isla de 300 px pegada al borde izquierdo de una tarjeta mucho más ancha, sin relación
   con los campos de arriba —que sí ocupan el ancho— y sin nada que lo enmarcara. Con `data-size="flexible"` el
   propio widget se estira hasta el ancho de esta caja, así que la fila se lee como una más del formulario. */
.nf-captcha {
    margin-top: 1.1rem;
    padding: .7rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    /* Respaldo: si `flexible` no llega a aplicarse, el widget se queda en sus 300 px y esto lo centra en la
       caja en vez de dejarlo pegado al borde izquierdo (el iframe es inline). */
    text-align: center;
}
/* Bloque a ancho completo, NO elemento de un flex centrado. `data-size="flexible"` estira el widget hasta el
   ancho de su contenedor, pero como hijo de un flex con `justify-content:center` no se estira —lo decide su
   contenido— y se quedaba en 300 px. A ese ancho, «Verifique que es un ser humano» no cabe en las dos líneas
   del recuadro y Cloudflare lo RECORTA: el rótulo salía cortado por abajo. En inglés no pasaba, así que es de
   los defectos que solo se ven en el idioma que no se prueba. */
.nf-captcha .cf-turnstile { display: block; width: 100%; }
.nf-captcha iframe { max-width: 100%; }

/* Texto auxiliar y enlaces dentro de tarjetas */
.nf-card a { font-weight: 600; }

/* Números/datos tabulares (importes, referencias) */
.nf-num { font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------------------- */
/* Responsive                                                              */
/* ----------------------------------------------------------------------- */
/* Menú: bajo este ancho los enlaces se colapsan en un desplegable (hamburguesa). El umbral es alto
   porque el backoffice de administrador tiene muchos enlaces. */
@media (max-width: 860px) {
    .nf-nav { gap: .6rem 1rem; padding: .6rem 1rem; }
    .nf-nav__burger { display: inline-flex; }
    .nf-nav__links {
        display: none;
        flex-basis: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: .1rem;
        margin-top: .55rem;
        padding-top: .55rem;
        border-top: 1px solid rgba(255, 255, 255, .14);
    }
    .nf-nav__links.is-open { display: flex; }
    .nf-nav__links > a,
    .nf-nav__links .link { padding: .6rem .2rem; width: 100%; text-align: left; }
    .nf-nav__links form { width: 100%; }
    .nf-nav .spacer { display: none; }
    .nf-nav .user { display: block; border-left: 0; padding: .5rem .2rem 0; }
    /* La pastilla de idioma mantiene sus mitades lado a lado (no hereda el ancho completo). */
    .nf-lang { align-self: flex-start; margin: .45rem .2rem; }
    .nf-lang a { width: auto; padding: .3rem .8rem; text-align: center; }
}

@media (max-width: 640px) {
    body { font-size: 15px; }
    h1 { font-size: 1.55rem; }
    .nf-card { padding: 1.15rem 1.1rem; }
    .nf-wrap { margin-top: 1.1rem; }

    /* Botones en VERTICAL y a ancho completo: más cómodos de tocar y mejor aprovechados (#17). */
    /* Backoffice (toolbar de revisión) y área de cliente (.nf-doc__actions). */
    .nf-doc__toolbar,
    .nf-doc__actions { flex-direction: column; margin-left: 0; width: 100%; }
    .nf-doc__toolbar .btn,
    .nf-doc__actions .btn,
    .nf-doc__rejrow .btn { width: 100%; justify-content: center; }
    .nf-doc__rejrow { flex-direction: column; }
    .nf-doc__rejrow select { flex-basis: auto; width: 100%; }

    /* Grupos de acción de fila (bandejas, copias, usuarios, datos generados): apilados a ancho completo.
       `:not(.nf-venta__cifras)` porque la regla es para COLUMNAS DE BOTONES y se cuela en cualquier último
       <div> de una fila: a la rejilla de cifras del cuadro de mando le imponía `display:flex` en columna y
       le dejaba las nueve cifras una debajo de otra, ocupando pantalla y media. Excluirla aquí es más
       honesto que subirle la especificidad allí: lo que falla es el alcance de esta regla, no su prioridad. */
    .nf-row { align-items: stretch; }
    .nf-row > div:last-child:not(.ref):not(.grow):not(.nf-venta__cifras) { width: 100%; display: flex; flex-direction: column; gap: .4rem; }
    .nf-row > div:last-child .btn,
    .nf-row > div:last-child .nf-confirm,
    .nf-row > div:last-child .nf-confirm > button { width: 100%; justify-content: center; }

    /* Selectores en bloque para que no compriman. */
    .nf-radios { flex-direction: column; }
    .nf-radio { width: 100%; }
    .nf-tabs { width: 100%; }
    .nf-tab { flex: 1; justify-content: center; }

    /* Botones de acción principales a ancho completo y con el contenido centrado (apilados). */
    .nf-card form button[type="submit"],
    .nf-card > p > button,
    .nf-card > p > .btn,
    form > p > button { display: flex; width: 100%; justify-content: center; text-align: center; }
}

/* Móvil: los botones de acción ocupan el 100% del ancho siempre que sea posible (más cómodos de tocar).
   Scopeado a .nf-wrap para no afectar a la barra de navegación. Se excluyen los controles compactos o
   en línea: segmentados del calendario, barra del editor, pestañas, confirmaciones sí/no, iconos (×),
   enlaces de texto y paginación. */
@media (max-width: 640px) {
    .nf-wrap button,
    .nf-wrap .btn { width: 100%; justify-content: center; }
    .nf-wrap .nf-confirm { width: 100%; display: flex; }

    /* Excepciones: conservan su ancho natural / disposición en línea. */
    .nf-wrap .nf-cal__views button,
    .nf-wrap .nf-cal__nav button,
    .nf-wrap .nf-editor__bar button,
    .nf-wrap .nf-tab,
    .nf-wrap .nf-link,
    .nf-wrap .nf-modal-close,
    .nf-wrap .nf-pagination button,
    .nf-wrap .nf-pagination .btn,
    .nf-wrap .nf-confirm__btns button { width: auto; }

    /* La «×» de borrar nota interna sigue siendo compacta. */
    .nf-note-item .nf-confirm { width: auto; display: inline-flex; }
    .nf-note-item .nf-note-del { width: auto; }
}

/* Targets táctiles: en dispositivos de puntero grueso (táctil), los botones compactos alcanzan los 44px
   recomendados (en escritorio con ratón conservan su tamaño compacto). */
@media (pointer: coarse) {
    .btn-sm, .nf-back { min-height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; }
}

/* Asistente por pasos del cliente (UX guiada). */
.nf-stepper { display: flex; align-items: flex-start; margin: 0 0 1.4rem; padding: 1rem .2rem .55rem; overflow-x: auto; }
.nf-stepper .nf-step {
    flex: 1 1 0; min-width: 74px; position: relative;
    display: flex; flex-direction: column; align-items: center; gap: .5rem;
    color: var(--muted); font-size: .76rem; text-align: center;
}
/* Línea conectora hacia el paso anterior (detrás de los círculos); se rellena al alcanzar el paso. */
.nf-stepper .nf-step::before {
    content: ""; position: absolute; top: 16px; z-index: 0;
    left: calc(-50% + 17px); width: calc(100% - 34px); height: 2px; background: var(--border-strong);
}
.nf-stepper .nf-step:first-child::before { display: none; }
.nf-stepper .nf-step--hecho::before,
.nf-stepper .nf-step--actual::before { background: var(--primary); }
.nf-stepper .nf-step__dot {
    position: relative; z-index: 1; flex: none;
    width: 34px; height: 34px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface); border: 2px solid var(--border-strong); color: var(--muted);
}
/* Rótulo del paso: era .76rem heredado del contenedor y quedaba por debajo de todo lo demás de la página;
   a .8rem con algo más de interlínea se lee sin esfuerzo y sigue sin competir con los títulos. */
.nf-stepper .nf-step__label { font-size: .8rem; line-height: 1.3; }
/* Paso ABRIBLE (ya alcanzado): es un <button>, así que hay que deshacer el botón de marca —degradado, alto
   mínimo, sombra— y dejarlo idéntico al paso normal, solo que pulsable. */
.nf-stepper button.nf-step {
    background: none; border: 0; padding: 0; margin: 0; box-shadow: none;
    font: inherit; font-size: .76rem; min-height: 0; letter-spacing: normal; cursor: pointer;
}
.nf-stepper button.nf-step:hover { background: none; filter: none; transform: none; box-shadow: none; }
/* Al pasar por encima se marca con color y peso, no con subrayado: subrayar dentro del stepper lo hacía
   parecer un enlace de texto suelto en medio del recorrido. */
.nf-stepper .nf-step--abrible:hover { color: var(--accent-ink); }
.nf-stepper .nf-step--abrible:hover .nf-step__dot { border-color: var(--primary); }
.nf-stepper .nf-step--abrible:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: var(--r-sm); }
/* Paso que se está CONSULTANDO cuando no es el actual: anillo tenue para saber qué se está mirando. */
.nf-stepper .nf-step--viendo:not(.nf-step--actual) .nf-step__dot { box-shadow: 0 0 0 4px var(--primary-weak); border-color: var(--primary); }
/* Aviso de que se consulta un paso anterior + vuelta al actual. */
.nf-paso-volver {
    display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
    margin: 1rem 0 .2rem; padding: .55rem .8rem;
    background: var(--primary-weak); border-radius: var(--r-sm);
    font-size: .86rem; font-weight: 600; color: var(--accent-ink);
}
.nf-paso-volver .btn { margin-left: auto; }

/* Paso «Información»: los datos del expediente dentro de la guía. Se les da aire —la tabla venía apretada y
   con el valor casi tan marcado como su rótulo— y las acciones van juntas en una fila, con una sola
   principal: editar. «Ver pagos y factura» es secundaria y llevaba el mismo peso visual. */
.nf-guia-info .nf-data td { font-size: .92rem; line-height: 1.45; padding-top: .6rem; padding-bottom: .6rem; }
.nf-guia-info .nf-data td:first-child { font-size: .68rem; color: var(--muted); letter-spacing: .05em; }
.nf-guia-info .nf-data td:last-child { font-weight: 600; }
.nf-guia-info .nf-data td:last-child .meta { font-size: .84rem; }
.nf-guia-info__acciones { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: 1rem; }
.nf-guia-info__bloqueo { margin: .6rem 0 0; font-size: .86rem; line-height: 1.5; color: var(--muted); }
@media (max-width: 640px) {
    .nf-guia-info__acciones .btn { width: 100%; justify-content: center; }
}
.nf-stepper .nf-step--hecho { color: var(--accent-ink); }
.nf-stepper .nf-step--hecho .nf-step__dot { background: var(--grad); border-color: transparent; color: #fff; }
.nf-stepper .nf-step__dot .nf-ico { width: 18px; height: 18px; }
.nf-stepper .nf-step--actual { color: var(--accent-ink); font-weight: 700; }
.nf-stepper .nf-step--actual .nf-step__dot { background: var(--grad); border-color: transparent; color: #fff; box-shadow: 0 0 0 4px var(--primary-weak); animation: pbStepPulse 2s ease-in-out infinite; }
/* Marcador del paso ACTUAL: punto blanco central + halo con pulso suave («estás aquí»). */
.nf-stepper .nf-step--actual .nf-step__dot::after { content: ""; width: 11px; height: 11px; border-radius: 50%; background: #fff; }
@keyframes pbStepPulse { 0%, 100% { box-shadow: 0 0 0 4px var(--primary-weak); } 50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--primary) 16%, transparent); } }
@media (prefers-reduced-motion: reduce) { .nf-stepper .nf-step--actual .nf-step__dot { animation: none; } }
.nf-stepper .nf-step--pendiente { color: var(--muted); }
/* «Lo hace el despacho» bajo el rótulo del paso. Venía como `style` en línea desde que el stepper era una
   sola vista; al salir a componente compartido se pasa a clase, que es lo que permite ajustarlo en un sitio
   para las dos pantallas que lo pintan. */
.nf-step__quien { display: block; font-weight: 400; opacity: .72; font-size: .72rem; }

/* Texto libre del cliente dentro de una ficha de datos (descripción del motivo, justificación de
   residencia). Son hasta 500 caracteres escritos por él: se respetan sus saltos de línea y se parten las
   palabras largas, para que un pegote sin espacios no ensanche la tabla y saque la ficha de la pantalla. */
.nf-data__libre { white-space: pre-line; overflow-wrap: anywhere; }
/* Matiz pegado a un valor de la tabla de datos: en su propio renglón y atenuado, para que se lea como una nota
   sobre el dato y no como parte del dato. Lo usa el consulado mientras es el de partida y no el del cliente. */
.nf-data__nota { display: block; margin-top: .15rem; }

/* =========================================================================
   F2 — Shell de backoffice con barra lateral (sidebar) + topbar.
   Solo para usuarios de backoffice; cliente y público siguen con .nf-nav.
   ========================================================================= */
.nf-shell { display: flex; flex: 1 0 auto; align-items: stretch; }

.nf-side {
    position: sticky; top: 0; align-self: flex-start;
    width: 240px; flex: 0 0 240px; height: 100vh; height: 100dvh;
    display: flex; flex-direction: column; gap: .15rem;
    padding: .9rem .7rem;
    background: var(--surface); border-right: 1px solid var(--border);
    overflow-y: auto;
}
.nf-side__brand {
    display: flex; align-items: center; gap: .55rem;
    font-family: var(--font-serif); font-weight: 700; font-size: 1.1rem; letter-spacing: .2px;
    color: var(--text); padding: .3rem .5rem 1rem; border: 0;
}
.nf-side__brand:hover { text-decoration: none; }
.nf-side__brand img { height: 26px; width: auto; }
.nf-side__logoicono { display: none; }        /* solo plegada; ver el bloque de la barra compacta */
/* Plegar la barra: vive en la CABECERA, junto al resto de controles de la vista (tema, idioma). Dentro de la
   barra desaparecería con ella al pasar a estrecho. Oculto por defecto y visible solo en ancho (ver abajo). */
.nf-topbar__plegar {
    display: none; flex: 0 0 auto; padding: .4rem; border: 0; border-radius: var(--r-sm);
    background: transparent; color: var(--muted); cursor: pointer; box-shadow: none;
    align-items: center; justify-content: center;
}
.nf-topbar__plegar:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
.nf-side__nav { display: flex; flex-direction: column; gap: .25rem; }
.nf-side__nav a {
    display: flex; align-items: center; gap: .65rem;
    padding: .6rem .7rem; margin: .1rem .4rem; border-radius: var(--r-pill);
    color: var(--muted); font-size: .9rem; font-weight: 600; text-decoration: none;
    transition: background .15s ease, color .15s ease;
}
.nf-side__nav a .nf-ico { flex: 0 0 auto; opacity: .85; }
.nf-side__nav a:hover { background: var(--primary-weak); color: var(--accent-ink); text-decoration: none; }
.nf-side__nav a:hover .nf-ico { opacity: 1; }
.nf-side__nav a.is-active { background: var(--grad); color: #fff; box-shadow: var(--shadow-sm); }
.nf-side__nav a.is-active .nf-ico { opacity: 1; color: #fff; }
.nf-side__nav .nf-dot { margin-left: auto; }
/* Título de sección del menú lateral: agrupa los enlaces (Trabajo / Configuración / …). */
.nf-side__grouptitle { margin: .9rem .3rem .15rem; font-size: .68rem; font-weight: 800; text-transform: uppercase; letter-spacing: .07em; color: var(--accent-ink); }
.nf-side__grouptitle:first-child { margin-top: .1rem; }

/* Grupo COLAPSABLE del menú de backoffice. La cabecera conserva el aspecto del título de sección que sustituye
   —mismo tamaño, peso y color— para que plegar no cambie el ritmo visual del menú; lo único que se añade es el
   chevron y que se pueda pulsar. */
.nf-navgrupo__cab {
    width: 100%; display: flex; align-items: center; gap: .4rem;
    margin: .9rem .3rem .15rem; padding: .15rem .2rem;
    background: transparent; border: 0; box-shadow: none; cursor: pointer;
    font-size: .68rem; font-weight: 800; text-transform: uppercase; letter-spacing: .07em;
    color: var(--accent-ink); text-align: left;
}
.nf-navgrupo:first-child .nf-navgrupo__cab { margin-top: .1rem; }
.nf-navgrupo__cab:hover { background: var(--primary-weak); border-radius: var(--r-xs); transform: none; filter: none; }
.nf-navgrupo__cab .nf-side__label { flex: 1; min-width: 0; }
.nf-navgrupo__chev { display: inline-flex; transition: transform .15s ease; }
.nf-navgrupo__chev.is-open { transform: rotate(90deg); }

/* Cabecera de caso familiar colapsable: chevron + nombre + resumen + acción. */
.nf-fam-head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.nf-fam-chevron { flex: 0 0 auto; padding: .25rem; background: transparent; border: 0; color: var(--muted); cursor: pointer; box-shadow: none; }
.nf-fam-chevron:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
.nf-fam-chevron__ico { display: inline-flex; transition: transform .15s ease; }
.nf-fam-chevron__ico.is-open { transform: rotate(90deg); }
/* Pie: usuario + salir, pegados al fondo. */
.nf-side__foot { margin-top: auto; padding-top: .7rem; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: .5rem; }
/* Ficha del usuario actual: avatar con iniciales + nombre destacado + rol. */
.nf-side__me { display: flex; align-items: center; gap: .55rem; padding: .4rem .5rem; border-radius: var(--r-sm); background: var(--primary-weak); }
.nf-side__avatar { flex: 0 0 auto; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: var(--grad); color: #fff; font-size: .82rem; font-weight: 800; letter-spacing: .02em; box-shadow: var(--shadow-sm); }
/* El nombre del cliente es un ENLACE a «Mi cuenta»: la sección que reúne sus herramientas y sus datos. */
.nf-side__me--link { text-decoration: none; transition: background .15s ease; }
.nf-side__me--link:hover { background: var(--border-strong); text-decoration: none; }
.nf-side__me--link.is-active { background: var(--grad); box-shadow: var(--shadow-sm); }
.nf-side__me--link.is-active .nf-side__name, .nf-side__me--link.is-active .nf-side__role { color: #fff; }
.nf-side__me--link.is-active .nf-side__avatar { background: var(--surface); color: var(--accent-ink); }
.nf-side__mechev { flex: 0 0 auto; margin-left: auto; color: var(--muted); }
.nf-side__me--link.is-active .nf-side__mechev { color: #fff; }
.nf-side__me--link .nf-dot { margin-left: auto; }
.nf-side__me--link .nf-dot + .nf-side__mechev { margin-left: .35rem; }
/* EL PIE DEL USUARIO ES SOLO EL CÍRCULO CON LAS INICIALES (decisión de producto, 31/08). El nombre y el rol
   no se pintan al lado ni con la barra desplegada.

   Pero el marcado NO se borra: se oculta A LA VISTA conservándolo para el lector de pantalla, con la misma
   técnica que ya usaba la barra plegada. Un enlace cuyo texto es un círculo con dos letras se anuncia como
   «enlace» y nada más, y ahí es donde se entra a la propia cuenta. El `title` cubre el ratón. */
.nf-side__meinfo {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.nf-side__me { justify-content: center; gap: 0; position: relative; }
.nf-side__mechev { display: none; }
/* El aviso de no leídas pasa a ser un punto SOBRE el avatar: con `margin-left:auto` en una fila centrada se
   salía de la pastilla. */
.nf-side__me .nf-dot { position: absolute; top: .1rem; right: .1rem; margin: 0; }
.nf-side__name { font-weight: 700; font-size: .9rem; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nf-side__role { font-size: .72rem; font-weight: 600; color: var(--accent-ink); }
.nf-side__foot form { margin: 0; }
.nf-side__foot button.link {
    width: 100%; display: flex; align-items: center; gap: .6rem; justify-content: flex-start;
    background: transparent; color: var(--muted); border: 1px solid var(--border); box-shadow: none;
    border-radius: var(--r-sm); font-weight: 600; font-size: .88rem; padding: .55rem .7rem; cursor: pointer;
}
.nf-side__foot button.link:hover { background: var(--danger-weak); color: var(--danger-ink); border-color: transparent; transform: none; filter: none; }

.nf-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.nf-topbar {
    position: sticky; top: 0; z-index: 30;
    display: flex; align-items: center; gap: .8rem;
    padding: .6rem 1.2rem; min-height: 56px;
    background: var(--surface); border-bottom: 1px solid var(--border);
}
.nf-topbar .spacer { margin-left: auto; }
.nf-topbar__burger {
    display: none; align-items: center; justify-content: center;
    width: 42px; min-height: 38px; padding: 0;
    background: var(--primary-weak); color: var(--accent-ink);
    border: 1px solid var(--border-strong); border-radius: var(--r-sm); box-shadow: none;
}
.nf-topbar__burger:hover { background: var(--border-strong); }
/* Selector de idioma y usuario sobre topbar CLARA (los tokens por defecto asumen nav oscura). */
.nf-topbar .nf-lang { border-color: var(--border-strong); }
.nf-topbar .nf-lang a { color: var(--muted); }
.nf-topbar .nf-lang a + a { border-left-color: var(--border); }
.nf-topbar .nf-lang a:hover { background: var(--primary-weak); color: var(--accent-ink); }
.nf-topbar .nf-lang a.active { background: var(--grad); color: #fff; }

/* Cabecera de la ficha de datos: el título a la izquierda y su acción a la derecha, en la misma línea. */
.nf-datoscab { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin-bottom: .8rem; }

/* Cabecera del bloque «devolver el expediente al cliente»: el texto a la izquierda y su disparador a la
   derecha, como el resto de avisos con acción. */
.nf-reabrir__cab { display: flex; align-items: flex-start; gap: .8rem; flex-wrap: wrap; }
.nf-reabrir__cab > div { flex: 1 1 16rem; min-width: 0; }

/* Cotejo OCR del pasaporte: cabecera plegable. El disparador es un botón de verdad —era un `<summary>`, que
   trae su propio triángulo del navegador y no casa con el resto de la ficha— y se pinta como una línea de
   texto, no como un botón: lo que importa es el veredicto, no el control. */
.nf-cotejo__toggle {
    display: inline-flex; align-items: center; gap: .4rem; flex-wrap: wrap;
    padding: .15rem 0; border: 0; background: none; box-shadow: none; cursor: pointer;
    font: inherit; color: var(--text); text-align: left;
}
.nf-cotejo__toggle:hover { background: none; transform: none; filter: none; }
.nf-cotejo__toggle:hover .nf-cotejo__estado { text-decoration: underline; }
.nf-cotejo__chev { display: inline-flex; color: var(--muted); transition: transform .15s ease; }
.nf-cotejo__chev.is-open { transform: rotate(90deg); }
/* El veredicto se lee con el mismo peso que el resto de la ficha, no en gris pequeño: es la conclusión. */
.nf-cotejo__estado { font-size: .88rem; font-weight: 600; color: var(--text); }

/* Botón de tema (claro/oscuro). Variante clara (topbar) y oscura (.nf-nav pública). */
.nf-theme-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; min-height: 36px; padding: 0; font-size: 1.05rem; line-height: 1;
    background: transparent; color: var(--muted);
    border: 1px solid var(--border-strong); border-radius: var(--r-pill); box-shadow: none; cursor: pointer;
}
.nf-theme-btn:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
.nf-nav .nf-theme-btn { color: rgba(255, 255, 255, .82); border-color: rgba(255, 255, 255, .4); }
.nf-nav .nf-theme-btn:hover { background: rgba(255, 255, 255, .14); color: #fff; }
/* Sol y luna en SVG incrustado, no glifos: «◐» y «☀» los dibujaba la fuente del sistema, así que el
   grosor de trazo no casaba con el resto de la interfaz y en varias plataformas salían como emoji a
   todo color. Heredan `currentColor`, que es lo que hace que la misma pieza sirva sobre la barra clara
   del backoffice y sobre la oscura de la pública sin una regla de color por sitio. */
/* El tamaño va SIN `display`: `.nf-theme-btn svg` pesa (0,1,1) y `.nf-theme-btn__sun` solo (0,1,0), así
   que un `display:block` aquí ganaba a la regla que oculta el icono que no toca — y salían la luna y el
   sol A LA VEZ. Qué cara se ve lo decide únicamente el par de reglas de abajo. */
.nf-theme-btn svg { width: 1.05rem; height: 1.05rem; }

/* Reporte de incidencias del personal interno (`<x-soporte>`), en la cabecera. Estuvo flotando en la esquina
   inferior derecha y tapaba la acción de la última fila: un elemento fijo acaba encima de ALGO en cuanto la
   página desplaza. Toma prestado el aspecto del botón de tema —mismo alto, mismo borde— porque es su vecino
   y son la misma clase de control; lo único que añade es la etiqueta. */
/* Buscador global (⌘K). El diálogo es el MODAL DE LA APP (`nf-modal`) y las filas son `nf-row`, las de las
   bandejas: aquí solo va lo que no existía ya —el botón de la cabecera, el campo y el pie de teclas—. La
   primera versión traía velo, caja y botones propios, y era la única pantalla con esas formas. */
.nf-buscador { position: relative; flex: 1 1 auto; max-width: 20rem; min-width: 0; }
.nf-buscador__btn {
    display: flex; align-items: center; gap: .45rem; width: 100%;
    min-height: 36px; padding: 0 .6rem; cursor: pointer; text-align: left;
    font-size: .85rem; font-weight: 500; color: var(--muted);
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-pill);
    box-shadow: none;
}
.nf-buscador__btn:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
.nf-buscador__ph { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Tecla impresa. Compartida por el botón y el pie del diálogo. */
.nf-kbd {
    flex: 0 0 auto; display: inline-block; padding: .1rem .35rem; min-width: 1.5em; text-align: center;
    font: 700 .7rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--muted); background: var(--surface-2); border: 1px solid var(--border-strong);
    border-radius: 6px; box-shadow: 0 1px 0 var(--border-strong);
}

/* La caja: más baja que la del visor de documentos —esto es una lista corta, no un PDF— y anclada arriba,
   donde el ojo ya está cuando se teclea el atajo. */
.nf-modal-box--buscador {
    width: min(44rem, 100%); height: auto; max-height: min(72vh, 100%);
    align-self: flex-start; margin-top: 8vh;
    /* Fondo y tinta EXPLÍCITOS: `.nf-modal-box` fija `background:#fff` y el visor de documentos vive con
       ello, pero aquí dentro va texto de la app —título, nombres, correos— y en tema oscuro se quedaba gris
       sobre gris. Comprobado en los dos temas. */
    background: var(--surface); color: var(--ink);
}
.nf-modal-box--buscador .nf-modal-head strong { color: var(--ink); }

.nf-buscador__campo {
    display: flex; align-items: center; gap: .55rem; padding: .7rem 1.1rem;
    border-bottom: 1px solid var(--border); color: var(--muted);
}
/* Sin marco propio: el marco es la franja. Un input con borde dentro de una caja con borde son dos cajas. */
.nf-buscador__campo input {
    flex: 1; min-width: 0; border: 0; background: transparent; padding: .2rem 0;
    font-size: 1.05rem; color: var(--ink);
}
.nf-buscador__campo input:focus { outline: none; box-shadow: none; }
.nf-buscador__cargando { flex: 0 0 auto; font-size: .8rem; color: var(--muted); }

.nf-buscador__res { overflow-y: auto; padding: .6rem 1.1rem 1rem; }
.nf-buscador__grupo {
    margin: .5rem 0 .1rem; font-size: .72rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .05em; color: var(--muted);
}
.nf-buscador__pista { margin: .8rem .2rem; }

/* Fila de resultado: la de las bandejas, con la referencia primero y la flecha al final. */
.nf-buscador__item { display: flex; align-items: center; gap: .6rem; text-decoration: none; color: var(--ink); }
.nf-buscador__item .nf-ico:last-child { margin-left: auto; color: var(--muted); flex: 0 0 auto; }
.nf-buscador__nombre { font-weight: 700; white-space: nowrap; }
.nf-buscador__quien { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
/* `is-sel` la pone el teclado y el hover el ratón: tienen que verse IGUAL, o navegar con flechas se siente
   distinto de navegar con el ratón sobre la misma lista. Se reutiliza el hover de `.nf-rows > .nf-row`. */
.nf-rows > .nf-row.is-sel {
    /* Marcada de verdad: relleno violeta suave y una barra a la izquierda. El primer intento reutilizaba el
       hover —un lavado al 45 %— y con tres filas seguidas no se distinguía cuál estaba marcada, que es
       justo lo único que el teclado necesita comunicar. */
    background: var(--primary-weak);
    border-color: var(--accent-ink);
    box-shadow: inset 3px 0 0 var(--accent-ink), var(--shadow-sm);
}

.nf-buscador__pie {
    margin: 0; padding: .5rem 1.1rem; display: flex; gap: .35rem; align-items: center; flex-wrap: wrap;
    font-size: .78rem; color: var(--muted); border-top: 1px solid var(--border); background: var(--surface-2);
}
@media (max-width: 700px) {
    /* En estrecho la cabecera ya lleva menú, avisos, soporte, tema e idioma: el buscador queda en icono. */
    .nf-buscador { flex: 0 0 auto; max-width: none; }
    .nf-buscador__ph, .nf-buscador__btn .nf-kbd { display: none; }
    .nf-buscador__btn { width: 40px; padding: 0; justify-content: center; }
    .nf-modal-box--buscador { margin-top: 2vh; max-height: 90vh; }
}

/* Centro de avisos de la cabecera. Comparte mecanismo con el botón de soporte —panel colgado de la barra
   pegajosa, no flotando sobre el contenido— y por eso comparte casi todo el CSS; lo propio es la campana con
   su globo y las líneas del panel. */
.nf-avisos { position: relative; flex: 0 0 auto; }
.nf-avisos__btn {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: 40px; min-height: 36px; padding: 0; cursor: pointer;
    background: transparent; color: var(--muted);
    border: 1px solid var(--border-strong); border-radius: var(--r-pill); box-shadow: none;
}
.nf-avisos__btn:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
/* Con algo urgente dentro, la campana misma se tiñe: el globo dice CUÁNTO y esto dice DE QUÉ CLASE, que es
   lo que decide si se abre ahora o después de terminar lo que se está haciendo. */
.nf-avisos__btn.is-urgente { color: var(--danger-ink); border-color: color-mix(in srgb, var(--danger-ink) 45%, transparent); }
.nf-avisos__btn[aria-expanded="true"] { background: var(--primary); color: #fff; border-color: transparent; }
/* El número, encima de la campana y no al lado: al lado se lee como un elemento aparte de la barra. */
.nf-avisos__n {
    position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 .25rem;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: .68rem; font-weight: 700; line-height: 1; color: #fff;
    background: var(--accent); border-radius: var(--r-pill); border: 2px solid var(--surface);
}
.nf-avisos__panel {
    position: absolute; right: 0; top: calc(100% + .55rem); z-index: 40;
    width: min(22rem, 88vw); padding: .9rem; font-size: .9rem; text-align: left; font-weight: 400;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--shadow-lg);
}
/* Cada línea es un enlace ENTERO: lo que se quiere al leerla es ir allí. */
.nf-avisos__linea {
    display: flex; align-items: center; gap: .5rem; padding: .5rem .6rem; margin-bottom: .3rem;
    color: var(--ink); text-decoration: none;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-xs);
}
/* Un color por CATEGORÍA: en un panel que se abre veinte veces al día, el ojo aprende «la roja» y «la rosa»
   antes que las palabras. Los seis tonos salen de la paleta de los badges, así que significan aquí lo mismo
   que en el resto de la aplicación, y todos tienen variante en tema oscuro.

   Se tiñen el borde izquierdo, el icono y la cifra; el fondo se deja en un lavado muy suave. Seis fondos
   saturados en 22 rem serían una tarta, y con todo gritando no se distingue lo que urge. */
.nf-avisos__linea--rojo    { border-left: 3px solid var(--danger);      background: var(--danger-weak); }
.nf-avisos__linea--rosa    { border-left: 3px solid var(--accent);      background: color-mix(in srgb, var(--accent) 10%, var(--surface)); }
.nf-avisos__linea--ambar   { border-left: 3px solid var(--amber-badge); background: var(--warning-weak); }
.nf-avisos__linea--violeta { border-left: 3px solid var(--info);        background: var(--info-weak); }
.nf-avisos__linea--verde   { border-left: 3px solid var(--success);     background: var(--success-weak); }
.nf-avisos__linea--pizarra { border-left: 3px solid var(--border-strong); background: var(--surface-2); }

.nf-avisos__linea--rojo .nf-ico,    .nf-avisos__linea--rojo .nf-avisos__cifra    { color: var(--danger-ink); }
.nf-avisos__linea--rosa .nf-ico,    .nf-avisos__linea--rosa .nf-avisos__cifra    { color: var(--accent); }
.nf-avisos__linea--ambar .nf-ico,   .nf-avisos__linea--ambar .nf-avisos__cifra   { color: var(--warning-ink); }
.nf-avisos__linea--violeta .nf-ico, .nf-avisos__linea--violeta .nf-avisos__cifra { color: var(--info); }
.nf-avisos__linea--verde .nf-ico,   .nf-avisos__linea--verde .nf-avisos__cifra   { color: var(--success-ink); }
.nf-avisos__linea--pizarra .nf-ico, .nf-avisos__linea--pizarra .nf-avisos__cifra { color: var(--muted); }

/* Al pasar por encima se levanta el propio tono en vez de sustituirlo por el violeta de siempre: si el hover
   pisara el color, la línea perdería justo aquello por lo que se reconoce. */
/* Una sola regla de hover, y NO lava el fondo a violeta: había otra antes que lo hacía y borraba el color de
   categoría justo al pasar por encima —o sea, en el momento en que se está mirando la línea. */
.nf-avisos__linea:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.nf-avisos__linea:hover .nf-avisos__txt { text-decoration: underline; }
.nf-avisos__txt { flex: 1; min-width: 0; }
/* La cifra repetida al final: el texto ya la dice, pero en una columna alineada se comparan de un vistazo. */
.nf-avisos__cifra { font-weight: 700; font-variant-numeric: tabular-nums; }
.nf-avisos__vacio { display: flex; align-items: center; gap: .4rem; margin: .2rem 0 0; color: var(--success-ink); }
.nf-avisos__pie { margin-top: .6rem; padding-top: .5rem; border-top: 1px solid var(--border); }
@media (max-width: 700px) {
    /* Igual que el soporte: sin `position` propia, el panel se cuelga de la cabecera y no se sale por la
       izquierda al estar el botón a media barra. */
    .nf-avisos { position: static; }
    .nf-avisos__panel { left: .7rem; right: .7rem; width: auto; }
}

.nf-soporte { position: relative; flex: 0 0 auto; }
.nf-soporte__btn {
    display: inline-flex; align-items: center; gap: .4rem;
    min-height: 36px; padding: 0 .75rem; font-size: .85rem; font-weight: 600; line-height: 1;
    /* CON COLOR, y no transparente en gris apagado como sus vecinos. Nació copiando al botón de tema, pero no
       son la misma clase de control: el tema y el idioma son ajustes que se tocan una vez, y el soporte es una
       acción que hay que encontrar deprisa —justo cuando algo acaba de fallar y quien mira está molesto—. En
       gris sobre la barra blanca no se veía. El relleno violeta suave lo saca del fondo sin gritar más que el
       contenido, y es el mismo par de tokens que ya usan los chips de la marca. */
    background: var(--primary-weak); color: var(--accent-ink);
    border: 1px solid color-mix(in srgb, var(--accent-ink) 35%, transparent);
    border-radius: var(--r-pill); box-shadow: none; cursor: pointer;
}
/* Al pasar por encima se rellena del todo: el reposo ya lleva color, así que el hover tiene que subir un
   escalón de verdad para seguir leyéndose como respuesta al puntero. */
.nf-soporte__btn:hover { background: var(--primary); color: #fff; border-color: transparent; transform: none; filter: none; }
.nf-soporte__btn[aria-expanded="true"] { background: var(--primary); color: #fff; border-color: transparent; }
/* El panel cuelga de la cabecera, que es pegajosa y ya está por encima del contenido: no necesita salirse de
   ella. Y solo aparece cuando alguien lo abre, así que taparle algo al contenido es lo que se ha pedido. */
.nf-soporte__panel {
    position: absolute; right: 0; top: calc(100% + .55rem); z-index: 40;
    width: min(21rem, 86vw); padding: .9rem; font-size: .9rem; text-align: left; font-weight: 400;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--shadow-lg);
}
.nf-soporte__panel textarea { width: 100%; resize: vertical; }
/* A la DERECHA, como el resto de acciones de la app; el enlace de salida se queda a la izquierda con
   `margin-right:auto` porque no es una acción sobre lo que se está escribiendo, es irse a otra pantalla. */
.nf-soporte__acciones { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: .6rem; justify-content: flex-end; align-items: center; }
/* El panel mide 21 rem: con el enlace y los dos botones en la misma línea, «Enviar» se descolgaba solo a
   una segunda fila. El enlace se lleva su propio renglón y los botones quedan juntos, alineados a la
   derecha, que es donde se los busca. */
.nf-soporte__acciones > .nf-link { flex: 1 0 100%; margin-bottom: .1rem; }
/* Respuestas rápidas de la mensajería. Reutiliza `.nf-chip` de los filtros: son el mismo gesto —pulsar una
   pastilla— y no hay razón para que se vean distintas. Solo cambia que aquí el texto puede ser largo. */
.nf-rapidas { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin: 0 0 .5rem; }
.nf-rapidas__lbl { font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.nf-rapidas .nf-chip { font-weight: 500; max-width: 100%; }

/* Filtros rápidos: los valores más usados de un filtro, como botones con su recuento dentro. Ver
   `components/filtros-rapidos.blade.php`. Se pintan por encima de la lista, donde cae la vista al entrar. */
.nf-chips { display: flex; gap: .4rem; flex-wrap: wrap; margin: 0 0 .8rem; }
.nf-chip {
    display: inline-flex; align-items: center; gap: .4rem;
    min-height: 34px; padding: 0 .7rem; font-size: .85rem; font-weight: 600; line-height: 1;
    color: var(--ink); background: var(--surface);
    border: 1px solid var(--border-strong); border-radius: var(--r-pill); cursor: pointer;
}
.nf-chip:hover { background: var(--primary-weak); color: var(--accent-ink); transform: none; filter: none; }
.nf-chip.is-active { background: var(--primary); color: #fff; border-color: transparent; }
/* El recuento: pastilla dentro de la pastilla. En el activo hereda el fondo blanco translúcido para que se
   siga leyendo sobre el violeta sin cambiar de color y parecer otro control. */
.nf-chip__n {
    display: inline-block; min-width: 1.4em; padding: .1rem .35rem; border-radius: var(--r-pill);
    font-size: .78rem; font-weight: 700; text-align: center;
    background: var(--surface-2); color: var(--muted);
}
.nf-chip.is-active .nf-chip__n { background: rgba(255, 255, 255, .22); color: #fff; }
.nf-chip:hover .nf-chip__n { background: var(--surface); color: var(--accent-ink); }

/* Confirmación de que la incidencia quedó registrada, dentro del propio panel (ver soporte.blade.php). */
.nf-soporte__ok {
    display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
    margin: 0 0 .5rem; padding: .4rem .55rem; font-size: .85rem;
    color: var(--success-ink); background: var(--success-weak); border: 1px solid var(--success-ink); border-radius: var(--r-xs);
}
/* En estrecho la cabecera lleva ya el menú, el tema y el idioma: la etiqueta se va y queda el icono, del
   mismo tamaño que sus vecinos. El nombre no se pierde, sigue en `aria-label` y en `title`. */
@media (max-width: 700px) {
    .nf-soporte__txt { display: none; }
    .nf-soporte__btn { width: 40px; padding: 0; justify-content: center; }

    /* Y el panel pasa a colgar de la CABECERA en vez de su botón: a 420 px el botón queda a media barra
       —tema e idioma a su derecha— y 21 rem colgados de su borde derecho se salían por la izquierda, con el
       texto cortado. Basta quitarle a `.nf-soporte` su `position`: la cabecera es `sticky`, o sea que ya está
       posicionada, y pasa a ser ella el marco de referencia. Así el ancho sale de la ventana y no hay que
       escribir en ningún sitio cuánto mide la barra. */
    .nf-soporte { position: static; }
    .nf-soporte__panel { left: .7rem; right: .7rem; width: auto; }
}

/* Un control y SU ACCIÓN en la misma línea.
 *
 * El patrón estaba escrito a mano —`display:flex;align-items:flex-end`— en tres sitios y ausente en otros
 * doce, donde el botón caía a su propio renglón debajo de un campo de dos centímetros. Eso deja el formulario
 * más alto de lo que necesita y, sobre todo, separa el control de lo que hace con él.
 *
 * `align-items:flex-end` alinea por el BORDE INFERIOR y no por el centro: el control suele llevar su rótulo
 * encima, así que centrarlos dejaría el botón flotando a media altura del par rótulo+campo.
 *
 * El mensaje de error ocupa el ancho entero para caer DEBAJO de su campo. Si compartiera línea empujaría el
 * botón fuera de la tarjeta en cuanto el texto fuese largo. */
.nf-fieldrow {
    display: flex;
    gap: .6rem;
    align-items: flex-end;
    flex-wrap: wrap;
    margin-top: .9rem;
}
.nf-fieldrow > * { margin-top: 0; margin-bottom: 0; }
.nf-fieldrow label { display: block; margin-bottom: .25rem; }
.nf-fieldrow button { flex: none; }
.nf-fieldrow .nf-err { flex-basis: 100%; margin: .25rem 0 0; }

/* Variante para cuando el control NO lleva rótulo encima (una casilla, un interruptor): ahí sí se alinea
   por el centro, que es donde está el texto de la casilla. */
.nf-fieldrow--centro { align-items: center; }

/* La ACCIÓN de una fila se va a su extremo derecho en pantalla ancha: el ojo recorre los campos de
   izquierda a derecha y termina justo donde está el botón que los envía. El margen automático se come el
   hueco libre, así que funciona con uno o con cuatro campos sin cifras a mano.
   En estrecho la fila se parte y el botón cae a su propio renglón: ahí «a la derecha» lo deja descolgado
   contra el borde, así que se centra. */
.nf-fieldrow > button,
.nf-formrow > button { margin-left: auto; }

@media (max-width: 640px) {
    .nf-fieldrow > button,
    .nf-formrow > button { margin-left: auto; margin-right: auto; }
}

/* La acción que NO cabe en la fila de sus campos —debajo de un área de texto, por ejemplo— va en su propio
   renglón. También se alinea a la derecha en pantalla ancha, o quedaría descolgada a la izquierda mientras
   todas las demás de la página terminan en el mismo borde.
   `:has(> button:only-child)` acota la regla a un párrafo que NO contiene otra cosa: es un renglón de
   acción y no un texto con un botón dentro, que sí se alinearía mal. En estrecho no se toca, que allí el
   botón ya ocupa el ancho completo. */
@media (min-width: 641px) {
    .nf-card form > p:has(> button:only-child),
    .nf-card > p:has(> button:only-child) { text-align: right; }
}
.nf-theme-btn .nf-theme-btn__moon { display: block; }
.nf-theme-btn .nf-theme-btn__sun { display: none; }
:root[data-theme="dark"] .nf-theme-btn .nf-theme-btn__sun { display: block; }
:root[data-theme="dark"] .nf-theme-btn .nf-theme-btn__moon { display: none; }

/* Momento de ENTREGAR la documentación: el gesto con el que la pelota pasa al despacho. Se marca con el filo
   izquierdo en verde y un fondo apenas teñido, en vez de la tarjeta verde entera de antes: teñirla toda la hacía
   parecer un mensaje de éxito —«ya está»— cuando lo que pide es una acción. El botón es el primario de la casa; el
   `btn-ok` verde plano no se usa en ninguna otra parte del área de cliente y ahí cantaba. */
.nf-entregar { border-left: 4px solid var(--success-ink); background: color-mix(in srgb, var(--success-weak) 45%, var(--surface)); }
.nf-entregar > .nf-sectitle { color: var(--success-ink); }
/* El icono acompaña al título: por defecto toma el violeta de marca y quedaba a dos colores. */
.nf-entregar > .nf-sectitle .nf-ico { color: var(--success-ink); }
/* La consecuencia, un paso por detrás del aviso: se lee al bajar la vista hacia el botón, no antes. */
.nf-entregar__despues { margin: .5rem 0 0; padding-top: .5rem; border-top: 1px solid color-mix(in srgb, var(--success-ink) 20%, transparent); }

/* Aviso de sesión caducada (419) durante una petición de Livewire, en lugar del `confirm()` del navegador.
   Va por encima de todo (incluido el off-canvas, z-index 60) porque no hay nada más que hacer en la página. */
.nf-expirada {
    position: fixed; inset: 0; z-index: 200;
    display: grid; place-items: center; padding: 1rem;
    background: rgba(23, 11, 38, .55);
}
.nf-expirada[hidden] { display: none; }   /* `hidden` no gana por sí solo frente a `display:grid` */
.nf-expirada__caja {
    max-width: 28rem; text-align: center;
    padding: 1.3rem;
    background: var(--surface); color: var(--ink);
    border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
}

/* Scrim del off-canvas (solo móvil). */
.nf-side__scrim { position: fixed; inset: 0; z-index: 55; background: rgba(23, 11, 38, .5); }

@media (max-width: 900px) {
    .nf-side {
        position: fixed; left: 0; top: 0; z-index: 60; height: 100dvh;
        transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--shadow-lg);
    }
    .nf-side.is-open { transform: none; }
    .nf-topbar__burger { display: inline-flex; }
}
@media (min-width: 901px) {
    .nf-side__scrim { display: none; }

    /* ---------------------------------------------------------------------
       BARRA LATERAL PLEGADA (`<html data-side="compacta">`): queda la península
       y los iconos, nada más. Solo en pantalla ancha: por debajo de 901 px la
       barra ya es un cajón off-canvas a pantalla casi completa, y plegarla ahí
       daría un carril de iconos flotando sobre el contenido — dos mecanismos
       peleándose por el mismo sitio.
       --------------------------------------------------------------------- */
    .nf-topbar__plegar { display: inline-flex; }

    :root[data-side="compacta"] .nf-side { width: 68px; flex-basis: 68px; padding-left: .35rem; padding-right: .35rem; }

    /* La marca cambia de pieza, no se recorta: fuera el logotipo con letras, dentro el icono. */
    :root[data-side="compacta"] .nf-side__logo { display: none; }
    :root[data-side="compacta"] .nf-side__logoicono { display: block; height: 28px; }
    :root[data-side="compacta"] .nf-side__brand { padding: .3rem 0 .8rem; justify-content: center; }

    /* Los rótulos se ocultan A LA VISTA pero siguen en el árbol de accesibilidad: con `display:none` un lector
       de pantalla leería «enlace» sin nombre, y el `title` de cada enlace es un apoyo para el ratón, no un
       sustituto del nombre accesible. */
    :root[data-side="compacta"] .nf-side__label {
        position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
    }

    /* Iconos centrados y sin hueco para el texto que ya no está. */
    :root[data-side="compacta"] .nf-side__nav a,
    :root[data-side="compacta"] .nf-side__foot button.link,
    :root[data-side="compacta"] .nf-side__me { margin-left: 0; margin-right: 0; }
    /* Los títulos de sección SIN grupo (los del área de cliente) no tienen versión corta: se sustituyen por una
       línea que separa, para no perder la agrupación. */
    :root[data-side="compacta"] .nf-side__grouptitle {
        height: 1px; margin: .55rem .5rem; padding: 0; overflow: hidden;
        color: transparent; background: var(--border);
    }
    :root[data-side="compacta"] .nf-side__grouptitle:first-child { margin-top: .1rem; }

    /* En modo icono, el ICONO DE LA SECCIÓN es la cabecera: se queda él, centrado y pulsable, y el acordeón sigue
       funcionando igual que en ancho. Antes esta cabecera se aplastaba a una línea de 1 px —que se llevaba el
       icono por delante— y, para que un grupo plegado no dejara sus enlaces inalcanzables, se forzaban visibles
       TODOS: quedaba un carril de quince iconos seguidos sin ninguna jerarquía. Con la cabecera pulsable, esa
       salvaguarda ya no hace falta. */
    :root[data-side="compacta"] .nf-navgrupo__cab {
        justify-content: center; gap: 0;
        margin: .5rem 0 .15rem; padding: .35rem 0;
        color: var(--accent-ink);
    }
    :root[data-side="compacta"] .nf-navgrupo:first-child .nf-navgrupo__cab { margin-top: .1rem; }
    /* El chevron no cabe al lado del icono en 68 px; el estado abierto ya se ve porque debajo están sus enlaces. */
    :root[data-side="compacta"] .nf-navgrupo__chev { display: none; }
    /* Separador entre grupos, que es lo que el rótulo dejaba de hacer al desaparecer. */
    :root[data-side="compacta"] .nf-navgrupo + .nf-navgrupo { border-top: 1px solid var(--border); }
    /* La cabecera tiene que distinguirse de sus enlaces, y sin rótulo no basta el sitio: «Usuarios y sistema» usa
       el mismo icono que su primer enlace, así que apilados eran dos iconos idénticos sin jerarquía. Se atenúa la
       cabecera y se resalta la del grupo ABIERTO, que además es lo único que dice en qué sección estás cuando el
       chevron no cabe. `aria-expanded` lo mantiene Alpine, así que la hoja puede leer el estado de ahí. */
    :root[data-side="compacta"] .nf-navgrupo__cab { opacity: .6; }
    :root[data-side="compacta"] .nf-navgrupo__cab:hover { opacity: 1; }
    :root[data-side="compacta"] .nf-navgrupo__cab[aria-expanded="true"] {
        opacity: 1; background: var(--primary-weak); border-radius: var(--r-xs);
    }
    :root[data-side="compacta"] .nf-side__grouptitle:first-child,
    :root[data-side="compacta"] .nf-navgrupo:first-child .nf-navgrupo__cab { margin-top: .1rem; }
}

/* =========================================================================
   F3 — Stat-tiles del cuadro de mando: KPI con anillo (donut) real.
   ========================================================================= */
.nf-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 1rem;
    margin-bottom: 1.1rem;
}
.nf-tile {
    display: flex; flex-direction: column; gap: .45rem;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
    box-shadow: var(--shadow); padding: 1.05rem 1.15rem;
}
.nf-tile__top { display: flex; align-items: center; justify-content: space-between; gap: .8rem; min-height: 48px; }
.nf-tile__lbl { font-size: .74rem; font-weight: 600; color: var(--muted); }
.nf-tile__num { font-size: 1.7rem; font-weight: 800; letter-spacing: -.02em; line-height: 1.05; color: var(--ink); font-variant-numeric: tabular-nums; }
/* Varias monedas en el mismo tile (ingresos EUR/GBP): apila los importes. */
.nf-tile__num + .nf-tile__num { font-size: 1.15rem; color: var(--muted); }
.nf-tile__cap { font-size: .76rem; color: var(--muted); }
.nf-tile__ico { color: var(--accent-ink); opacity: .85; }
.nf-tile--alert { border-color: color-mix(in srgb, var(--danger) 40%, transparent); background: var(--danger-weak); }
.nf-tile--alert .nf-tile__num { color: var(--danger-ink); }
.nf-tile--alert .nf-tile__ico { color: var(--danger-ink); opacity: 1; }
.nf-donut { flex: 0 0 auto; display: block; }

/* Pastilla de NIVEL DE SERVICIO. Va CONTORNEADA y no rellena, y eso es lo que la arregla: los estados usan
   los seis colores sólidos que hay (azul, ámbar, verde, rojo, gris y pizarra), así que cualquier tono que
   se eligiera chocaría con alguno — el violeta del nivel alto se confundía con «En revisión». El nivel no
   es un estado y no debe leerse como tal, así que se distingue por FAMILIA visual (contorno frente a
   relleno) y no por matiz. Dentro de esa familia se usan los DOS colores de marca —violeta el presencial,
   rosa la representación— y no un gris para el primero: en gris parecía deshabilitado, que es justo lo
   contrario de lo que es. */
.nf-badge--nivel {
    background: transparent; color: var(--primary-dark);
    border-color: var(--primary); font-weight: 600;
}
.nf-badge--nivel-rep {
    background: transparent; color: var(--accent-dark);
    border-color: var(--accent); font-weight: 700;
}

/* Etiquetas de la tarjeta de expediente (nivel + estado). Se apilan en columna a la derecha para que el
   nivel no empuje al estado fuera de la tarjeta cuando el nombre es largo («NIEFY Fully Managed»). */
.nf-exp-card__etiquetas { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; flex: 0 0 auto; }
@media (max-width: 560px) {
    /* En estrecho la cabecera ya se apila, así que las etiquetas vuelven a leerse en línea. */
    .nf-exp-card__etiquetas { flex-direction: row; align-items: center; flex-wrap: wrap; }
}

/* -----------------------------------------------------------------------
   Alta (paso 1: elección de servicio) y oferta del add-on fiscal.
   Antes iba todo en atributos `style` de la vista: no se podía reutilizar
   entre los dos pasos que muestran el add-on, no respondía a estados y el
   borde del nivel elegido se calculaba en el propio HTML.
   ----------------------------------------------------------------------- */
/* Todo el recorrido del cliente comparte anchura: la del contenedor de página (`--maxw`), que es la que
   ya tenían la documentación y el resto de su área. Va en el envoltorio del paso y no en cada tarjeta,
   para que un paso nuevo la herede sin acordarse de nada.

   Antes el alta iba a 640 px y «Información» a 900, con la idea de que una pantalla de compra se lee
   mejor estrecha. El efecto real era otro: al pasar de contratar a subir documentos la caja daba un
   salto de 340 px, y el cliente veía tres anchos distintos recorriendo UNA sola cosa. La continuidad
   entre pasos pesa más que el ancho de línea ideal de cada uno por separado. */
.nf-alta { max-width: var(--maxw); margin-inline: auto; }
/* Se mantiene la clase, ya sin efecto propio, porque «Información» la usa y su significado —«este paso
   necesita aire»— sigue siendo cierto: es un formulario largo a dos columnas y no una pantalla de
   compra. Si algún día se vuelve a estrechar el alta, este es el paso que NO debe estrecharse: a 640 px
   sus parejas de campos rompen la fila del móvil, que tiene prueba propia porque ya se rompió una vez. */
.nf-alta--ancho { max-width: var(--maxw); }

/* Vuelta del pago. Centrada y con un solo camino: es el punto donde el cliente puede creer que ha
   terminado, así que todo lo que no sea «continuar» estorba. */
.nf-gracias { text-align: center; padding: 2rem 1.4rem 1.6rem; }
.nf-gracias__ico { display: flex; justify-content: center; margin-bottom: .5rem; color: var(--success); }
.nf-gracias--confirmando .nf-gracias__ico { color: var(--primary); }
.nf-gracias--fallido .nf-gracias__ico { color: var(--danger); }
.nf-gracias__titulo { margin: 0 0 .4rem; font-size: 1.5rem; }
.nf-gracias__texto { margin: 0 auto; max-width: 42ch; color: var(--text-muted); }
.nf-gracias__importe { margin: .9rem 0 0; font-size: 1.9rem; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.nf-gracias__acciones { margin: 1.3rem 0 0; }
/* El aviso de que aún falta un paso: legible, no una nota al pie. Quien paga y desaparece deja un
   expediente sin documentación, que es el peor caso operativo del negocio. */
.nf-gracias__aviso { margin: .9rem auto 0; max-width: 46ch; }
.nf-gracias__nota { margin: .6rem auto 0; max-width: 46ch; }
.nf-alta__titulo { margin-top: 0; }
.nf-alta__aviso { margin-top: .9rem; }
.nf-alta__campo { margin-top: 1rem; }
.nf-alta__nota { margin-top: 1.2rem; }
.nf-alta__acciones { margin-top: 1rem; }

/* Selector de nivel del alta. Son LAS MISMAS tarjetas de la landing (`.plan`, compartidas por el
   `:is(body.nf-landing, .nf-planes)` de más abajo) en lugar de una fila con un radio y un precio suelto:
   quien elige aquí lo que va a pagar ve exactamente lo que vio en la portada —precio, lema y prestaciones—,
   y por eso desaparece el enlace «ver la comparativa de niveles»: la comparativa ES esta pantalla.

   Los niveles van UNO AL LADO DEL OTRO, igual que en la portada: puestos en pila hay que recordar la
   tarjeta de arriba para juzgar la de abajo, y esta pantalla existe para compararlos.

   Las medidas se afinan bajo `.nf-alta` a propósito: ahí ganan por especificidad a las de la portada
   —`:is(body.nf-landing, .nf-planes)` cuenta como (0,2,1) y `.nf-planes .plans` se queda corta—. */
.nf-planes { margin: .25rem 0 0; padding: 0; border: 0; }
.nf-alta .nf-planes .plans { gap: 16px; margin: 0; max-width: none; }
/* Aquí la tarjeta ES la etiqueta del radio: se pulsa entera, no un punto de 13 px. Y respira menos que en la
   portada: allí es una sección a pantalla completa, aquí van dentro de la tarjeta del alta. */
.nf-alta .nf-planes .plan { cursor: pointer; padding: 22px 24px; }
.nf-alta .nf-planes .plan:hover { transform: none; }
.nf-alta .nf-planes .plan__label { padding-right: 140px; }
/* La nota del nivel («requiere poder notarial…», «sin representante…») se va al PIE de la tarjeta: es el
   sitio que ocupa el botón en la portada, y sin ese `margin-top:auto` quedaba pegada a la última prestación
   —parecía un ✓ más al que se le hubiera caído la marca— y a distinta altura en cada tarjeta. */
.nf-alta .nf-planes .plan__note { margin-top: auto; padding-top: 1rem; }
/* El radio no se PINTA —la selección se ve en la tarjeta— pero sigue en el DOM y sigue recibiendo el foco:
   con `display:none` el selector se quedaría sin teclado y sin lector de pantalla. */
.nf-planes__radio { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
/* El nivel elegido se lleva el tratamiento oscuro de la tarjeta destacada (`plan--priority`, puesto desde la
   plantilla al cambiar la selección) y además un filo: el color por sí solo también lo tiene el «recomendado»
   de la portada, y sin el filo «destacado» y «elegido» se leerían igual. */
.nf-alta .nf-planes .plan:has(:checked) { border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary) inset; }
.nf-alta .nf-planes .plan--priority:has(:checked) { border-color: var(--sand); box-shadow: 0 0 0 2px var(--sand) inset; }
.nf-alta .nf-planes .plan:has(:focus-visible) { outline: 2px solid var(--primary); outline-offset: 3px; }

/* Las dos acciones de un paso, en esquinas opuestas: volver a la izquierda y seguir a la derecha, con la
   misma caja. Puestas en fila una detrás de otra, «cambiar de servicio» parecía el remate del formulario y
   no la vuelta atrás. */
.nf-alta__acciones--dos { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }

/* Oferta del add-on fiscal. Toma prestado el lenguaje de la tarjeta destacada de la landing —degradado de
   marca, filo de luz interior, halo— porque es lo mismo que hace allí: señalar la pieza que queremos que
   se mire. Va más contenida que en la landing: esto es un paso de compra y no un escaparate, así que sin
   el `translateY` ni el pulso continuo, que aquí distraerían de la decisión que se está tomando.

   Es una ETIQUETA, no un div: toda la tarjeta acciona la casilla. */
.nf-addon {
    position: relative; display: flex; flex-direction: column; gap: .45rem;
    margin: .6rem 0 0; padding: 1rem 1.15rem;
    background: var(--grad); color: #fff; cursor: pointer;
    border-radius: var(--r); border: 1px solid transparent;
    box-shadow: 0 18px 38px -22px rgba(124, 58, 237, .65), 0 2px 8px rgba(0, 0, 0, .08);
}
/* Filo de luz interior: es lo que da el acabado de «pieza destacada» sin subir el ruido. */
.nf-addon::after {
    content: ''; position: absolute; inset: 0; border-radius: var(--r); pointer-events: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .38), inset 0 0 0 1px rgba(255, 255, 255, .16);
}
.nf-addon:hover { box-shadow: 0 24px 46px -22px rgba(124, 58, 237, .72), 0 4px 12px rgba(0, 0, 0, .10); }
/* El foco se pinta sobre la tarjeta entera: quien navega con teclado ve la oferta marcada, no un punto. */
.nf-addon:has(input:focus-visible) { outline: 2px solid #fff; outline-offset: 3px; }
/* Ya añadido: se refuerza el filo para que se note que está dentro del carrito. */
.nf-addon:has(input:checked)::after {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 0 0 2px rgba(255, 255, 255, .55);
}

/* La pastilla va EN EL FLUJO, dentro de la cabecera, y no volando sobre el borde con `top: -.6rem`: ahí la
   recortaba el recuadro de la lista de niveles, que sí tiene su propio límite.
   El color del texto va en HEXADECIMAL LITERAL a propósito. Estaba en `var(--primary-dark)`, y si esa
   variable no está definida en el contexto donde se pinte la tarjeta, `color: var(--indefinida)` no cae a
   ningún valor por defecto: hereda. Y lo que hereda aquí es el blanco de la tarjeta, así que la palabra
   desaparecía sobre su propia pastilla blanca. */
.nf-addon__cinta {
    margin-left: auto; flex: 0 0 auto;
    background: #fff; color: #5B21B6;
    font-size: .66rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
    padding: .2rem .55rem; border-radius: 999px; box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}
.nf-addon__cab { display: flex; align-items: center; gap: .5rem; }
.nf-addon__ico { display: flex; color: #fff; opacity: .9; }
.nf-addon__titulo { font-size: 1rem; font-weight: 800; letter-spacing: -.01em; }
/* Sobre el degradado hace falta blanco casi pleno: el `--text-muted` de las tarjetas claras no llega a
   contraste sobre violeta. */
.nf-addon__texto { font-size: .86rem; line-height: 1.5; color: rgba(255, 255, 255, .92); }
.nf-addon__check { display: flex; align-items: center; gap: .55rem; margin-top: .2rem; font-weight: 700; }
.nf-addon__check input { accent-color: #fff; width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }
.nf-addon__anadir { flex: 1; }
.nf-addon__precio { font-size: 1.05rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.nf-addon__despues { font-size: .78rem; color: rgba(255, 255, 255, .78); }

@media (max-width: 480px) {
    /* En estrecho el precio se va a su propia línea antes que comprimir el texto de la casilla. */
    .nf-addon__check { flex-wrap: wrap; }
    .nf-addon__precio { margin-left: auto; }
}

/* Venta por nivel de servicio (cuadro de mando). Una fila por nivel, con sus cifras en rejilla.
   `auto-fit` + `minmax` en lugar de un número fijo de columnas: son nueve cifras y en un portátil no caben
   en una línea, así que se reparten solas sin necesidad de media queries ni de scroll horizontal. */
/* `flex-wrap: nowrap` NO es cosmético: `.nf-row` viene con `wrap`, y un contenedor flex en COLUMNA con wrap
   reparte su altura entre las «columnas» que genera, lo que le daba a la rejilla de dentro una altura
   definida. Con altura definida, `align-content` por defecto estira las filas automáticas para repartir el
   hueco sobrante: las dos filas de cifras salían a 234 px cada una y el bloque medía 535 px de alto con dos
   franjas vacías enormes. `align-content: start` lo remata desde el otro lado. */
.nf-venta { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: .55rem; }
.nf-venta__cab { display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap; }
.nf-venta__cifras {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
    gap: .55rem .9rem; align-content: start;
}
.nf-venta__dato { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.nf-venta__dato .lbl { font-size: .7rem; font-weight: 600; color: var(--muted); }
/* `tabular-nums` para que las cifras de niveles distintos queden alineadas en vertical y se puedan comparar
   de un vistazo, que es justo para lo que sirve esta tabla. */
.nf-venta__dato .val { font-size: 1rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
/* Segunda divisa y siguientes: presentes pero sin competir con la principal. */
.nf-venta__dato .val + .val { font-size: .85rem; font-weight: 600; color: var(--muted); }

/* =========================================================================
   F4 — Listas de filas como tarjetas redondeadas (bandejas, estancados…).
   Scopeado a .nf-rows para NO afectar a las listas densas (pagos, tarifas,
   usuarios…) que usan .nf-row suelto con separador por borde superior.
   ========================================================================= */
.nf-rows { display: flex; flex-direction: column; gap: .5rem; margin-top: .4rem; }
/* Barra de acciones en lote. Aparece solo con algo marcado, pegada a la lista sobre la que actúa. */
.nf-lote {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    margin: .6rem 0 0; padding: .6rem .8rem;
    background: var(--primary-weak); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
}
/* El desplegable no se come la fila: con `width:100%` empujaba los botones a un segundo renglón. */
.nf-lote select { min-height: 34px; width: auto; min-width: 14rem; }
.nf-rows > .nf-row,
.nf-rows > .nf-row:first-of-type {
    padding: .7rem .9rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.nf-rows > .nf-row:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-sm);
    background: color-mix(in srgb, var(--primary-weak) 45%, var(--surface));
}
/* Cita solapada dentro de una lista-tarjeta: tinte y borde ámbar (aviso), coherente con el badge. */
.nf-rows > .nf-row--overlap {
    background: color-mix(in srgb, var(--amber-badge) 12%, var(--surface));
    border-color: color-mix(in srgb, var(--amber-badge) 55%, transparent);
}

/* ----------------------------------------------------------------------- */
/* Calendario de disponibilidad de cita (tier presencial)                  */
/* ----------------------------------------------------------------------- */
/* Ojo con el nombre: `.nf-cal*` YA es el calendario del BACKOFFICE (43 reglas, /admin/calendario).
   Reusarlo aquí heredaba su `display:flex` y desmontaba esta rejilla en columnas. De ahí `.nf-citacal`.
   NO es un selector: el dato sigue siendo «días de la semana». Está para ver qué fechas caen en lo elegido,
   cuáles abre el consulado y cuáles ya pasaron. De ahí que ningún día sea pulsable. */
.nf-citacal__tit { font-size: 1.05rem; margin: 0; }

/* ---------------------------------------------------------------------
   Lo que OFRECE el consulado, antes de pedirle nada al cliente.
   El dato ya estaba (días, franjas y el `horario` de la ficha) y no se
   enseñaba en ninguna parte: el cliente solo podía deducir qué días
   atiende por cuáles casillas existían, y el horario no se veía nunca.
   Marcar disponibilidad sin saber la del otro es adivinar.
   --------------------------------------------------------------------- */
.nf-citaoferta {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.6rem;
    padding: .8rem .9rem;
    margin: .2rem 0 1.1rem;
    border-radius: var(--r);
    background: var(--primary-weak);
    border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
}
.nf-citaoferta__bloque { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.nf-citaoferta__lbl {
    font-size: .68rem; font-weight: 800; text-transform: uppercase; letter-spacing: .07em;
    color: var(--accent-ink);
}
.nf-citaoferta__valor { display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; font-size: .9rem; color: var(--text); }
/* Pastilla sólida: es dato del consulado, no algo que el cliente elija. */
.nf-citaoferta__dia {
    display: inline-flex; align-items: center;
    padding: .1rem .5rem; border-radius: var(--r-pill);
    background: var(--surface); border: 1px solid color-mix(in srgb, var(--primary) 25%, transparent);
    font-size: .8rem; font-weight: 700; color: var(--accent-ink);
}

/* ---------------------------------------------------------------------
   Los días/franjas que marca el CLIENTE: pastillas pulsables, no casillas
   sueltas alineadas a la izquierda. El estado sigue al checkbox real con
   `:has(:checked)` —el mismo recurso que el interruptor de la casa—, así
   que sigue siendo un `<input>` de verdad: teclado y lector de pantalla
   funcionan sin JavaScript.
   --------------------------------------------------------------------- */
/* Los dos grupos (días y franjas) en la MISMA línea mientras quepan. El corte no es un ancho de móvil
   inventado: `auto-fit` + `minmax` los pasa a una columna justo cuando dejan de caber, así que funciona igual
   dentro de la guía por pasos —que es más estrecha— que a pantalla completa. */
/* ---------------------------------------------------------------------
   ZONAS de la pantalla de disponibilidad.
   La tarjeta es blanca y todo lo de dentro también, así que las tres
   partes —lo que ofrece el consulado, lo que eliges y el calendario— se
   leían como un único bloque largo sin jerarquía. Cada una va sobre el
   lila de página de la app, que ya es un color del sistema: separa sin
   inventar una paleta nueva y sigue funcionando en oscuro, donde `--page`
   es más oscuro que la superficie de la tarjeta.
   --------------------------------------------------------------------- */
.nf-citazona {
    background: var(--page);
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 1rem 1.1rem;
    margin-top: 1rem;
}
.nf-citazona__tit {
    display: flex; align-items: center; gap: .4rem;
    margin: 0 0 .7rem;
    font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .07em;
    color: var(--accent-ink);
}

.nf-citagrid {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 2.5rem;
    margin-top: 0;
}
/* Cada grupo ocupa LO SUYO y no media tarjeta: con dos columnas iguales, los cinco días no cabían en su
   mitad y «Viernes» se caía solo a una segunda línea mientras al lado sobraba sitio. Así van juntos mientras
   quepan de verdad y se apilan cuando no, sin fijar ningún ancho de móvil a mano. */
/* Cada grupo es su propia tarjeta y ocupa LO SUYO, no media pantalla: con dos columnas iguales, los cinco
   días no cabían en su mitad y «Viernes» se caía solo a una segunda línea mientras al lado sobraba sitio.
   Así van juntos mientras quepan de verdad y se apilan cuando no, sin fijar ningún ancho de móvil a mano. */
/* Las dos tarjetas LLENAN la fila: `flex-grow` reparte el espacio sobrante a partir del ancho que cada una
   necesita, así que la de los días —que lleva cinco pastillas— sigue siendo más ancha que la de las franjas,
   pero ninguna se queda corta dejando un hueco muerto a la derecha. Con `0 1 auto` la de franjas se quedaba
   a media fila; con dos columnas iguales, «Viernes» se caía solo a una segunda línea. */
/* Reparto FIJO, no por contenido: con `flex-basis: auto` el ancho natural lo marcaba el párrafo de ayuda
   —que es largo— y las dos tarjetas dejaban de caber juntas. Con base 0 y `flex-grow` desigual, la de los
   días se lleva más espacio (lleva cinco pastillas y tienen que caber en una línea) y entre las dos llenan
   la fila sin hueco muerto a la derecha. El `min-width` es lo que las apila cuando de verdad no caben. */
.nf-citagrid > fieldset { flex: 1 1 0; min-width: 17rem; margin-top: 0; }
.nf-citagrid > fieldset:first-child { flex-grow: 1.7; }
/* El título de cada tarjeta va en un `<p>` propio, no en el `<legend>`: un `<legend>` con estilo abre una
   muesca en el borde de la tarjeta —el aspecto de «fieldset» que no queremos— y arrastra
   `.nf-fieldset-plain > legend`, que lo pinta en negro (`--ink`) y gana por especificidad. El `<legend>` se
   queda oculto para lectores de pantalla, que es donde de verdad sirve: agrupa las casillas. */
.nf-citagrid > fieldset > .nf-citazona__tit { margin-top: 0; }
/* La explicación va DEBAJO de las pastillas, en el tono de las notas: dice qué hace lo que acaba de marcar. */
.nf-citazona__pie { margin: .7rem 0 0; font-size: .84rem; line-height: 1.45; color: var(--muted); }

.nf-diachips { display: flex; flex-wrap: wrap; gap: .45rem; }
.nf-diachip {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .45rem .85rem; border-radius: var(--r-pill);
    background: var(--surface); border: 1px solid var(--border-strong);
    font-size: .9rem; font-weight: 600; color: var(--text);
    cursor: pointer; user-select: none;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.nf-diachip:hover { border-color: var(--primary); background: var(--primary-weak); }
.nf-diachip:has(:checked) {
    background: var(--grad); border-color: transparent; color: #fff; box-shadow: var(--shadow-sm);
}
/* El checkbox se oculta a la vista pero SIGUE existiendo: enfocable y anunciable. */
.nf-diachip input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.nf-diachip:has(:focus-visible) { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.nf-diachip:has(:disabled) { opacity: .55; cursor: default; }
.nf-diachip:has(:disabled):hover { border-color: var(--border-strong); background: var(--surface); }

/* El calendario tiene ancho propio (no crece con la tarjeta), así que se CENTRA: alineado a la izquierda
   dejaba media tarjeta vacía a su derecha en escritorio. La leyenda y la ayuda lo acompañan, para que el
   bloque se lea como una pieza y no como una tabla con notas sueltas debajo. */
.nf-citacal__tabla {
    width: 100%;
    max-width: 34rem;
    margin-inline: auto;
    border-collapse: separate;
    border-spacing: 5px;
    table-layout: fixed;
}

.nf-citacal__tabla th {
    font-size: .74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-muted);
    padding-bottom: .35rem;
}

/* Día en que NO se atienden citas. Se distingue por PATRÓN y no solo por tono: sobre una tarjeta blanca,
   `--page` y el lila del día abierto quedaban a un matiz de distancia, y esa diferencia no sobrevive ni a un
   monitor malo ni a una visión del color distinta de la nuestra. Sin relleno y con el borde marcado se lee
   como «aquí no hay nada» aunque el color no llegue. */
.nf-citacal__d {
    position: relative;
    height: 3rem;
    text-align: center;
    font-size: .95rem;
    border-radius: 10px;
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--text-muted);
    opacity: .7;
}

/* Abre pero sin marcar: se ve que es posible, sin competir con lo elegido. Relleno CLARO pero de verdad —el
   10 % anterior era indistinguible del día cerrado sobre tarjeta blanca— y borde del color de marca. */
.nf-citacal__d--abre {
    background: color-mix(in srgb, var(--primary) 22%, var(--surface));
    color: var(--accent-ink);
    font-weight: 600;
    box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 45%, transparent);
    opacity: 1;
}

/* Lo elegido por el cliente: es la única lectura que tiene que saltar a la vista. Sólido, blanco y con
   sombra: separado de los otros dos por relleno, por contraste y por peso, no por un matiz. */
.nf-citacal__d--elegido {
    background: var(--grad);
    color: #fff;
    font-weight: 800;
    box-shadow: var(--shadow-sm);
    opacity: 1;
}

/* EL DÍA DE LA CITA (backoffice). Es la única celda que representa un hecho y no una preferencia, así que
   se distingue de «le viene bien al cliente» por forma y no por matiz: aro de acento alrededor de la celda.
   Se combina con cualquiera de los otros estados —una cita puede caer en un día que el cliente no pidió, que
   es justo el caso que hay que ver de un vistazo. */
.nf-citacal__d--cita {
    box-shadow: 0 0 0 3px var(--accent), var(--shadow-sm);
    position: relative;
    z-index: 1;
}

.nf-citacal__k--cita {
    background: var(--surface);
    box-shadow: 0 0 0 2px var(--accent);
}

/* Confirmación en línea junto a un campo: la contrapartida verde de `.nf-err`, para decir «esto encaja» sin
   robarle el sitio al aviso. */
.nf-ok-inline {
    display: block;
    margin-top: .35rem;
    font-size: .85rem;
    font-weight: 600;
    color: var(--success);
}

/* Fecha DESCARTADA por el cliente dentro de su patrón: «ese martes no puedo». Se distingue del día cerrado
   —que nunca estuvo disponible— porque aquí hubo una decisión: color de aviso y la cifra tachada. El tachado
   es lo que lo hace legible sin depender del color. */
.nf-citacal__d--bloqueada {
    background: color-mix(in srgb, var(--danger) 14%, var(--surface));
    box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--danger) 45%, transparent);
    color: var(--danger);
    font-weight: 700;
    opacity: 1;
}
.nf-citacal__d--bloqueada .nf-citacal__num { text-decoration: line-through; text-decoration-thickness: 2px; }

/* El día pulsable es un botón de verdad (teclado y lector de pantalla), pero ocupa toda la celda y no se
   pinta como botón: lo que se ve es el día, y el color de la celda ya dice en qué estado está. */
.nf-citacal__btn {
    display: block; width: 100%; height: 100%;
    padding: 0; margin: 0; border: 0; background: none; box-shadow: none;
    font: inherit; color: inherit; cursor: pointer; border-radius: inherit;
}
.nf-citacal__btn:hover { background: none; transform: none; filter: brightness(.96); }
.nf-citacal__btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* Pasado: no se puede pedir cita para ayer. Pierde peso, y nunca se pinta como elegido (ver CalendarioCita). */
.nf-citacal__d--pasado { opacity: .3; box-shadow: inset 0 0 0 1px var(--line); background: transparent; color: var(--text-muted); font-weight: 400; }

.nf-citacal__num { display: block; line-height: 3rem; }
/* Con el mes debajo, el número sube para que los dos quepan sin apretarse. */
.nf-citacal__d:has(.nf-citacal__mes) .nf-citacal__num { line-height: 2.4rem; }

/* Marca dónde cambia el mes: en una ventana de cuatro semanas pasa casi siempre. */
.nf-citacal__mes {
    position: absolute;
    inset: auto 0 .3rem 0;
    font-size: .6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    opacity: .8;
}

.nf-citacal__leyenda {
    display: flex;
    gap: .2rem 1rem;
    flex-wrap: wrap;
    justify-content: center;
    max-width: 34rem;
    margin: .7rem auto 0;
}
/* El título y la leyenda del calendario, centrados con él. Los párrafos largos NO: centrar un texto de dos
   líneas se lee peor, así que se centra el BLOQUE y el texto se queda alineado a la izquierda dentro. */
.nf-citacal { text-align: center; }

/* Las notas del pie, como una lista: mismo ancho que el calendario, icono en su columna y texto alineado.
   Eran dos párrafos sueltos —uno dentro del bloque centrado y otro fuera— y no cuadraban ni entre ellos. */
.nf-citanotas {
    list-style: none;
    max-width: 34rem;
    margin: .8rem auto 0;
    padding: 0;
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: .45rem;
}
.nf-citanotas li {
    display: grid;
    grid-template-columns: 1rem 1fr;
    gap: .45rem;
    align-items: start;
    font-size: .88rem;
    color: var(--muted);
    line-height: 1.45;
}
.nf-citanotas .nf-ico { margin-top: .15rem; color: var(--accent-ink); }

.nf-citacal__leyenda span { display: inline-flex; align-items: center; gap: .35rem; }

.nf-citacal__k {
    width: .8rem;
    height: .8rem;
    border-radius: 4px;
    display: inline-block;
}

/* Las tres muestras de la leyenda replican EXACTAMENTE el relleno y el borde de su día. Si divergen, la
   leyenda explica un calendario que no es el que se está viendo. */
.nf-citacal__k--elegido { background: var(--grad); }

.nf-citacal__k--abre {
    background: color-mix(in srgb, var(--primary) 22%, var(--surface));
    box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--primary) 45%, transparent);
}

.nf-citacal__k--bloqueada {
    background: color-mix(in srgb, var(--danger) 14%, var(--surface));
    box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--danger) 45%, transparent);
}

.nf-citacal__k--cierra { background: transparent; box-shadow: inset 0 0 0 1px var(--line); }


/* ==========================================================================
   ==========================================================================
   LANDING PÚBLICA · todo lo de aquí abajo vive dentro de `body.nf-landing`
   ==========================================================================
   ========================================================================== */

/* ==========================================================================
   Landing pública de NIEFY. Portada del sitio estático (docs/website_niefy),
   concatenando tokens.css + base.css + landing.css en el orden que exige su
   README (los componentes leen sus colores de los tokens).

   Vive ACOTADA bajo `body.nf-landing` dentro de esta misma hoja (ver la cabecera del fichero).
   Por eso sus tokens pueden seguir en :root sin repintar el resto de la app:
   ninguna otra pantalla incluye este fichero. Prefijar 560 líneas a mano para
   acotarlas habría sido más frágil que no cargarlas donde no tocan.

   ÚNICO cambio respecto al original: las rutas de los assets pasan de
   'assets/…' a '/img/niefy/…', que es donde viven servidos por Laravel.
   ========================================================================== */

/* ============================================================
   Niefy.es — Design tokens
   Single source of truth for colour, type and layout scale.
   Palette derived from the Niefy logo (violet → magenta → pink).
   Loaded FIRST on every page.

   `.nf-planes` entra en el MISMO selector porque el alta pinta las tarjetas de
   nivel con la estética de la landing, y esas reglas leen esta paleta. Los
   tokens quedan acotados a ese bloque: el resto de la app no los ve.
   ============================================================ */
body.nf-landing,
.nf-planes {
  /* --- Brand ramp --- */
  --primary:#4A17A8;        /* primary, 8.6:1 on white         */
  --primary-dark:#37107F;   /* primary hover                   */
  --primary-deep:#2B0B63;   /* dark surfaces                   */
  --red:#7A1E9E;            /* secondary accent, 6.4:1         */
  --orange:#A833D8;         /* decorative only                 */
  --amber:#C42BC7;          /* decorative only                 */
  --brick:#C81E68;          /* links & eyebrows, 5.0:1         */
  --accent:#F42C7A;         /* decorative highlights           */
  --sand:#F3C4FF;           /* text/icon on dark surfaces      */

  /* --- Headline word colours (all AA on light surfaces) --- */
  --h-1:#4A17A8;
  --h-2:#7A1E9E;
  --h-3:#A31E8E;
  --h-4:#C81E68;

  /* --- Neutrals --- */
  --ink:#241033;            /* headings                        */
  --muted:#55475F;          /* body copy, 7:1 on --paper       */
  --paper:#FAF5FF;          /* page background                 */
  --soft:#F6ECFF;           /* alternating band                */
  --card:#FFFFFF;           /* tarjeta SOBRE una banda         */
  --line:#EDE0F7;           /* hairlines & card borders        */

  /* --- Gradients --- */
  --grad-brand:linear-gradient(100deg,#4A17A8 0%,#7C22D0 46%,#DF1466 100%);
  --grad-brand-hover:linear-gradient(100deg,#3A1090 0%,#6A1BB8 46%,#C21058 100%);
  --grad-page:linear-gradient(170deg,#FFFFFF 0%,#FDF7FF 40%,#F5E8FF 72%,#FBE0F0 100%);
  --glow:radial-gradient(100% 70% at 50% 0%,#fff 0%,rgba(255,255,255,.7) 45%,transparent 72%);

  /* --- Type & layout --- */
  /* DOS familias: la máquina de escribir se queda para los TITULARES, que es donde da carácter, y el
     cuerpo pasa a una sans legible. Un párrafo largo en monoespaciada cansa: las columnas se estiran y la
     lectura se vuelve trabajo.

     Desde el 20/09 las dos van AUTOALOJADAS (`@font-face` al principio de esta hoja, ficheros en
     `public/fonts/`): la cara exacta sin pedirle nada a Google, que enviaría la IP de cada visitante a un
     tercero sin contrato del art. 28 (PD-05). Las cadenas de respaldo se quedan detrás, que es lo que se lee
     mientras la fuente llega y lo que cubre los alfabetos que no traemos. */
  --font:'Courier Prime','Courier New',monospace;          /* titulares */
  --font-body:'Nunito','Noto Sans',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --wrap:1100px;
  --radius:20px;

  --cta-fin:#F5E4FA;   /* final del degradado que baja hacia el pie */

  /* Ritmo vertical. Estaba disperso: las secciones iban a 96px pero el cierre a 90, el pie a 60/40, y
     el hueco entre el titular de sección y su contenido valía 54, 50, 48 o 36 según la sección. Nada de
     eso se decidió, se fue acumulando. Dos tokens y una sola cifra por concepto. */
  --sec-y:96px;        /* aire arriba y abajo de cada sección       */
  --gap-titulo:48px;   /* del titular de sección a su contenido     */
}

/* ============================================================
   Niefy.es — Base layer
   Shared by every page: reset, accessibility rules, buttons,
   the waitlist form, the NIE certificate illustration and the
   keyframes. Depends on tokens.css.
   ============================================================ */

/* ---------- reset ---------- */


body.nf-landing {
  margin:0;min-height:100vh;
  display:flex;flex-direction:column;
  font-family:var(--font-body);color:var(--ink);
  /* El resplandor superior estaba CODIFICADO en blanco, encima del token de fondo: en modo oscuro se
     quedaba arriba y dejaba texto claro sobre fondo claro. Pasa a token para que el tema pueda voltearlo. */
  background:
    var(--glow),
    var(--grad-page);
  overflow-x:hidden;
}
body.nf-landing h1,
body.nf-landing h2,
body.nf-landing h3,
body.nf-landing p {margin:0;}
body.nf-landing a {color:var(--brick);text-decoration:none;}
body.nf-landing a:hover {color:var(--primary);}
body.nf-landing img {display:block;max-width:100%;}
body.nf-landing button {font-family:inherit;cursor:pointer;border:none;}
body.nf-landing ul {margin:0;padding:0;list-style:none;}

/* ---------- accessibility / visibility ---------- */
body.nf-landing :focus-visible {outline:3px solid var(--brick);outline-offset:3px;border-radius:6px;}
body.nf-landing .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;
}
body.nf-landing .skip {
  position:absolute;left:16px;top:-60px;z-index:99;
  background:var(--primary);color:#fff;padding:12px 20px;
  border-radius:0 0 12px 12px;font-weight:700;font-size:14px;
  transition:top .2s ease;
}
body.nf-landing .skip:focus {top:0;color:#fff;}
body.nf-landing [hidden] {display:none !important;}

/* ---------- decorative dot grid ---------- */
body.nf-landing .dots {
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:radial-gradient(rgba(74,23,168,.12) 1px,transparent 1px);
  background-size:26px 26px;
  -webkit-mask-image:radial-gradient(70% 60% at 50% 40%,#000,transparent 76%);
          mask-image:radial-gradient(70% 60% at 50% 40%,#000,transparent 76%);
}

/* ---------- headline word colours ---------- */
body.nf-landing .c1 {color:var(--h-1);}
body.nf-landing .c2 {color:var(--h-2);}
body.nf-landing .c3 {color:var(--h-3);}
body.nf-landing .c4 {color:var(--h-4);}

/* ---------- buttons ---------- */
body.nf-landing .btn {
  min-height:52px;display:inline-flex;align-items:center;justify-content:center;
  background:var(--grad-brand);color:#fff;
  box-shadow:0 10px 24px -12px rgba(74,23,168,.55);
  border-radius:30px;padding:14px 26px;
  font-size:15px;font-weight:700;white-space:nowrap;
  transition:transform .2s ease,background .2s ease,box-shadow .2s ease;
}
body.nf-landing .btn:hover {
  transform:translateY(-2px);background:var(--grad-brand-hover);color:#fff;
  box-shadow:0 14px 30px -12px rgba(74,23,168,.6);
}
body.nf-landing .btn--sm {min-height:44px;padding:11px 22px;font-size:14px;}
/* Botón secundario. Era BLANCO PLANO sobre una página casi blanca: solo se distinguía del fondo por una
   sombra tenue, así que a plena luz o en una pantalla mala no se veía que fuese un botón. Lleva ahora un
   filo violeta —de contorno, no de borde real, para no cambiar la caja ni desalinearlo del principal— y
   una sombra con más recorrido. El relleno sale de `--card` y no de #fff para que el tema pueda voltearlo. */
body.nf-landing .btn--soft {
  background:var(--card);color:var(--primary);
  box-shadow:0 10px 26px -12px rgba(74,23,168,.42),inset 0 0 0 1.5px rgba(74,23,168,.22);
}
body.nf-landing .btn--soft:hover {
  background:var(--card);color:var(--primary-dark);
  box-shadow:0 16px 34px -12px rgba(74,23,168,.5),inset 0 0 0 1.5px rgba(74,23,168,.4);
}
body.nf-landing .btn[aria-busy="true"],
body.nf-landing .btn:disabled {opacity:.7;pointer-events:none;}

/* ---------- waitlist form ---------- */
body.nf-landing .form {display:flex;gap:10px;max-width:460px;margin-top:28px;}
body.nf-landing .form input {
  flex:1;min-height:52px;border:2px solid var(--primary);background:var(--card);
  border-radius:30px;padding:14px 20px;font-size:15px;font-family:inherit;
  color:var(--ink);outline:none;
}
body.nf-landing .form input:focus {box-shadow:0 0 0 3px rgba(74,23,168,.2);}
body.nf-landing .form input[aria-invalid="true"] {border-color:var(--brick);}

/* honeypot — hidden from humans and assistive tech, bots fill it */
body.nf-landing .hp {
  position:absolute !important;left:-9999px !important;
  width:1px !important;height:1px !important;
  opacity:0 !important;pointer-events:none !important;
}
body.nf-landing .done {
  display:inline-flex;align-items:center;gap:10px;margin-top:28px;
  background:var(--primary);color:var(--sand);border-radius:30px;
  padding:15px 26px;font-size:15px;font-weight:700;
}
body.nf-landing .error {
  display:inline-flex;align-items:center;gap:10px;margin-top:28px;
  background:#FFF0F5;color:#A3103F;border:1.5px solid #F2C2D4;border-radius:30px;
  padding:14px 24px;font-size:14px;font-weight:700;max-width:460px;line-height:1.45;
}
body.nf-landing .microcopy {font-size:13px;line-height:1.6;color:var(--muted);margin-top:14px;max-width:440px;}

/* ============================================================
   NIE certificate illustration (decorative facsimile)
   ============================================================ */
body.nf-landing .stage-col {display:flex;flex-direction:column;justify-content:center;}
body.nf-landing .stage {
  position:relative;display:flex;align-items:center;justify-content:center;
  perspective:1500px;min-height:470px;
}
body.nf-landing .stage__halo {
  position:absolute;width:420px;height:290px;border-radius:50%;filter:blur(28px);
  background:radial-gradient(ellipse,rgba(255,255,255,.85),transparent 66%);
}
body.nf-landing .stage__shadow {
  position:absolute;bottom:14px;left:50%;width:290px;height:34px;transform:translateX(-50%);
  background:radial-gradient(ellipse,rgba(74,23,168,.28),transparent 70%);
  filter:blur(8px);animation:shadow 7s ease-in-out infinite;
}
body.nf-landing .stage__note {
  margin-top:18px;font-size:12px;line-height:1.55;color:#5F4A6B;
  max-width:330px;text-align:center;margin-inline:auto;
}
body.nf-landing .spark {position:absolute;width:11px;height:11px;background:var(--orange);animation:twinkle 3.2s ease-in-out infinite;}
body.nf-landing .spark--1 {top:24px;left:34px;width:14px;height:14px;}
body.nf-landing .spark--2 {top:74px;right:26px;animation-duration:2.6s;animation-delay:.6s;}
body.nf-landing .spark--3 {bottom:62px;left:18px;width:9px;height:9px;animation-duration:3.8s;animation-delay:1.1s;}

body.nf-landing .nie {
  position:relative;width:290px;height:410px;border-radius:5px;overflow:hidden;
  background:#fffdf9;color:#2a2320;transform-style:preserve-3d;
  animation:idfloat 7s ease-in-out infinite;
  box-shadow:0 46px 80px -22px rgba(74,23,168,.38),0 6px 18px rgba(0,0,0,.12),inset 0 0 0 1px rgba(0,0,0,.05);
}
body.nf-landing .nie__bar {
  position:absolute;top:0;left:0;right:0;height:5px;
  background:linear-gradient(90deg,var(--primary),var(--amber),var(--accent));
}
/* SPECIMEN band — marks the certificate as a facsimile.
   Kept in normal flow (no rotation): a rotated child inside the
   card's preserve-3d context gets projected and skews. */
body.nf-landing .nie__specimen {
  position:relative;z-index:4;margin:5px 0 0;
  background:var(--grad-brand);color:#fff;text-align:center;padding:4px 6px;
  font-size:6px;font-weight:700;letter-spacing:.16em;
}
body.nf-landing .nie__frame {position:absolute;inset:9px;border:1.5px double rgba(74,23,168,.24);border-radius:2px;}
body.nf-landing .nie__watermark {
  position:absolute;inset:0;display:grid;place-items:center;
  font-weight:700;font-size:46px;letter-spacing:2px;white-space:nowrap;
  color:rgba(74,23,168,.07);transform:rotate(-32deg);
}
body.nf-landing .nie__holo {
  position:absolute;bottom:58px;left:16px;width:26px;height:26px;border-radius:6px;
  background:conic-gradient(from 0deg,#6D28E8,#A833D8,#F42C7A,#4A17A8,#6D28E8);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.7);animation:spin 6s linear infinite;
}
body.nf-landing .nie__head {position:relative;padding:12px 16px 8px;display:flex;justify-content:space-between;align-items:flex-start;gap:8px;}
body.nf-landing .nie__issuer {display:flex;align-items:center;gap:7px;}
body.nf-landing .seal-sm {
  position:relative;width:30px;height:30px;flex:none;border-radius:50%;
  border:2px solid rgba(74,23,168,.55);display:grid;place-items:center;
  font-weight:700;font-size:11px;color:var(--primary);
}
body.nf-landing .seal-sm::after {content:"";position:absolute;inset:3px;border-radius:50%;border:1px solid rgba(74,23,168,.4);}
body.nf-landing .nie__org {font-weight:700;font-size:9px;letter-spacing:.3px;line-height:1.1;}
body.nf-landing .nie__dept {font-size:6px;letter-spacing:.06em;color:#9a8b90;margin-top:1px;}
body.nf-landing .nie__authtxt {text-align:right;font-size:5px;line-height:1.55;letter-spacing:.03em;color:#7a6f6c;}
body.nf-landing .nie__officer {position:relative;padding:14px 22px 0;font-size:7px;line-height:1.5;}
body.nf-landing .nie__body {position:relative;padding:9px 22px 0;font-size:7px;line-height:1.62;text-align:justify;}
body.nf-landing .nie__number {
  position:relative;margin:16px auto 0;width:168px;padding:9px 10px 7px;text-align:center;
  border:1.4px solid #2a2320;border-radius:2px;background:rgba(168,51,216,.1);
}
body.nf-landing .nie__number span {
  position:absolute;top:-7px;left:50%;transform:translateX(-50%);
  background:#fffdf9;padding:0 6px;font-size:7px;font-weight:700;letter-spacing:.12em;
}
body.nf-landing .nie__number strong {font-size:17px;letter-spacing:3px;color:var(--primary);}
body.nf-landing .nie__closing {position:relative;padding:14px 22px 0;font-size:7px;line-height:1.62;}
body.nf-landing .nie__foot {
  position:absolute;left:0;right:0;bottom:0;padding:6px 18px 14px;
  display:flex;justify-content:space-between;align-items:flex-end;gap:8px;
}
body.nf-landing .nie__qr {
  width:34px;height:34px;border:1px solid #2a2320;background-color:#fff;
  background-image:repeating-linear-gradient(90deg,#2a2320 0 3px,transparent 3px 6px),
                   repeating-linear-gradient(0deg,#2a2320 0 3px,transparent 3px 6px);
}
body.nf-landing .nie__csv {font-size:4.5px;color:#9a8b90;margin-top:2px;}
body.nf-landing .nie__sign {flex:1;text-align:center;}
body.nf-landing .nie__signlabel {font-size:7px;}
body.nf-landing .nie__signature {font-style:italic;font-weight:700;font-size:12px;color:#2a3a7a;transform:rotate(-3deg);}
body.nf-landing .nie__signrule {
  display:inline-block;width:88px;margin-top:1px;padding-top:1px;
  border-top:1px solid rgba(0,0,0,.3);font-size:5px;color:#9a8b90;
}
body.nf-landing .nie__seal {
  position:relative;width:48px;height:48px;flex:none;border-radius:50%;
  border:2px solid rgba(74,23,168,.45);color:rgba(74,23,168,.62);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  transform:rotate(-12deg);font-size:5px;letter-spacing:.08em;
}
body.nf-landing .nie__seal::after {content:"";position:absolute;inset:4px;border-radius:50%;border:1px solid rgba(74,23,168,.35);}
body.nf-landing .nie__seal b {font-size:12px;}
body.nf-landing .nie__sheen {
  position:absolute;inset:0;pointer-events:none;transform:translateX(-130%);
  background:linear-gradient(115deg,transparent 38%,rgba(255,255,255,.55) 50%,transparent 62%);
  animation:sheen 5.5s ease-in-out infinite;
}
body.nf-landing .nie__scan {
  position:absolute;left:0;right:0;top:7%;height:2.5px;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(196,43,199,.55),transparent);
  box-shadow:0 0 12px 2px rgba(196,43,199,.28);animation:scan 4.5s ease-in-out infinite;
}

/* ============================================================
   Animations
   ============================================================ */
@keyframes idfloat {
  0%{transform:translateY(0) rotateX(6deg) rotateY(-12deg);}
  50%{transform:translateY(-18px) rotateX(6deg) rotateY(12deg);}
  100%{transform:translateY(0) rotateX(6deg) rotateY(-12deg);}
}
@keyframes shadow {0%,100%{transform:translateX(-50%) scale(1);opacity:.5;}50%{transform:translateX(-50%) scale(.8);opacity:.3;}}
@keyframes sheen {0%{transform:translateX(-130%);}55%,100%{transform:translateX(130%);}}
@keyframes scan {0%{top:7%;opacity:0;}12%,88%{opacity:1;}100%{top:90%;opacity:0;}}
@keyframes spin {to{transform:rotate(360deg);}}
@keyframes twinkle {0%,100%{transform:scale(.6) rotate(45deg);opacity:.25;}50%{transform:scale(1) rotate(45deg);opacity:.9;}}
@keyframes pulse {0%,100%{transform:scale(1);opacity:1;}50%{transform:scale(1.35);opacity:.55;}}
@keyframes floaty {0%,100%{transform:translateY(0);}50%{transform:translateY(-12px);}}

@media (prefers-reduced-motion:reduce) {body.nf-landing * {animation:none !important;transition:none !important;}}
@media (prefers-contrast:more) {
  body.nf-landing .lead,
body.nf-landing .microcopy,
body.nf-landing .stage__note {color:#1A0A26;}
  body.nf-landing .dots {display:none;}
}

@media (max-width:940px) {
  body.nf-landing .nie {width:250px;height:376px;}
  body.nf-landing .stage {min-height:0;padding:24px 0 8px;}
}
@media (max-width:600px) {
  body.nf-landing .form {flex-direction:column;}
}

/* ============================================================
   Niefy.es — Landing page (landing.html)
   Depends on: tokens.css, base.css
   ============================================================ */

/* ---------- shared section furniture ---------- */
body.nf-landing .wrap {width:100%;max-width:var(--wrap);margin-inline:auto;}
body.nf-landing .section {padding:var(--sec-y) 44px;border-top:1px solid var(--line);}
/* El antetítulo iba a 13px con mucho interletrado: a esa medida el espaciado que le da carácter es lo
   mismo que lo hace costar de leer. Sube con `clamp`, que escala con el ancho sin necesitar una regla
   por pantalla: 14px en un móvil, 16 en un escritorio grande. */
body.nf-landing .eyebrow {font-size:clamp(14px,1.05vw,16px);font-weight:700;letter-spacing:.16em;color:var(--brick);}
body.nf-landing .h2 {
  font-size:38px;font-weight:700;letter-spacing:-1px;line-height:1.06;
  margin-top:14px;text-wrap:pretty;
}
body.nf-landing .lead {font-size:16px;line-height:1.55;color:var(--muted);max-width:560px;margin-top:16px;}

/* ============================================================
   Header + hero
   ============================================================ */
body.nf-landing .site-head {
  position:relative;z-index:7;display:flex;justify-content:space-between;
  align-items:center;gap:24px;width:100%;max-width:1280px;
  margin-inline:auto;padding:26px 44px;
}
body.nf-landing .brand {display:flex;align-items:center;}
body.nf-landing .brand__logo {height:64px;width:auto;}
body.nf-landing .site-nav {display:flex;gap:30px;font-size:15px;font-weight:700;}
body.nf-landing .site-nav a {color:var(--red);min-height:44px;display:flex;align-items:center;}
body.nf-landing .site-nav a:hover {color:var(--primary);}

body.nf-landing .hero {position:relative;z-index:1;padding:32px 44px 76px;}
body.nf-landing .hero__inner {
  width:100%;max-width:var(--wrap);margin-inline:auto;
  display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:56px;
}
body.nf-landing .hero__title {
  font-size:clamp(34px,4vw,48px);line-height:1.03;font-weight:700;
  letter-spacing:-1.5px;margin-top:20px;text-wrap:pretty;
}
body.nf-landing .hero__sub {font-size:17px;line-height:1.6;color:var(--muted);max-width:460px;margin-top:18px;}
body.nf-landing .hero__cta {display:flex;flex-wrap:wrap;gap:12px;margin-top:28px;}
/* Los tres puntos del hero van SIEMPRE en columna, uno por línea. Iban en fila con salto automático, así
   que el número de columnas dependía del ancho que sobrara: dos y media en escritorio, dos en tableta,
   una en móvil. Una lista de garantías que se recoloca sola en cada pantalla se lee como una sucesión de
   fragmentos, no como tres promesas.
   Al ocupar una sola columna cabe más cuerpo, así que sube de 13px a 15 (17 en escritorio, abajo). */
body.nf-landing .hero__meta {
  display:flex;flex-direction:column;gap:10px;margin-top:26px;
  font-size:15px;font-weight:700;color:var(--red);
}
@media (min-width:941px) {
  body.nf-landing .hero__meta {font-size:17px;gap:12px;}
}
body.nf-landing .hero__meta li {display:flex;align-items:center;gap:10px;}
body.nf-landing .hero__meta svg {flex:none;width:20px;height:20px;color:var(--brick);}

/* ============================================================
   Trust strip
   ============================================================ */
body.nf-landing .trust {
  position:relative;z-index:1;background:var(--primary);color:#fff;padding:22px 44px;
}
body.nf-landing .trust__inner {
  width:100%;max-width:var(--wrap);margin-inline:auto;
  display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:18px;
}
body.nf-landing .trust__rating {display:flex;align-items:center;gap:12px;}
body.nf-landing .trust__stars {color:var(--sand);font-size:18px;letter-spacing:2px;}
body.nf-landing .trust__score {font-size:14px;font-weight:700;color:#F7F1FF;}
body.nf-landing .trust__points {
  display:flex;align-items:center;gap:26px;flex-wrap:wrap;
  font-size:14px;font-weight:700;color:#E4D6F5;
}
body.nf-landing .trust__points li {display:flex;align-items:center;gap:10px;}
body.nf-landing .trust__points svg {flex:none;width:19px;height:19px;color:var(--sand);}

/* ============================================================
   Benefits — glass cards on a tinted band
   ============================================================ */
body.nf-landing .benefits {
  position:relative;z-index:1;padding:var(--sec-y) 44px;overflow:hidden;
  background:linear-gradient(135deg,#FDF7FF 0%,#F5E8FF 55%,#FBE0F0 100%);
}
body.nf-landing .benefits__blob {position:absolute;border-radius:50%;filter:blur(10px);pointer-events:none;}
body.nf-landing .benefits__blob--a {
  width:380px;height:380px;top:-120px;right:8%;
  background:radial-gradient(circle,rgba(243,196,255,.85),transparent 68%);
}
body.nf-landing .benefits__blob--b {
  width:320px;height:320px;bottom:-140px;left:6%;
  background:radial-gradient(circle,rgba(255,255,255,.6),transparent 66%);
}
body.nf-landing .benefits .wrap {position:relative;}
body.nf-landing .grid-3 {display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:var(--gap-titulo);}
/* Mismo criterio que los pasos: el icono y su título EN LA MISMA LÍNEA. Apilados, el icono quedaba
   como un adorno sin dueño y el titular empezaba la tarjeta por su cuenta. */
body.nf-landing .glass {
  display:grid;grid-template-columns:48px 1fr;column-gap:14px;align-items:center;align-content:start;
  background:rgba(255,255,255,.78);
  -webkit-backdrop-filter:blur(22px) saturate(160%);
          backdrop-filter:blur(22px) saturate(160%);
  border:1px solid rgba(255,255,255,.9);border-radius:22px;padding:30px 26px;
  box-shadow:0 18px 40px -20px rgba(74,23,168,.2),inset 0 1px 0 #fff;
  transition:transform .25s ease,box-shadow .25s ease;
}
body.nf-landing .glass:hover {
  transform:translateY(-4px);
  box-shadow:0 26px 52px -20px rgba(74,23,168,.26),inset 0 1px 0 #fff;
}
body.nf-landing .glass h3 {grid-column:2;grid-row:1;font-size:19px;font-weight:700;color:var(--ink);margin:0;line-height:1.3;}
body.nf-landing .glass p {grid-column:1 / -1;grid-row:2;margin-top:16px;font-size:15px;line-height:1.6;color:var(--muted);}
body.nf-landing .glass__icon {
  grid-column:1;grid-row:1;width:48px;height:48px;border-radius:14px;
  display:grid;place-items:center;background:var(--card);border:1px solid var(--line);
  box-shadow:0 4px 10px -4px rgba(74,23,168,.16);
}
/* CSS-drawn glyphs */
body.nf-landing .ico-noqueue {width:24px;height:24px;border-radius:50%;border:2px solid var(--primary);position:relative;}
body.nf-landing .ico-noqueue::after {
  content:"";position:absolute;left:50%;top:50%;width:14px;height:2px;
  background:var(--primary);transform:translate(-50%,-50%) rotate(-45deg);
}
body.nf-landing .ico-check {width:24px;height:24px;border-radius:50%;border:2px solid var(--red);position:relative;}
body.nf-landing .ico-check::after {
  content:"";position:absolute;left:50%;top:50%;width:9px;height:5px;
  border-left:2px solid var(--red);border-bottom:2px solid var(--red);
  transform:translate(-50%,-65%) rotate(-45deg);
}
body.nf-landing .ico-doc {width:18px;height:24px;border:2px solid var(--brick);border-radius:3px;position:relative;}
body.nf-landing .ico-doc::after {
  content:"";position:absolute;left:3px;right:3px;top:5px;height:2px;
  background:var(--brick);box-shadow:0 4px 0 var(--brick),0 8px 0 var(--brick);
}

/* ============================================================
   Use cases
   ============================================================ */
body.nf-landing .usecases {background:var(--card);}
body.nf-landing .grid-cases {display:grid;grid-template-columns:repeat(3,1fr);gap:28px 36px;margin-top:var(--gap-titulo);}
body.nf-landing .case {display:flex;gap:14px;}
/* La viñeta era un cuadrado de 14px, idéntico en los seis casos. Ahora es la placa que sostiene el icono
   de cada uno: fondo tenue de marca y el trazo en primario, que hereda por `currentColor`. */
body.nf-landing .case__marker {
  flex:none;display:grid;place-items:center;margin-top:2px;
  width:36px;height:36px;border-radius:11px;
  background:color-mix(in srgb,var(--primary) 12%,transparent);
  color:var(--primary);
}
body.nf-landing .case__marker svg {width:20px;height:20px;}
body.nf-landing .case h3 {font-size:17px;font-weight:700;margin-bottom:6px;}
body.nf-landing .case p {font-size:15px;line-height:1.65;color:var(--muted);}

/* ============================================================
   How it works
   ============================================================ */
body.nf-landing .steps-section {background:var(--soft);}
body.nf-landing .steps {display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:var(--gap-titulo);}
/* El número y el título van EN LA MISMA LÍNEA: la viñeta numera el paso, así que separarla de su
   enunciado dejaba un círculo suelto y, debajo, un titular que no se leía como suyo.
   Rejilla de dos columnas —viñeta | título— y el párrafo cruzando las dos por debajo. */
body.nf-landing .step {
  position:relative;display:grid;grid-template-columns:42px 1fr;
  column-gap:14px;align-items:center;align-content:start;
}
body.nf-landing .step__num {
  grid-column:1;grid-row:1;
  width:42px;height:42px;border-radius:50%;background:var(--primary);color:var(--sand);
  display:grid;place-items:center;font-weight:700;font-size:16px;
}
/* El hilo de puntos que unía un paso con el siguiente SE RETIRA: salía a la altura del centro de la
   viñeta, que es justo donde ahora está el título, y le habría pasado por encima. La numeración ya
   dice el orden por sí sola. */
body.nf-landing .step h3 {grid-column:2;grid-row:1;font-size:17px;font-weight:700;margin:0;line-height:1.3;}
body.nf-landing .step p {grid-column:1 / -1;grid-row:2;margin-top:14px;font-size:15px;line-height:1.65;color:var(--muted);}

/* ============================================================
   Pricing
   ============================================================ */
/* La banda va en `--soft` y las tarjetas en `--card`: antes la sección era #fff FIJO y la tarjeta
   `--paper`, así que en oscuro quedaba una plancha blanca, y en claro la tarjeta apenas se despegaba
   del fondo (#FAF5FF sobre #FFF). Con dos tokens la tarjeta se lee como tarjeta en los dos temas. */
body.nf-landing .pricing {background:var(--soft);}
body.nf-landing .pricing .h2 {text-align:center;margin-top:0;}

/* ---------- Requisitos previos, sobre los planes ----------
   Dos condiciones que hay que cumplir para que este servicio sirva de algo, dichas donde todavía no ha
   pagado nadie. Comparten la retícula, el radio y la caja de los planes que tienen debajo a propósito: son
   parte de la oferta —lo que hay que traer— y no una advertencia pegada encima de ella. El acento va en la
   marca y no en ámbar; el ámbar es el idioma del área privada, y aquí no dice «cuidado», dice «esto hace
   falta». Todo con los tokens de la portada, así que el tema oscuro sale solo. */
body.nf-landing .requisitos {max-width:1000px;margin:var(--gap-titulo) auto 0;}
/* El rótulo NO trae tipografía ni color propios: lleva además `.eyebrow`, que es como esta portada escribe
   sus rótulos de sección desde que existe —beneficios, comparativa, casos y pasos usan el mismo—. Aquí solo
   se le dice dónde va. Declararlo aparte habría sido un quinto rótulo con su propio tamaño y su propio
   interletrado, que es como una hoja acaba teniendo cuatro maneras de escribir lo mismo. */
body.nf-landing .requisitos__intro {margin:0 0 20px;text-align:center;}
body.nf-landing .requisitos__lista {
  display:grid;grid-template-columns:repeat(2,1fr);gap:26px;align-items:stretch;
  margin:0;padding:0;list-style:none;
}
body.nf-landing .requisitos__item {
  display:flex;flex-direction:column;
  padding:26px 28px;border-radius:var(--radius);
  background:var(--card);border:1px solid var(--line);
}
/* El disco tintado, no relleno: a plena marca competía con el botón de comprar, que es lo único de esta
   sección que tiene que llamar. */
body.nf-landing .requisitos__ico {
  display:inline-flex;align-items:center;justify-content:center;
  width:46px;height:46px;flex:0 0 auto;margin-bottom:16px;border-radius:50%;
  background:color-mix(in srgb, var(--primary) 12%, transparent);
  color:var(--primary);
}
body.nf-landing .requisitos__tit {margin:0 0 8px;font-size:17px;font-weight:700;line-height:1.35;color:var(--ink);}
body.nf-landing .requisitos__txt {margin:0;font-size:14.5px;line-height:1.6;color:var(--muted);}
:is(body.nf-landing, .nf-planes) .plans {
  display:grid;grid-template-columns:repeat(2,1fr);gap:26px;
  margin:var(--gap-titulo) auto 0;max-width:1000px;align-items:stretch;
}
:is(body.nf-landing, .nf-planes) .plan {
  position:relative;display:flex;flex-direction:column;border-radius:var(--radius);
  padding:36px 32px 32px;background:var(--card);border:1px solid var(--line);
  transition:transform .25s ease,box-shadow .25s ease;
}
:is(body.nf-landing, .nf-planes) .plan:hover {transform:translateY(-4px);box-shadow:0 22px 44px -26px rgba(74,23,168,.35);}

/* El rótulo reserva el ancho del distintivo: va absoluto arriba a la derecha y un nombre de nivel
   largo se le metía debajo. */
:is(body.nf-landing, .nf-planes) .plan__label {margin:0;padding-right:120px;font-size:14px;font-weight:700;letter-spacing:.04em;color:var(--brick);}

/* El precio cierra su bloque con una regla: separa «cuánto cuesta» de «qué incluye» sin depender de
   que el ojo lo deduzca del espaciado. */
:is(body.nf-landing, .nf-planes) .plan__price {
  display:flex;align-items:baseline;gap:8px;
  margin:14px 0 26px;padding-bottom:26px;border-bottom:1px solid var(--line);
}
/* El titular va en monoespaciada, y ahí el espacio que separa cifra y símbolo mide lo mismo que un
   dígito: a 52px abría un hueco de «150     €». Se recorta con word-spacing en vez de tocar
   `Formato::dinero`, que escribe el importe para TODA la app y no debe llevar el ancho de una tipografía
   concreta metido en la cadena. */
:is(body.nf-landing, .nf-planes) .plan__price b {
  font-size:52px;font-weight:700;letter-spacing:-2px;word-spacing:-.28em;
  line-height:1;color:var(--ink);font-variant-numeric:tabular-nums;
}
:is(body.nf-landing, .nf-planes) .plan__price small {font-size:15px;color:var(--muted);}

/* Lema del nivel: la frase que dice qué papel juega el cliente. Va entre el precio y la lista, con su
   propio peso: si se pareciera a un ✓ más, se leería como parte de la lista y no como su resumen. */
:is(body.nf-landing, .nf-planes) .plan__lema {
  margin:0 0 20px;font-size:14.5px;line-height:1.5;font-weight:600;color:var(--muted);
}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__lema {color:rgba(255,255,255,.92);}

/* ---- Comparativa entre niveles ----------------------------------------------------------------- */
body.nf-landing .compara {background:var(--soft);}
body.nf-landing .compara .lead {max-width:760px;margin-top:14px;}
/* El nombre del nivel, dentro de la frase: es el sujeto de la comparación. */
body.nf-landing .compara__nivel {color:var(--h-1);font-weight:700;}

/* Lo que te ahorras va en TARJETA: es una lista de ausencias, y suelta sobre el fondo se leía como una
   enumeración más del texto que la rodea. Encerrada se lee como lo que es, un bloque aparte. */
body.nf-landing .compara__card {
  margin-top:26px;max-width:760px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:24px 26px;box-shadow:0 14px 34px -26px rgba(74,23,168,.30);
}
body.nf-landing .compara__evitas {margin:0;font-weight:700;color:var(--ink);}
/* Lista de lo que NO hay que hacer: la marca es un aspa, no un ✓. Un ✓ delante de «el poder notarial»
   se lee como que lo incluye, que es justo lo contrario de lo que dice. */
body.nf-landing .compara__lista {
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 26px;
  margin-top:16px;font-size:15px;line-height:1.5;color:var(--muted);
}
body.nf-landing .compara__lista li {display:flex;gap:10px;align-items:flex-start;}
body.nf-landing .compara__lista span {flex:none;font-weight:700;color:var(--brick);line-height:1.5;}
body.nf-landing .compara__cambio {margin-top:24px;max-width:760px;font-size:15px;line-height:1.65;color:var(--muted);}
body.nf-landing .compara__cierre {
  margin:22px 0 0;padding-top:20px;border-top:1px solid var(--line);
  font-size:19px;font-weight:700;color:var(--ink);text-align:center;
}
body.nf-landing .compara__cta {margin-top:1.2rem;text-align:center;}
body.nf-landing .compara__nota {margin-top:14px;text-align:center;font-size:13px;line-height:1.6;color:var(--muted);}
@media (max-width:640px){
  body.nf-landing .compara__lista {grid-template-columns:1fr;}
}

:is(body.nf-landing, .nf-planes) .plan__features {
  display:flex;flex-direction:column;gap:14px;margin:0 0 24px;
  font-size:14.5px;line-height:1.55;color:var(--muted);
}
:is(body.nf-landing, .nf-planes) .plan__features li {display:flex;gap:10px;align-items:flex-start;}
:is(body.nf-landing, .nf-planes) .plan__features i {font-style:normal;font-weight:700;color:var(--red);line-height:1.55;}

/* La nota de exclusión NO tenía regla propia: heredaba el margen del navegador y se pegaba a la lista
   o al botón según el nivel. */
:is(body.nf-landing, .nf-planes) .plan__note {
  margin:0 0 22px;font-size:13px;line-height:1.55;color:var(--muted);opacity:.9;
}
:is(body.nf-landing, .nf-planes) .plan .btn {width:100%;margin-top:auto;padding:15px;}

/* ---- El recomendado ---------------------------------------------------------------------------
   Se levanta sobre los demás y lleva el degradado de marca en vez del plano `--primary`. El plano
   era además un fallo en oscuro: allí `--primary` se aclara a #A97BF5 y el texto blanco encima se
   quedaba en 2,4:1. El degradado no cambia con el tema, así que el blanco aguanta en los dos.
   Las animaciones caen solas con `prefers-reduced-motion` (regla global más arriba). */
:is(body.nf-landing, .nf-planes) .plan--priority {
  background:var(--grad-brand);border-color:transparent;color:#fff;
  transform:translateY(-10px);z-index:1;
  box-shadow:0 30px 60px -26px rgba(74,23,168,.65),0 4px 14px rgba(0,0,0,.10);
}
:is(body.nf-landing, .nf-planes) .plan--priority:hover {
  transform:translateY(-16px);
  box-shadow:0 40px 74px -26px rgba(74,23,168,.72),0 6px 18px rgba(0,0,0,.12);
}
/* Halo que respira por detrás de la tarjeta. Va en un pseudoelemento y no en la sombra para que el
   pulso no arrastre repintados del contenido. */
:is(body.nf-landing, .nf-planes) .plan--priority::before {
  content:'';position:absolute;inset:-2px;border-radius:calc(var(--radius) + 2px);z-index:-1;
  background:var(--grad-brand);filter:blur(16px);opacity:.42;
  animation:planPulse 4.5s ease-in-out infinite;
}
/* Y un filo de luz interior, que es lo que da el acabado de «pieza destacada» sin subir el ruido. */
:is(body.nf-landing, .nf-planes) .plan--priority::after {
  content:'';position:absolute;inset:0;border-radius:var(--radius);pointer-events:none;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.38),inset 0 0 0 1px rgba(255,255,255,.16);
}
@keyframes planPulse {
  0%,100%{opacity:.34;transform:scale(.99);}
  50%    {opacity:.55;transform:scale(1.015);}
}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__label {color:var(--sand);}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__price {border-bottom-color:rgba(255,255,255,.22);}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__price b {color:#fff;}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__price small {color:rgba(255,255,255,.72);}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__features {color:rgba(255,255,255,.90);}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__features i {color:var(--sand);}
:is(body.nf-landing, .nf-planes) .plan--priority .plan__note {color:rgba(255,255,255,.78);}
:is(body.nf-landing, .nf-planes) .plan--priority .btn {background:var(--sand);color:var(--primary-deep);box-shadow:none;}
:is(body.nf-landing, .nf-planes) .plan--priority .btn:hover {background:#fff;color:var(--primary-deep);}

/* El distintivo del nivel recomendado viaja con la tarjeta: el alta usa las mismas y sin esto salía como
   texto suelto encima del nombre, que es justo lo contrario de un distintivo. */
:is(body.nf-landing, .nf-planes) .badge-tag {
  position:absolute;top:24px;right:24px;background:var(--sand);color:var(--primary-deep);
  font-size:11px;font-weight:700;letter-spacing:.04em;padding:5px 12px;border-radius:20px;
  box-shadow:0 4px 12px rgba(43,11,99,.28);
}

/* Apilados en una columna, levantar el recomendado solo abre un hueco raro entre tarjetas. */
@media (max-width:860px) {
  :is(body.nf-landing, .nf-planes) .plan--priority,
:is(body.nf-landing, .nf-planes) .plan--priority:hover,
:is(body.nf-landing, .nf-planes) .plan:hover {transform:none;}
}
body.nf-landing .pricing__note {
  font-size:13px;line-height:1.6;color:var(--muted);
  margin:24px auto 0;max-width:760px;text-align:center;
}

/* ============================================================
   FAQ — native details/summary
   ============================================================ */
body.nf-landing .faq {background:var(--paper);}
body.nf-landing .faq .wrap {max-width:820px;}
body.nf-landing .faq .h2 {margin:0 0 var(--gap-titulo);}
body.nf-landing .faq details {border-bottom:1px solid var(--line);}
body.nf-landing .faq summary {
  display:flex;justify-content:space-between;align-items:center;gap:16px;
  min-height:44px;padding:22px 4px;cursor:pointer;
  font-size:17px;font-weight:700;list-style:none;
}
body.nf-landing .faq summary::-webkit-details-marker {display:none;}
body.nf-landing .faq summary::after {
  content:"+";font-size:24px;color:var(--brick);flex:none;width:24px;text-align:center;
}
body.nf-landing .faq details[open] summary::after {content:"–";}
body.nf-landing .faq p {padding:0 4px 24px;font-size:15px;line-height:1.65;color:var(--muted);max-width:720px;}

/* ============================================================
   Closing CTA
   ============================================================ */
/* El degradado del cierre baja hacia el pie. Su color final estaba escrito a mano en rosa pálido, así
   que en oscuro la página se ENCENDÍA justo antes del pie, que es negro: el salto era brutal. Pasa a
   token y en oscuro desciende hacia el propio pie en vez de subir hacia el blanco. */
body.nf-landing .cta {
  background:linear-gradient(180deg,var(--paper),var(--cta-fin));
  /* Sin aire propio arriba: el cierre remata la sección anterior, y esa ya aporta el suyo por
     abajo. Con los dos, la tarjeta caía a casi 200px de lo último que se ha leído. */
  padding:0 44px var(--sec-y);
}
body.nf-landing .cta__card {
  width:100%;max-width:760px;margin-inline:auto;text-align:center;
  background:var(--card);border:1px solid var(--line);border-radius:26px;
  /* Arriba −40 % y abajo −10 % sobre los 52px originales: la llamada se leía con demasiado aire por
     encima del titular, que es lo primero que hay que ver al llegar aquí. */
  padding:31px 40px 47px;box-shadow:0 24px 60px -30px rgba(74,23,168,.26);
}
body.nf-landing .cta h2 {
  font-size:clamp(30px,3.4vw,42px);font-weight:700;letter-spacing:-1.2px;
  line-height:1.04;margin-bottom:14px;text-wrap:pretty;
}
body.nf-landing .cta__lead {font-size:16px;line-height:1.5;color:var(--muted);margin-bottom:8px;}
body.nf-landing .cta .form {margin-inline:auto;}
body.nf-landing .cta .microcopy {margin-inline:auto;}

/* ============================================================
   Footer
   ============================================================ */
body.nf-landing .site-foot {background:var(--primary-deep);color:#E4D6F5;padding:56px 44px 48px;}
body.nf-landing .site-foot__top {
  width:100%;max-width:var(--wrap);margin-inline:auto;
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:40px;
}
body.nf-landing .site-foot__about {max-width:460px;}
/* Logo a la izquierda y descripción a su derecha, en una sola fila. Antes iban apilados y la columna
   quedaba estrecha y alta al lado de los enlaces. */
body.nf-landing .site-foot__marca {display:flex;align-items:center;gap:18px;flex-wrap:wrap;}
/* El logo NO se encoge. Iba en una fila flex, y el reparto por defecto —más el `max-width:100%` del reset—
   le recortaba el ANCHO mientras la altura seguía clavada en 52px: la península salía aplastada en cuanto
   la columna se estrechaba. Con `flex:none` conserva su proporción, y si no cabe junto al texto la fila
   parte en dos, que es lo que debe pasar. */
body.nf-landing .site-foot__marca .brand {flex:none;}
body.nf-landing .site-foot .brand__logo {height:52px;width:auto;max-width:none;filter:brightness(0) invert(1);opacity:.95;}
body.nf-landing .site-foot__marca p {flex:1 1 240px;min-width:0;font-size:13px;line-height:1.6;color:#B9A3D4;margin:0;}
body.nf-landing .site-foot__legal {font-size:12px;color:#B9A3D4;margin-top:18px;}
body.nf-landing .site-foot__cols {display:flex;gap:64px;flex-wrap:wrap;}
body.nf-landing .site-foot__title {font-size:12px;font-weight:700;letter-spacing:.1em;color:#fff;margin-bottom:14px;}
body.nf-landing .site-foot__cols ul {display:flex;flex-direction:column;font-size:13px;}
body.nf-landing .site-foot__cols a {color:#CBB4E6;min-height:44px;display:flex;align-items:center;}
body.nf-landing .site-foot__cols a:hover {color:#fff;}
body.nf-landing .site-foot__bottom {
  width:100%;max-width:var(--wrap);margin:40px auto 0;padding-top:24px;
  border-top:1px solid #46208A;font-size:12px;color:#B9A3D4;
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;
}
body.nf-landing .site-foot__bottom a {color:var(--sand);}
body.nf-landing .site-foot__bottom a:hover {color:#fff;}

/* ============================================================
   Responsive
   ============================================================ */
@media (prefers-contrast:more) {
  body.nf-landing .case p,
body.nf-landing .step p,
body.nf-landing .glass p,
:is(body.nf-landing, .nf-planes) .plan__features,
body.nf-landing .faq p {color:#1A0A26;}
}
@media (max-width:1024px) {
  body.nf-landing .grid-3,
body.nf-landing .grid-cases {grid-template-columns:repeat(2,1fr);}
  body.nf-landing .steps {grid-template-columns:repeat(2,1fr);}
  body.nf-landing .site-nav {display:none;}
}
@media (max-width:940px) {
  body.nf-landing .hero__inner {grid-template-columns:1fr;gap:8px;}
  body.nf-landing .hero {padding:24px 44px 56px;}
  body.nf-landing .brand__logo {height:56px;}
}
@media (max-width:860px) {
  body.nf-landing .section,
body.nf-landing .benefits,
body.nf-landing .trust,
body.nf-landing .cta {padding-left:24px;padding-right:24px;}
  body.nf-landing {--sec-y:64px;--gap-titulo:34px;}
  body.nf-landing .site-head {padding:22px 24px;}
  body.nf-landing .hero {padding:16px 24px 48px;}
  body.nf-landing .h2 {font-size:30px;}
  body.nf-landing .grid-3,
body.nf-landing .grid-cases,
body.nf-landing .steps,
body.nf-landing .requisitos__lista,
:is(body.nf-landing, .nf-planes) .plans {grid-template-columns:1fr;}
  body.nf-landing .cta__card {padding:24px 24px 36px;}
  body.nf-landing .site-foot {padding:44px 24px 36px;}
  /* Si la fila de marca se parte —logo arriba, descripción debajo—, el bloque queda descolgado a la
     izquierda con medio pie vacío a la derecha. En estrecho se centra TODO el pie: marca, aviso de
     derechos y las dos columnas de enlaces. Los enlaces son cajas flex a lo ancho, así que además de
     centrar la columna hay que centrar su contenido, o el texto se quedaría pegado al borde. */
  body.nf-landing .site-foot__top {justify-content:center;text-align:center;}
  body.nf-landing .site-foot__about {max-width:none;}
  body.nf-landing .site-foot__marca {justify-content:center;}
  body.nf-landing .site-foot__cols {justify-content:center;gap:44px;}
  body.nf-landing .site-foot__cols a {justify-content:center;}

  /* En pantalla estrecha el hero se queda con UNA sola llamada. Los dos botones apilados hacen que la
     principal y la secundaria pesen lo mismo, y «cómo funciona» es además redundante: el propio scroll
     lleva a esa sección unos centímetros más abajo. El enlace sigue en la barra de navegación. */
  body.nf-landing .hero__cta .btn--soft {display:none;}

  /* Y sin el certificado ilustrativo: es decoración, ocupa una pantalla entera antes de llegar al
     precio y en móvil se escala hasta que sus advertencias de MUESTRA dejan de leerse. Una pieza que
     solo se sostiene si sus descargos son legibles no debe encogerse por debajo de eso: se retira. */
  body.nf-landing .stage-col {display:none;}

  /* Párrafos justificados. En una columna estrecha justificar SIN partición abre ríos de blanco entre
     palabras, así que va con `hyphens:auto` —que funciona porque el <html> lleva su `lang`— y con
     `text-wrap:pretty` para que no quede una palabra suelta en la última línea. Solo en móvil: en
     escritorio las columnas son anchas y el borde irregular se lee mejor. */
  body.nf-landing .hero__sub,
body.nf-landing .section p,
body.nf-landing .case p,
body.nf-landing .step p,
body.nf-landing .glass p,
body.nf-landing .faq p,
body.nf-landing .cta__lead,
:is(body.nf-landing, .nf-planes) .plan__note,
body.nf-landing .pricing__note {
    text-align:justify;text-justify:inter-word;hyphens:auto;text-wrap:pretty;
  }

  /* …menos el rótulo de los requisitos, que es un rótulo y no un párrafo. La regla de arriba lo alcanza por
     ser un <p> dentro de una sección, y justificar lo deja alineado a la IZQUIERDA —la última línea de un
     texto justificado no se estira—: en estrecho el rótulo se descolgaba del par de tarjetas que encabeza.
     Lleva `.pricing` delante para ganar por especificidad; sin él pierde contra `.section p`, que tiene una
     clase más, y la regla no hacía nada. */
  body.nf-landing .pricing .requisitos__intro {text-align:center;}
  /* La lista de ventajas NO se justifica: son frases de una línea con su ✓ delante, y justificarlas
     estiraría los espacios de una sola línea sin ganar nada. */
  :is(body.nf-landing, .nf-planes) .plan__features,
body.nf-landing .hero__meta,
body.nf-landing .trust__points {text-align:left;hyphens:manual;}

  /* Botones centrados y a lo ancho de la columna: apilados, un botón alineado a la izquierda deja la
     mitad derecha vacía y el pulgar no sabe dónde apuntar. */
  body.nf-landing .hero__cta,
body.nf-landing .cta__card,
body.nf-landing .cta__actions {justify-content:center;align-items:center;}
  body.nf-landing .hero__cta {width:100%;}
  body.nf-landing .hero__cta .btn {width:100%;max-width:340px;text-align:center;justify-content:center;}
  body.nf-landing .hero__sub {margin-left:auto;margin-right:auto;}
  :is(body.nf-landing, .nf-planes) .plan .btn {text-align:center;}
}

/* ==========================================================================
   MODO OSCURO
   Como todo el diseño lee de los tokens, basta con redefinirlos: es la promesa
   del propio README de NIEFY («a rebrand is a single-file change»).

   La rampa de marca original son violetas OSCUROS —pensados para ir sobre blanco—,
   así que sobre fondo oscuro desaparecen. No se «invierten»: se levantan a los
   equivalentes claros del mismo tono, y los contrastes están comprobados, no
   supuestos (ver el commit).

   El conmutador reutiliza el mecanismo de la app: `data-theme` en <html>,
   persistido en localStorage['nf-theme'] y fijado ANTES de pintar para evitar el
   parpadeo. Un tema que parpadea en cada carga es peor que no tenerlo.
   ========================================================================== */
[data-theme="dark"] body.nf-landing,
[data-theme="dark"] .nf-planes {
    /* Superficies */
    --paper: #150A21;
    --soft: #1D0F2E;
    --card: #241338;
    --line: #33224A;

    /* Neutros */
    --ink: #F4ECFB;
    --muted: #C0B2D0;

    /* Rampa de marca, levantada para que exista sobre fondo oscuro */
    --primary: #A97BF5;
    --primary-dark: #BF9AF8;
    --primary-deep: #0F0718;
    --red: #C98BEA;
    --brick: #FF8FBE;
    --accent: #FF6AA6;
    --sand: #F3C4FF;

    /* Titulares: el mismo degradado violeta → rosa, en su versión clara */
    --h-1: #B392F8;
    --h-2: #CE9AF2;
    --h-3: #EE8FD8;
    --h-4: #FF8FBE;

    /* Los degradados de botón se conservan: son de tono medio y el texto blanco
       encima sigue leyéndose. El de página sí se rehace, que era casi blanco. */
    --grad-page: linear-gradient(170deg, #1B0E2B 0%, #170C24 40%, #14091F 72%, #1A0A22 100%);
    --glow: radial-gradient(100% 70% at 50% 0%, rgba(169,123,245,.20) 0%, rgba(169,123,245,.07) 45%, transparent 72%);
}

/* La trama de puntos del fondo y los halos decorativos estaban calculados sobre
   claro; sobre oscuro quedaban como una niebla gris. Se atenúan. */
[data-theme="dark"] body.nf-landing .dots { opacity: .35; }
[data-theme="dark"] body.nf-landing .benefits__blob { opacity: .28; }

/* El certificado ilustrativo es papel: se queda claro a propósito, como se queda
   claro un documento real sobre una mesa oscura. Invertirlo lo haría irreconocible
   justo cuando su lectura importa (lleva las advertencias de MUESTRA). */
[data-theme="dark"] body.nf-landing .nie { color-scheme: light; }

/* ---- Superficies que estaban en BLANCO FIJO ----------------------------------------------------
   El tema se hizo redefiniendo tokens, y eso solo alcanza a lo que los usa. Estas reglas llevaban el
   blanco escrito a mano y en oscuro quedaban como planchas encendidas: la banda de casos de uso, las
   tarjetas de cristal, la tarjeta del cierre, el botón secundario y el campo de la lista de espera.
   Se corrigen aquí, en el bloque del tema, y no en la regla original: el diseño claro está aprobado y
   no hay motivo para tocarlo. */
[data-theme="dark"] body.nf-landing .usecases { background: var(--soft); }

/* Hacia el pie, no hacia el blanco. */
[data-theme="dark"] body.nf-landing { --cta-fin: #100719; }
[data-theme="dark"] body.nf-landing .case__marker { background: color-mix(in srgb, var(--primary) 20%, transparent); }

/* La banda de ventajas llevaba su propio degradado ROSA CLARO escrito a mano, así que en oscuro se
   quedaba como una franja encendida en mitad de la página — y con ella las tarjetas de cristal, que
   dependen de ese fondo para tener contraste. Se rehace en los mismos tonos, en su versión oscura. */
[data-theme="dark"] body.nf-landing .benefits {
    background: linear-gradient(135deg, #1E1030 0%, #241338 55%, #2B1338 100%);
}

[data-theme="dark"] body.nf-landing .glass {
    background: rgba(255, 255, 255, .055);
    border-color: rgba(255, 255, 255, .10);
    box-shadow: 0 18px 40px -20px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 255, 255, .07);
}
[data-theme="dark"] body.nf-landing .glass:hover {
    box-shadow: 0 26px 52px -20px rgba(0, 0, 0, .65), inset 0 1px 0 rgba(255, 255, 255, .07);
}
[data-theme="dark"] body.nf-landing .glass__icon { background: rgba(255, 255, 255, .08); }

[data-theme="dark"] body.nf-landing .cta__card { background: var(--card); }

/* El botón secundario es blanco con tinta violeta. En oscuro el blanco lo convierte en el elemento
   más luminoso de la página, por encima de la llamada PRINCIPAL: se invierte la jerarquía. Pasa a
   contorno sobre el fondo, que es lo que un botón secundario debe parecer. */
[data-theme="dark"] body.nf-landing .btn--soft {
    background: transparent;
    color: var(--primary);
    box-shadow: inset 0 0 0 1.5px var(--primary);
}
[data-theme="dark"] body.nf-landing .btn--soft:hover {
    background: rgba(169, 123, 245, .12);
    color: var(--primary-dark);
}

[data-theme="dark"] body.nf-landing .form input { background: var(--card); color: var(--ink); }

/* El modo de alto contraste forzaba tinta CASI NEGRA en el cuerpo de texto. Sobre fondo oscuro eso es
   negro sobre negro: el ajuste que existe para ayudar a leer dejaba la página ilegible. */
[data-theme="dark"] body.nf-landing .case p,
[data-theme="dark"] body.nf-landing .step p,
[data-theme="dark"] body.nf-landing .glass p,
[data-theme="dark"] body.nf-landing .faq p { color: var(--muted); }
@media (prefers-contrast: more) {
    [data-theme="dark"] body.nf-landing .case p,
[data-theme="dark"] body.nf-landing .step p,
[data-theme="dark"] body.nf-landing .glass p,
[data-theme="dark"] :is(body.nf-landing, .nf-planes) .plan__features,
[data-theme="dark"] body.nf-landing .faq p { color: #F7F1FF; }
}

/* Conmutadores del header: idioma y tema. */
body.nf-landing .site-nav__ctrl {
    display: inline-flex;
    align-items: center;
    gap: .1rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: .2rem;
    background: var(--paper);
}

body.nf-landing .site-nav__ctrl a,
body.nf-landing .site-nav__ctrl button {
    min-width: 2.4rem;
    min-height: 2.1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .03em;
    cursor: pointer;
    padding: 0 .5rem;
    text-decoration: none;
    box-shadow: none;
}

body.nf-landing .site-nav__ctrl a:hover,
body.nf-landing .site-nav__ctrl button:hover { color: var(--ink); }

/* «Entrar» comparte la píldora de los controles, pero lleva icono y palabra: los otros dos son conmutadores
   de dos estados y se entienden con dos letras; este es una salida a otra página y tiene que decirlo. */
body.nf-landing .site-nav__ctrl a > .nf-ico { margin-right: .3rem; }

/* El idioma ACTIVO se marca: sin esto el control dice qué idiomas hay, pero no en
   cuál estás — que es justo lo que uno mira antes de pulsar. */
body.nf-landing .site-nav__ctrl a[aria-current="true"] {
    background: var(--primary);
    color: #fff;
}

/* Los iconos son SVG incrustados, no glifos de una fuente: heredan el color y el grosor de trazo se
   mantiene igual en todas las plataformas. La cara que se ve la decide el tema. */
body.nf-landing .site-nav__tema svg { width: 1.05rem; height: 1.05rem; display: block; }
body.nf-landing .site-nav__tema .is-luna { display: none; }
[data-theme="dark"] body.nf-landing .site-nav__tema .is-luna { display: block; }
[data-theme="dark"] body.nf-landing .site-nav__tema .is-sol { display: none; }

/* En oscuro el primario es CLARO, así que el texto blanco encima se queda en 3,07:1 —
   por debajo del 4,5 que pide AA para texto normal—. La píldora activa invierte: tinta
   oscura sobre el violeta claro. Comprobado, no supuesto. */
[data-theme="dark"] body.nf-landing .site-nav__ctrl a[aria-current="true"] { color: #150A21; }


/* Los TITULARES y las piezas de marca conservan la máquina de escribir: es donde la voz tipográfica del
   producto se reconoce. El cuerpo ya va en sans por `body`. */
body.nf-landing h1,
body.nf-landing h2,
body.nf-landing h3,
body.nf-landing h4,
body.nf-landing .hero__title,
body.nf-landing .h2,
body.nf-landing .eyebrow,
:is(body.nf-landing, .nf-planes) .plan__price,
:is(body.nf-landing, .nf-planes) .plan__label,
body.nf-landing .step__num,
body.nf-landing .nie,
body.nf-landing .site-foot__title,
body.nf-landing .brand {
    font-family: var(--font);
}

/* ── Código postal con sugerencias (acta 18/08, punto 12) ──────────────────────────────────────────────
   Un campo de texto normal con una lista debajo. No es un desplegable a propósito: un código postal no se
   elige de un catálogo de 2.872 entradas, se escribe — la lista está para que la errata se vea al teclearla
   y para que el código llegue en nuestro formato. */
/* ── Código postal: el campo y sus sugerencias, UNO AL LADO DEL OTRO ─────────────────────────────────────
   Era un desplegable flotante debajo del campo, y ahí lo tapaba el menú de direcciones guardadas del
   navegador. Quitarle el `autocomplete` evita que ese menú salga, pero la banda al lado arregla además el
   caso del gestor de contraseñas, que pinta lo suyo encima igual: lo que no está debajo del campo no se
   puede tapar con algo que sale debajo del campo.

   Y de paso se lee mejor: el campo y lo que se ofrece están a la misma altura, así que comparar lo tecleado
   con las sugerencias no obliga a bajar la vista. */
.nf-cp { display: flex; align-items: flex-start; gap: .5rem; }

/* El campo y su nota, en columna. Cede ancho a la banda, pero no baja de lo que mide un código entero. */
.nf-cp__campo { flex: 1 1 14rem; min-width: 9.5rem; }
.nf-cp__input { width: 100%; }

/* LA BANDA. Del alto del campo y del ancho que pida su contenido, hasta donde quepa; si hay más, se
   desplaza en horizontal. Resaltada —fondo y borde de marca— porque es una ayuda viva, no un bloque más de
   la ficha: tiene que distinguirse del campo sin parecer un error. */
.nf-cp__lista {
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: .25rem;
    height: var(--h-control);
    margin: 0;
    padding: .25rem .3rem;
    list-style: none;
    background: var(--primary-weak);
    border: 1px solid var(--primary);
    border-radius: var(--r-sm);
    overflow-x: auto;
    overflow-y: hidden;
    /* Una sola fila: si algo envuelve, la banda crece de alto y deja de cuadrar con el campo. */
    flex-wrap: nowrap;
    scrollbar-width: thin;
}

.nf-cp__lista li { flex: 0 0 auto; margin: 0; }

.nf-cp__lista button {
    display: flex;
    align-items: baseline;
    gap: .35rem;
    padding: .3rem .5rem;
    border: 0;
    border-radius: var(--r-xs);
    background: var(--surface);
    box-shadow: none;
    white-space: nowrap;
    font: inherit;
    color: var(--ink);
    cursor: pointer;
}

.nf-cp__lista li.is-focus button,
.nf-cp__lista button:hover { background: var(--primary); color: var(--on-primary, #fff); transform: none; }
.nf-cp__lista li.is-focus .nf-cp__zona,
.nf-cp__lista button:hover .nf-cp__zona { color: inherit; opacity: .85; }
.nf-cp__lista button:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }

/* En fila ya no hay columnas que alinear: cada sugerencia es una pastilla y el ancho lo pone su texto. */
.nf-cp__cod { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-weight: 700; }
.nf-cp__zona { flex: 0 0 auto; color: var(--muted); font-size: .88rem; }

/* En móvil el campo ENCOGE para que quepan los dos, que es lo que se pidió. Un código británico cabe en
   nueve caracteres, así que el campo no necesita más; el resto del ancho vale más en la banda. */
@media (max-width: 560px) {
    .nf-cp { gap: .35rem; }
    .nf-cp__campo { flex: 0 1 8.5rem; min-width: 7.5rem; }
    .nf-cp__lista { padding: .2rem .25rem; }
    .nf-cp__lista button { padding: .3rem .4rem; font-size: .92rem; }
    /* El nombre de la zona se va: con códigos completos es el MISMO en todas las pastillas, así que en una
       banda estrecha solo roba el sitio de los códigos, que es lo que se está comparando. */
    .nf-cp__lista .nf-cp__zona { display: none; }
}

.nf-cp__nota {
    display: flex;
    align-items: center;
    gap: .3rem;
    margin: .35rem 0 0;
    font-size: .85rem;
    color: var(--success);
}

/* ── Apoderados del poder (/admin/poder) ────────────────────────────────────────────────────────────────
   Una lista ORDENADA en la que el orden es el dato: el número de posición va delante y con peso, porque es
   lo que se está decidiendo, y no un adorno de fila. Las filas de quien todavía no comparece van apagadas
   —mismo esqueleto, sin número y en gris— para que se lea de un vistazo dónde acaba el poder y dónde empieza
   la lista de candidatos. */
.nf-apod { margin-top: 1.25rem; }
.nf-apod__fila {
    display: flex; align-items: center; gap: .85rem; flex-wrap: wrap;
    margin-top: .55rem; padding: .6rem .8rem;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2);
}
.nf-apod__fila--off { background: transparent; border-style: dashed; }
.nf-apod__pos {
    flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--primary); color: #fff; font-weight: 700; font-size: .82rem;
    font-variant-numeric: tabular-nums;
}
.nf-apod__txt { display: flex; flex-direction: column; gap: .15rem; min-width: 220px; flex: 1; }
.nf-apod__nom { font-weight: 700; color: var(--ink); }
.nf-apod__dsc { font-size: .85rem; color: var(--muted); }
.nf-apod__acc { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
/* Deshabilitado y no oculto en los extremos: un botón que desaparece desplaza a los de al lado bajo el
   cursor justo entre una pulsación y la siguiente, y se acaba moviendo a quien no se quería mover. */
.nf-apod__acc button[disabled] { opacity: .35; cursor: not-allowed; }
.nf-apod__subtit { font-size: 1rem; margin: 1.4rem 0 .2rem; color: var(--ink); }
.nf-apod__vacio { margin-top: .6rem; }
.nf-apod__preview { margin-top: 1rem; }
/* La frase tal cual se imprime. Con serif y justificada porque es un texto de acta notarial, no una fila de
   panel: verla con la forma que tendrá en el papel es justo lo que hace útil la vista previa. */
.nf-apod__paper {
    margin: .3rem 0 0; padding: .8rem .95rem;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface);
    font-family: Georgia, 'Times New Roman', serif; line-height: 1.6; text-align: justify;
}
/* Ver / descargar en la misma fila de modelo: el visor es la acción normal y la descarga la excepción (hacen
   falta DOS ficheros a la vez para comparar los modelos), así que una lleva rótulo y la otra solo el icono. */
.nf-modelo__btns { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
/* Hoja de recuperación: aviso con acción a la derecha, como el resto de filas de la casa. */
.nf-hoja { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.nf-hoja > div { display: flex; flex-direction: column; gap: .15rem; min-width: 260px; flex: 1; }
/* «Comprueba tu zona» dentro de una tarjeta de nivel. Va pegado al botón y no arriba: lo que se evita es que
   alguien pulse «empezar» creyendo que compra algo que en su zona no se presta. */
.plan__zona { margin: .8rem 0 .6rem; text-align: left; }
.plan__zona label { display: block; font-size: .82rem; font-weight: 600; margin-bottom: .25rem; }
/* `margin-bottom` en el campo y no solo `margin-top` en el mensaje: el input tiene anillo de foco por
   `box-shadow`, que NO ocupa espacio en el flujo, así que el aviso se le montaba encima justo cuando el
   cliente acababa de escribir —el único momento en que hay foco y hay mensaje a la vez—. */
.plan__zona input { width: 100%; margin-bottom: .5rem; }
.plan__zona-ok { margin: 0; font-size: .84rem; color: #1B6B50; font-weight: 600; line-height: 1.4; }
.plan__zona-no { margin: 0 0 .2rem; font-size: .84rem; color: var(--warning-ink); line-height: 1.4; }

/* EL CLAUSULADO (/legal). Página de LECTURA larga, no de venta: ancho corto de columna y no el ancho de la
   landing. Un contrato a 1100 px de línea no se lee, y el problema de que nadie se lea las condiciones no
   hace falta agravarlo con la tipografía. Hereda `.nf-fmt` para el cuerpo, que es el mismo formato sencillo
   que guarda el editor del backoffice. */
.nf-landing .nf-legal { max-width: 46rem; margin: 0 auto; padding: 3rem 1.2rem 4rem; }
.nf-legal h1 { margin: 0 0 .3rem; }
.nf-legal__indice { margin: 1.2rem 0 2rem; }
.nf-legal__indice ul { margin: 0; padding-left: 1.1rem; }
.nf-legal__indice li { margin: .2rem 0; }
.nf-legal__doc { margin-top: 2.4rem; scroll-margin-top: 1rem; }
.nf-legal__doc h2 { border-top: 1px solid var(--line); padding-top: 1.2rem; }

/* «VIENDO COMO CLIENTE». Barra permanente arriba del todo. Iba en ámbar oscuro para que se leyera como una
   advertencia; el marrón que salía no es de la casa y desentonaba con todo lo demás, así que va en el
   degradado de marca. Lo que la hace inconfundible no es el color raro sino el sitio: ninguna otra pieza
   ocupa el ancho completo por encima de la aplicación, y el aviso viaja SIEMPRE con su salida — el mayor
   riesgo de esta función no es entrar, es olvidarse de salir. */
.nf-suplantando {
    display: flex; align-items: center; justify-content: center; gap: 1rem; flex-wrap: wrap;
    padding: .5rem 1rem; color: #fff; font-size: .88rem; font-weight: 600;
    background: linear-gradient(90deg, var(--primary), var(--accent));
}
.nf-suplantando span { display: inline-flex; align-items: center; gap: .4rem; }
.nf-suplantando .btn { background: #fff; color: var(--primary); border-color: #fff; }
.nf-suplantando .btn:hover { background: #fff; color: var(--accent); }

/* LIGHTBOX: diálogo centrado sobre fondo atenuado. Sobre el `popover` nativo, así que la capa superior, el
   Escape y el clic fuera los pone el navegador; aquí solo se coloca y se viste. `inset:auto` + `margin:auto`
   es lo que centra un popover en la top layer — sin ello se pega a la esquina superior izquierda. */
[popover].nf-lightbox {
    inset: 0; margin: auto; border: 1px solid var(--border-strong); border-radius: var(--r-md);
    background: var(--surface); color: var(--ink); box-shadow: var(--shadow-lg);
    padding: 1.4rem; width: min(92vw, 620px); max-height: 88vh; overflow: auto;
}
.nf-lightbox::backdrop { background: rgb(0 0 0 / .45); }
.nf-lightbox__x {
    position: absolute; top: .4rem; right: .6rem; border: 0; background: none; cursor: pointer;
    font-size: 1.6rem; line-height: 1; color: var(--muted); padding: .2rem .4rem;
}
.nf-lightbox__x:hover { color: var(--ink); }
.nf-lightbox__cuerpo { padding-right: 1.2rem; }
/* Las dos tiendas, en fila y cada QR con su plataforma debajo. En estrecho se apilan solos. */
.nf-mfa-apps { display: flex; gap: 1.2rem; flex-wrap: wrap; margin-top: .8rem; }
.nf-mfa-apps figure { margin: 0; text-align: center; }
.nf-mfa-apps figcaption { font-size: .82rem; font-weight: 600; margin-top: .3rem; }
.nf-mfa-apps svg { display: block; border-radius: 6px; }

/* Ayuda del MFA: una app por bloque, y dentro sus dos tiendas (QR + botón). El bloque existe para que el
   nombre de la app quede claramente POR ENCIMA de sus dos tiendas: sin él, cuatro figuras seguidas se leen
   como cuatro apps distintas. */
.nf-mfa-app { margin-top: 1rem; }
.nf-mfa-app__nombre { font-weight: 700; margin: 0 0 .4rem; }
.nf-mfa-apps figure .btn { margin-top: .45rem; }
.nf-mfa-pasos { margin: .3rem 0 0; padding-left: 1.1rem; font-size: .9rem; line-height: 1.55; }
.nf-mfa-pasos li + li { margin-top: .45rem; }
/* La clave TOTP se copia a mano: monoespaciada y con `user-select: all` para que un clic la seleccione
   entera. Partirla en dos por un salto de línea es cómo se teclea mal. */
.nf-mfa-clave { user-select: all; word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* Zona de peligro: el borrado definitivo del expediente, al final de su ficha y solo para el administrador.
   Separada en su propio bloque y con el color del riesgo, para que nadie la pulse mientras busca otra cosa. */
/* Zona de peligro: el borrado definitivo del expediente. Es una `nf-card--danger` como cualquier otra
   tarjeta del backoffice —icono + título + contenido—, así que aquí solo va lo que esa convención no da: el
   resumen de lo que desaparece y el pie con la acción. */
.nf-zona-peligro {
    margin-top: 2rem;
    /* Fondo rojo PÁLIDO además del filo y del título en rojo: la tarjeta es la misma pieza que las demás
       —icono, título, contenido— y lo único que cambia es el tono, que aquí tiene que verse desde lejos.
       Se pide para que no se llegue a ella buscando otra cosa. */
    background: var(--danger-weak);
}
.nf-zona-peligro .nf-hint { margin: 0; max-width: 62ch; }

/* Qué desaparece, contado: referencia, titular y número de documentos. Es la última ocasión de ver que se
   está en la ficha equivocada. */
.nf-zona-peligro__lista {
    display: flex; flex-wrap: wrap; gap: .3rem .9rem;
    margin: .8rem 0 0; padding: 0; list-style: none;
    font-size: .82rem; color: var(--muted);
}
.nf-zona-peligro__lista li { display: inline-flex; align-items: center; gap: .3rem; }
.nf-zona-peligro__lista svg { opacity: .75; }

.nf-zona-peligro__pie {
    display: flex; justify-content: flex-end; align-items: center; gap: .6rem; flex-wrap: wrap;
    margin-top: 1rem; padding-top: .9rem;
    border-top: 1px solid color-mix(in srgb, var(--danger) 20%, transparent);
}
/* El aviso de bloqueo es PROSA, no una acción: se queda a la izquierda. Con el `flex-end` del pie salía
   alineado a la derecha, leyéndose como un botón largo. */
.nf-zona-peligro__bloqueo { margin: 0 auto 0 0; max-width: 62ch; text-align: left; font-size: .82rem; color: var(--danger-ink); }
}

/* «Antes de subirlo», plegado. Eran dos párrafos largos en ámbar, abiertos, ANTES de haber subido nada:
   ocupaban más que la fila entera y empujaban el botón de subir fuera de la vista («visualmente es muy
   ruidoso», 08/09). El aviso se conserva —un pasaporte sin firmar no se apostilla— pero deja de gritar a
   quien todavía no ha hecho nada. */
/* El plegado de los avisos del pasaporte se retiró el 15/09: los cuatro requisitos pasaron a una tarjeta
   propia y a la vista (`.nf-escaneo`). Su CSS se va con él — dejarlo invita a resucitarlo creyendo que se usa. */

/* ── El disco, con barra ────────────────────────────────────────────────────────────────────────────────
   El 15/09 el disco del servidor se llenó y la primera señal fue el sitio caído: llevaba tres semanas
   creciendo y no había dónde mirarlo sin entrar por SSH. Con barra y no solo con un número porque «62%» hay
   que pensarlo y una barra medio llena se entiende sin leer.
   El color lo pone el ESTADO, no un adorno: verde holgado, ámbar a partir del 85% y rojo del 92%, los mismos
   umbrales con los que avisa `nf:vigilar-disco` — dos escalas distintas para lo mismo serían dos verdades. */
.nf-disco__cab { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

.nf-disco__pct {
    font-size: 1.6rem; font-weight: 700; line-height: 1;
    font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}

.nf-disco__barra {
    height: 12px; margin-top: .8rem; border-radius: 99px; overflow: hidden;
    background: var(--border); 
}

.nf-disco__barra > span {
    display: block; height: 100%; border-radius: 99px;
    transition: width .3s ease;
}

.nf-disco__cifras { margin: .55rem 0 0; }
.nf-disco__aviso { margin: .6rem 0 0; font-weight: 600; font-size: .92rem; }

.nf-disco--holgado .nf-disco__pct { color: var(--success-ink); }
.nf-disco--holgado .nf-disco__barra > span { background: var(--success-ink); }

.nf-disco--aviso .nf-disco__pct,
.nf-disco--aviso .nf-disco__aviso { color: var(--warning-ink); }
.nf-disco--aviso .nf-disco__barra > span { background: var(--warning-ink); }

.nf-disco--critico .nf-disco__pct,
.nf-disco--critico .nf-disco__aviso { color: var(--danger-ink); }
.nf-disco--critico .nf-disco__barra > span { background: var(--danger-ink); }

/* ── Cómo tiene que estar el pasaporte ──────────────────────────────────────────────────────────────────
   Cuatro requisitos, cada uno con su titular y su porqué. Antes eran dos párrafos en ámbar plegados detrás
   de un «más»: como párrafos hacían demasiado ruido abiertos y no los leía nadie cerrados. Como lista
   ocupan menos abiertos que los párrafos plegados. */
.nf-escaneo__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }
.nf-escaneo__lista > li { display: flex; gap: .55rem; align-items: flex-start; }
.nf-escaneo__ico { flex: 0 0 auto; margin-top: .1rem; color: var(--success-ink); }
/* El titular y el detalle, uno debajo del otro: en la misma línea el detalle empuja y se descuadra la
   rejilla en cuanto uno de los cuatro es más largo que los demás. */
.nf-escaneo__lista strong { display: block; line-height: 1.35; }
.nf-escaneo__lista .meta { display: block; margin-top: .1rem; }

/* ── Secciones de una pantalla de configuración ─────────────────────────────────────────────────────────
   Pestañas, no acordeones: los ajustes se BUSCAN, y en un acordeón cerrado no se ve qué hay dentro sin
   abrirlo uno por uno — que es exactamente el problema que esto viene a arreglar.

   Dos intentos hasta dar con esto. El primero eran rótulos sueltos con una rayita debajo: no se distinguían
   de un párrafo. El segundo, pastillas con borde: las CUATRO parecían activas y la seleccionada solo cambiaba
   el color del texto — en una paleta lila sobre fondo lila, eso no se ve.

   Lo que funciona es no fiarlo al color: la activa va RELLENA con el degradado de la marca y texto blanco,
   y las demás son texto plano sin fondo ni borde. La diferencia es de forma y de peso, no de tono, así que
   se lee de un vistazo y también en escala de grises. */
.nf-secciones {
    display: flex; flex-wrap: wrap; gap: .2rem;
    margin: 1.1rem 0 .2rem; padding: .3rem;
    background: var(--surface-2, var(--bg-alt)); border: 1px solid var(--border);
    border-radius: var(--r-pill, 999px);
}
/* `border:0` y `background:none` explícitos: esto es un <button> y hereda el aspecto de botón de la casa,
   que aquí sobra — el carril ya es el recuadro. */
.nf-seccion {
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    flex: 1 1 auto;
    background: none; border: 0; border-radius: var(--r-pill, 999px);
    padding: .55rem 1rem; box-shadow: none;
    font: inherit; font-size: .93rem; font-weight: 600; color: var(--text-muted);
    cursor: pointer; white-space: nowrap;
    transition: background .12s ease, color .12s ease;
}
.nf-seccion:hover { background: var(--surface); color: var(--text); box-shadow: none; }
/* La activa: RELLENA en morado con texto blanco. No hay forma de confundirla con las otras tres, que no
   tienen fondo ninguno.

   `--primary` y no `--grad-brand`: el degradado de la marca está acotado a `body.nf-landing` / `.nf-planes`
   —lo dice su propio bloque, «el resto de la app no los ve»— así que aquí resolvía a nada y la pestaña
   quedaba con texto blanco sobre fondo claro, o sea invisible. Comprobado en captura, no deducido. */
.nf-seccion.is-activa,
.nf-seccion.is-activa:hover {
    background: var(--primary); color: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}
.nf-seccion.is-activa svg { color: #fff; }
.nf-seccion:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* En móvil el carril se parte en dos filas antes que dejar las pastillas ilegibles de estrechas. */
@media (max-width: 560px) {
    .nf-secciones { border-radius: var(--r-sm, 10px); }
    .nf-seccion { flex: 1 1 45%; border-radius: var(--r-sm, 10px); padding: .55rem .4rem; font-size: .88rem; }
}
.nf-seccion__pie { margin: .7rem 0 1.1rem; }

/* ── El clausulado, leíble sin salir del alta ───────────────────────────────────────────────────────────
   (Aquí estaba `.nf-clausulado__marco`, el marco con scroll del 15/09. Se retiró al plegar el clausulado el
   19/09 —dos desplazamientos, y en un móvil se comía 470 px de 844— y su CSS se quedó huérfano hasta el
   rediseño. `git log -S nf-clausulado__marco`.)

   EL TIRADOR, QUE NO ES UNA LLAMADA A LA ACCIÓN. Era `btn btn-ghost` —que de fantasma no tiene nada: pinta
   un botón sólido del color secundario— a ancho completo, así que en un móvil se leía tan alto y casi tan
   llamativo como el de pagar. En una pantalla con un solo botón de verdad, el primero que se ve no puede ser
   el de leer la letra pequeña. Vuelve a ser lo que siempre fue, un enlace, y comparte línea con el PDF. */
.nf-clausulado { margin: 0 0 1.3rem; }
.nf-clausulado__acciones { display: flex; align-items: center; gap: .3rem 1.2rem; flex-wrap: wrap; margin: 0; }
.nf-clausulado__abrir,
.nf-clausulado__pdf {
    display: inline-flex; align-items: center; gap: .35rem;
    background: none; border: 0; box-shadow: none; padding: 0; min-height: 0;
    font-size: .88rem; font-weight: 600; color: var(--primary); cursor: pointer;
}
.nf-clausulado__abrir:hover, .nf-clausulado__pdf:hover { color: var(--primary-dark); text-decoration: underline; }
.nf-clausulado__abrir:focus-visible, .nf-clausulado__pdf:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 3px; }
.nf-clausulado__doc { font-size: 1rem; margin: 1.2rem 0 .4rem; }
.nf-clausulado__doc:first-child { margin-top: 0; }
.nf-clausulado__pie { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; margin: .7rem 0 0; }
.nf-clausulado__pie a { display: inline-flex; align-items: center; gap: .3rem; }

/* ── La casilla de aceptar, con la marca ────────────────────────────────────────────────────────────────
   Es el gesto que convierte una página en un contrato: tiene que verse que ES ese gesto y no una
   preferencia más. El logotipo dice con quién se contrata, que es lo que hay que poder enseñar. */
.nf-acepto--marca {
    display: flex; align-items: flex-start; gap: .7rem;
    border: 2px solid var(--primary); border-radius: var(--r-sm, 8px);
    padding: .9rem 1rem; margin: 1.1rem 0 .4rem;
    background: var(--primary-weak, transparent);
}
.nf-acepto__marca { flex: 0 0 auto; width: 34px; height: 34px; object-fit: contain; }
.nf-acepto--marca > span { font-weight: 600; }
.nf-acepto--marca .meta { display: block; margin-top: .15rem; font-weight: 400; }
@media (max-width: 480px) { .nf-acepto__marca { width: 26px; height: 26px; } }

/* ── El código de 6 cifras ──────────────────────────────────────────────────────────────────────────────
   Grande y espaciado: se teclea mirando otro dispositivo, y a cuerpo normal se baila un dígito sin notarlo.
   Es el mismo motivo por el que la hoja de recuperación imprime la clave en bloques. */
.nf-codigo { max-width: 27rem; margin-inline: auto; }
.nf-codigo__input {
    font-size: 1.7rem; letter-spacing: .5em; text-align: center;
    font-variant-numeric: tabular-nums; padding-block: .5rem;
    /* El `letter-spacing` mete un hueco también DESPUÉS del último dígito y descentra el conjunto. */
    text-indent: .5em;
}
.nf-codigo__pie { margin-top: 1.1rem; padding-top: .8rem; border-top: 1px solid var(--border); }

/* ═══ LAS MIGAS, COMO EL SELECTOR DE SECCIONES ═══════════════════════════════════════════════════════════
   Mismo carril de pastillas que `/admin/catalogo` (`.nf-secciones`), en los dos recorridos que ve el
   cliente: los tres pasos de la COMPRA (`.nf-steps`) y los del EXPEDIENTE (`.nf-stepper` — Información,
   Pasaporte, Notario, NIE).

   Por qué unificarlos: eran tres formas distintas de decir «estás aquí» en la misma aplicación —números en
   círculo con una rayita, puntos unidos por una línea, y pestañas—, y cada una había que aprenderla por
   separado. Una sola forma se aprende una vez.

   Lo que NO se pierde es el color ni el brillo, que es lo que estas migas tenían de bueno: el paso actual
   sigue llevando el degradado de la marca, el halo `--primary-weak` y el pulso de «estás aquí». Lo que
   cambia es el soporte —una pastilla en vez de un círculo suelto—, así que el recorrido se lee como un
   bloque y no como cuatro adornos flotando.

   Va TODO por CSS, sin tocar las plantillas: los conectores (`.sep` y los `::before`) se ocultan en vez de
   borrarse del marcado. El carril ya es el que agrupa, así que unir las pastillas con rayas sobra. */

/* ── El carril, común a los dos ───────────────────────────────────────────────────────────────────────
   `:not(ol)` porque la pantalla de la extensión de la tasa 790 reutiliza `.nf-steps` para una LISTA DE
   INSTRUCCIONES numerada, que no es un recorrido: meterla en un carril de pastillas la convertiría en una
   barra de navegación que no navega a ninguna parte. Reutilizar ahí el nombre ya era discutible; lo que no
   se puede es arrastrarla a un cambio que no le toca. */
.nf-steps:not(ol),
.nf-stepper {
    gap: .2rem;
    padding: .3rem;
    background: var(--surface-2, var(--bg-alt));
    border: 1px solid var(--border);
    border-radius: var(--r-pill, 999px);
    align-items: stretch;
}
/* Los conectores sobran dentro de un carril: lo que agrupa es la caja. */
.nf-steps:not(ol) .sep,
.nf-stepper .nf-step::before { display: none; }

/* ── La pastilla ───────────────────────────────────────────────────────────────────────────────────────
   `flex: 1 1 0` con `min-width: 0`: los cuatro pasos reparten el ancho a partes iguales aunque sus rótulos
   midan distinto, que es lo que hace que el carril se lea como una sola pieza. */
.nf-steps:not(ol) .nf-step,
.nf-stepper .nf-step {
    flex: 1 1 0; min-width: 0;
    justify-content: center; text-align: center;
    padding: .5rem .7rem;
    border-radius: var(--r-pill, 999px);
    background: none;
    transition: background .14s ease, color .14s ease;
}
.nf-stepper .nf-step { flex-direction: row; align-items: center; gap: .45rem; }
.nf-stepper .nf-step__label { font-size: .85rem; }

/* ── Hecho: fondo tenue y el ✓ en el degradado. Se ve que está cerrado sin gritar. ─────────────────── */
.nf-steps .nf-step.done,
.nf-stepper .nf-step.nf-step--hecho { background: var(--primary-weak); color: var(--accent-ink); }

/* ── Actual: relleno con el degradado de la marca, halo y pulso. El brillo de siempre, en la pastilla. ──
   `.nf-step.nf-step--actual` y no `.nf-step--actual` a secas: el paso actual es un <button> cuando se puede
   abrir, y hay una regla `.nf-stepper button.nf-step { background: none }` —que le quita el aspecto de botón
   de la casa— con MÁS peso que un selector de dos clases. Se llevaba por delante el relleno y la pastilla
   salía con texto blanco sobre fondo claro, o sea invisible. Visto en captura, no deducido. */
.nf-steps .nf-step.on,
.nf-stepper .nf-step.nf-step--actual {
    background: var(--grad); color: #fff;
    box-shadow: 0 0 0 3px var(--primary-weak);
    animation: pbStepPulse 2s ease-in-out infinite;
}
/* El número y el punto YA no necesitan su propio relleno: iría degradado sobre degradado y se emborrona. */
.nf-steps .nf-step.on .n,
.nf-stepper .nf-step.nf-step--actual .nf-step__dot {
    background: rgba(255, 255, 255, .22); border-color: rgba(255, 255, 255, .55);
    color: #fff; box-shadow: none; animation: none;
}
.nf-steps .nf-step.done .n,
.nf-stepper .nf-step.nf-step--hecho .nf-step__dot { box-shadow: none; }
.nf-stepper .nf-step.nf-step--actual .nf-step__dot::after { background: #fff; }
.nf-steps .nf-step.on .nf-step__quien,
.nf-stepper .nf-step.nf-step--actual .nf-step__quien { opacity: .85; }

/* ── Pulsable: la pastilla entera responde, no solo el rótulo. ───────────────────────────────────────
   Y EL RELLENO NO SE PIERDE al pasar por encima. Se perdía: existe `.nf-stepper button.nf-step:hover
   { background: none }` —la que le quita el aspecto de botón de la casa— y con el `:hover` suma (0,3,1),
   que gana a un selector de tres clases. Al señalar el paso actual, el degradado desaparecía y quedaba su
   texto BLANCO sobre fondo claro: ilegible justo mientras se está apuntando.
   Por eso cada estado lleva su `:hover` explícito, con una clase más de peso. */
.nf-steps .nf-step--volver,
.nf-stepper .nf-step--abrible { margin: 0; }

/* El ACTUAL conserva degradado y blanco pase lo que pase; al señalarlo solo se le abre un poco el halo. */
.nf-steps .nf-step.on:hover,
.nf-stepper .nf-step.nf-step--actual:hover,
.nf-stepper .nf-step.nf-step--actual:focus-visible {
    background: var(--grad); color: #fff;
    box-shadow: 0 0 0 5px var(--primary-weak);
}
/* Un paso HECHO al señalarlo: fondo de tarjeta y texto de marca. Contraste alto, no un gris que se apaga. */
.nf-steps .nf-step.done:hover,
.nf-stepper .nf-step.nf-step--hecho:hover,
.nf-stepper .nf-step.nf-step--hecho:focus-visible { background: var(--surface); color: var(--primary); box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, .12)); }
/* Sin subrayado: un paso hecho es un ENLACE, y el subrayado lo sacaba del carril — parecía texto suelto en
   medio del recorrido. Es la misma decisión que ya estaba tomada para el stepper antiguo. */
.nf-steps a.nf-step,
.nf-stepper a.nf-step,
.nf-steps a.nf-step:hover,
.nf-stepper a.nf-step:hover { text-decoration: none; }
/* Y el punto del hecho no pierde su relleno: es la marca de «esto ya está». */
.nf-stepper .nf-step.nf-step--hecho:hover .nf-step__dot { background: var(--grad); border-color: transparent; color: #fff; }
/* Uno PENDIENTE que se puede abrir. `--muted` se apagaba aún más al quedarse sin fondo. */
.nf-steps .nf-step--volver:hover,
.nf-stepper .nf-step.nf-step--abrible:hover:not(.nf-step--actual):not(.nf-step--hecho),
.nf-stepper .nf-step.nf-step--abrible:focus-visible:not(.nf-step--actual):not(.nf-step--hecho) {
    background: var(--surface); color: var(--primary); box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, .12));
}
.nf-stepper .nf-step.nf-step--viendo:not(.nf-step--actual) { box-shadow: inset 0 0 0 2px var(--primary); }

@media (prefers-reduced-motion: reduce) {
    .nf-steps .nf-step.on,
    .nf-stepper .nf-step.nf-step--actual { animation: none; }
}

/* En móvil el carril se parte antes que dejar los rótulos ilegibles, igual que el de configuración. */
@media (max-width: 560px) {
    .nf-steps:not(ol), .nf-stepper { border-radius: var(--r-sm, 10px); flex-wrap: wrap; overflow-x: visible; }
    .nf-steps:not(ol) .nf-step, .nf-stepper .nf-step { flex: 1 1 45%; border-radius: var(--r-sm, 10px); padding: .5rem .35rem; }
    .nf-stepper .nf-step__label { font-size: .78rem; }

    /* LA DEL ALTA, EN UNA SOLA LÍNEA.

       Con la base del 45% solo caben dos por fila, así que el tercer paso —«Pago»— bajaba solo y la miga
       ocupaba el doble de alto justo en la pantalla que menos sitio tiene. Con tres pasos de rótulo corto
       (Servicio · Términos · Pago) caben de sobra; la regla de arriba se queda para la guía del EXPEDIENTE,
       que tiene más pasos y rótulos largos, y ahí partir sí es lo correcto.

       `flex: 1 1 0` reparte el ancho por igual en vez de reservar un mínimo por tarjeta, que es lo que
       forzaba el salto. El `min-width: 0` es lo que permite a la caja encoger por debajo de su contenido:
       sin él, flex respeta el ancho mínimo del texto y vuelve a partir. */
    /* El `:not(ol)` no es decorativo: la regla de arriba lo lleva, y sin él esta pesa MENOS y no se aplica
       —se quedaba en dos por fila—. Con la misma especificidad manda la que viene después, que es esta. */
    .nf-steps--centrado:not(ol) { flex-wrap: nowrap; gap: .2rem; }
    .nf-steps--centrado:not(ol) .nf-step {
        flex: 1 1 0;
        min-width: 0;
        padding: .45rem .2rem;
        gap: .3rem;
        font-size: .8rem;
    }
    .nf-steps--centrado:not(ol) .nf-step .n { width: 1.55rem; height: 1.55rem; font-size: .78rem; flex: none; }
    /* Los separadores sobran cuando el sitio es justo: lo que tiene que caber son los rótulos. */
    .nf-steps--centrado:not(ol) .sep { display: none; }
}

/* ── VIENDO COMO CLIENTE: los controles de escritura, apagados ──────────────────────────────────────────
   La sesión suplantada es de SOLO LECTURA y el guardián de Eloquent la corta. Pero lo cortaba al final: se
   podía rellenar el cuestionario entero —treinta campos— y descubrir la pared al pulsar «Guardar».

   Esto no sustituye al guardián, que sigue siendo la barrera de verdad; solo evita el viaje en balde. Por eso
   los controles quedan visibles y explicados en vez de escondidos: quien mira la pantalla del cliente tiene
   que ver LO QUE EL CLIENTE VE, incluidos sus botones — esconderlos daría una idea falsa de su pantalla, que
   es justo lo que esta función viene a resolver. */
.nf-ro [type="submit"],
.nf-ro [type="file"],
.nf-ro button[wire\:click],
.nf-ro label.btn {
    opacity: .5; cursor: not-allowed; filter: grayscale(.4);
}
/* El banner de arriba NO: su botón es el único que tiene que funcionar, porque es el de salir. */
.nf-ro .nf-suplantando [type="submit"] { opacity: 1; cursor: pointer; filter: none; }

/* «y N más» dentro de la lista de códigos postales: es un aviso, no una opción. Se distingue de las de
   arriba —sin fondo al pasar, en cursiva y apagado— para que nadie intente pulsarlo. */
/* «y N más» dentro de la banda: es un AVISO, no una pastilla pulsable. Sin fondo y en cursiva para que no
   se confunda con las sugerencias, y `flex-shrink: 0` para que no lo aplaste el desplazamiento. */
.nf-cp__mas {
    flex: 0 0 auto; padding: .3rem .5rem; font-size: .8rem; font-style: italic;
    color: var(--muted); cursor: default; white-space: nowrap;
}

/* El botón «Siguiente: …» al pie de la guía. A la derecha, que es donde se busca lo que avanza —igual que
   en el alta— y separado del contenido del paso para que no se lea como una acción suya. */
.nf-paso-siguiente { display: flex; justify-content: flex-end; margin: 1.1rem 0 0; }

/* ═══ SELECCIÓN DE NIVEL: la elegida CRECE POR ENCIMA, la otra no se mueve ═══════════════════════════════
   Solo en el ALTA (`.nf-planes`). En la portada las tarjetas son una comparativa y ahí ninguna está elegida:
   deben pesar lo mismo.

   El primer intento las hacía repartirse el ancho —la elegida el doble, la otra la mitad— y el efecto era
   correcto pero el precio no: al cambiar de nivel se recolocaba la fila entera, la tarjeta pequeña estrujaba
   su nombre en una palabra por línea, y todo lo que había debajo daba un salto. Deformaba la caja para decir
   algo que se puede decir sin tocarla.

   Ahora crece con `scale` y se superpone: la otra CONSERVA SU TAMAÑO y su sitio, no hay reflujo ninguno y lo
   de abajo no se mueve. El z-index es lo único que hace falta para que el solape se vea. */
/* SIN NADA ELEGIDO todas son iguales: misma escala, mismo z-index, mismo espaciado. Se llega así —`$tier`
   arranca vacío— y es el estado en el que la pantalla es una COMPARATIVA: adelantar una sin que nadie la haya
   elegido sería recomendar por el diseño lo que el negocio decide con el distintivo de «recomendado». */
.nf-alta .nf-planes .plan {
    transition: transform .3s cubic-bezier(.22, 1, .36, 1), box-shadow .3s ease, opacity .3s ease;
    /* CRECE HACIA ABAJO, no desde el centro.
       Con el origen en el centro, la tarjeta se estira por arriba y por abajo a partes iguales, y cuánto
       sube depende de lo ALTA que sea: la del nivel bajo lleva dentro el código postal y el botón, así que
       es bastante más alta y se comía el margen superior hasta tocar el selector de país. Reservar aire
       para el peor caso es adivinar una altura que cambia con las prestaciones de cada nivel.
       Anclando el borde de arriba, la tarjeta no puede subir NUNCA, mida lo que mida. */
    transform-origin: center top;
}
/* NI CRECE NI SE SUPERPONE (19/09, V-04).

   Aquí vivían el crecimiento del 22 % de la tarjeta elegida y su desplazamiento del 30 % hacia el centro,
   pensados para que se superpusiera a la otra. Medido en pantalla: la de al lado quedaba TAPADA A MEDIAS
   —«NIEFY Essential» cortado por la mitad y su precio leyéndose «9 €» en vez de «199 €»—, en la pantalla
   cuyo único trabajo es comparar dos niveles.

   Y arrastraban un andamiaje entero para sostenerse: el relleno del contenedor que abría hueco para lo que
   sobresalía, un `ResizeObserver` y un enganche de Livewire midiendo `(escala − 1) × altura` porque no podía
   ser un número fijo, el `z-index` de lo que había encima, el rebote al elegir y tres reglas de móvil que no
   hacían más que desactivarlo todo otra vez. Nada de eso existía por sí mismo: existía por el crecimiento.

   Lo que señala la elección se queda donde estaba y basta: el filo interior de `:has(:checked)`.

   EL ZOOM OUT, con `zoom` y no con `transform: scale()`. La diferencia es justo la que causó el problema
   anterior: `transform` NO ocupa sitio en el flujo —la tarjeta se ve distinta pero su celda mide igual, y por
   eso se salía y había que abrir hueco a mano—, mientras que `zoom` sí reserva el tamaño que pinta. Encoge
   el par para que quepa entero sin que nada se corte ni haya nada que compensar. */
.nf-alta .nf-planes .plans { zoom: .92; }

/* La fila respira lo justo: sin nada que sobresalga, el relleno ya no tiene que reservar hueco para nadie. */
.nf-alta .nf-planes .plans { padding: 1rem 1.2rem; overflow: visible; }



/* EL TIRADOR de «qué incluye», solo en móvil (15/09).

   En escritorio no existe: las prestaciones están siempre a la vista y la pantalla es la comparativa. */
.plan__desplegar { display: none; }

.plan__chevron { display: inline-flex; transition: transform .2s ease; }
.plan__chevron.is-open { transform: rotate(90deg); }

/* ── LAS TARJETAS EN MÓVIL ──────────────────────────────────────────────────────────────────────────────
   En un teléfono ocupaban tanto que solo se veía la primera: había que desplazarse para descubrir que
   existía la otra, y ahí la pantalla deja de ser una comparativa justo donde se decide la compra.

   Aquí había además tres reglas que no hacían otra cosa que DESACTIVAR el crecimiento y el desplazamiento de
   la elegida —en vertical no superponen nada y solo hacían la tarjeta más alta todavía más alta—. Se fueron
   con él el 19/09: ya no hay nada que apagar. Lo que queda es el plegado de las prestaciones. */
@media (max-width: 760px) {
    .plan__desplegar {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: .4rem;
        width: 100%;
        margin-top: .9rem;
        padding: .55rem;
        background: none;
        border: 1px solid var(--line);
        border-radius: var(--r-sm, 10px);
        color: inherit;
        font: inherit;
        font-size: .88rem;
        font-weight: 600;
        min-height: 0;
        box-shadow: none;
        cursor: pointer;
    }
    /* Sobre la tarjeta oscura de la elegida, el borde de la casa no se ve. */
    .plan--priority .plan__desplegar { border-color: rgba(255, 255, 255, .3); color: #fff; }
}

/* La ETIQUETA de elegir ocupa la tarjeta entera: la tarjeta dejó de ser un `<label>` al meter el código
   postal dentro, y sin esto solo sería pulsable el texto. */
.plan__elegir { display: flex; flex-direction: column; flex: 1 1 auto; cursor: pointer; }

/* EL CÓDIGO POSTAL dentro de la tarjeta. Separado por una línea: es una pregunta, no una prestación más de
   la lista de arriba. */
.plan__postcode { margin-top: 1.6rem; padding-top: 1.4rem; border-top: 1px solid var(--line); }
.plan--priority .plan__postcode { border-top-color: rgba(255, 255, 255, .28); }
.plan--priority .plan__postcode label { color: #fff; }
.plan--priority .plan__postcode .meta { color: #fff; opacity: .88; }

/* EL VEREDICTO, sobre el degradado de la tarjeta elegida.

   Fuera de ella es verde o rojo sobre fondo claro y se lee perfectamente. Encima del morado-magenta, no: el
   verde de «corresponde a Londres» quedaba prácticamente invisible sobre el magenta, y el rojo directamente
   se confundía con el fondo.

   Se resuelve con una pastilla: texto blanco sobre un velo oscuro semitransparente. El velo es lo que hace
   que funcione en CUALQUIER punto del degradado —que va de morado a magenta, así que un color fijo acierta
   en un extremo y falla en el otro—. Y el icono conserva un tinte propio, que es lo que sigue distinguiendo
   el sí del no sin leer. */
.plan--priority .plan__postcode .nf-postcode {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    margin-top: .7rem;
    padding: .3rem .6rem;
    border-radius: var(--r-pill, 999px);
    background: rgba(0, 0, 0, .28);
    color: #fff;
    font-weight: 600;
}
.plan--priority .plan__postcode .nf-postcode--ok .nf-ico { color: #8BE8A8; }
.plan--priority .plan__postcode .nf-postcode--ko { background: rgba(0, 0, 0, .38); }
.plan--priority .plan__postcode .nf-postcode--ko .nf-ico { color: #FFC9C9; }
.plan--priority .plan__postcode .nf-err { color: #FFD9D9; }

/* La banda de sugerencias, dentro de la tarjeta oscura: su fondo de marca desaparecería sobre el degradado. */
.plan--priority .plan__postcode .nf-cp__lista {
    background: rgba(255, 255, 255, .92);
    border-color: rgba(255, 255, 255, .55);
}
.plan--priority .plan__postcode .nf-cp__nota { color: #fff; }

/* EL HALO PALPITANTE. El mismo recurso que marca el paso actual en las migas (`pbStepPulse`), subido de
   tono: allí es un punto de 26px y basta un anillo de 4-8px; aquí es una tarjeta de 400px, y a esa escala ese
   anillo no se ve. Va de 6 a 22px y cambia también de opacidad, que es lo que hace que respire en vez de
   parpadear.

   Latido CONTINUO y no un destello al elegir: la tarjeta se queda marcada mientras siga siendo la elegida, y
   eso es lo que se pidió — que se vea cuál es sin tener que acordarse de qué se pulsó.

   El `box-shadow` lleva DOS sombras: el halo y la que da profundidad al solape. Si se declaran por separado,
   la segunda pisa a la primera — es una sola propiedad. */
@keyframes nfPlanHalo {
    0%, 100% {
        box-shadow: 0 0 0 6px color-mix(in srgb, var(--primary) 30%, transparent),
                    0 28px 56px -22px rgba(74, 23, 168, .45);
    }
    50% {
        box-shadow: 0 0 0 22px color-mix(in srgb, var(--primary) 6%, transparent),
                    0 28px 56px -22px rgba(74, 23, 168, .45);
    }
}
.nf-alta .nf-planes .plan--priority { animation: nfPlanHalo 1.9s ease-in-out infinite; }
/* (Aquí había un rebote al elegir, `nfPlanRebote`. Animaba la escala y el desplazamiento que se retiraron el
   19/09, así que sin ellos no rebotaba: terminaba donde empezaba. `git log -S nfPlanRebote`.) */

/* EL BOTÓN, dentro de la tarjeta elegida. Al ancho completo de ella, que es lo que antes había que copiar
   con JavaScript midiendo un hermano lejano: dentro, «al 100 %» ya significa «el ancho de esta tarjeta». */
.plan__accion { margin-top: 1.6rem; }
.plan__accion button { width: 100%; }
.plan__falta { margin: .5rem 0 0; }
/* Sobre el degradado de la tarjeta elegida, el botón de la casa —que ES ese mismo degradado— desaparecería.
   Se invierte: fondo claro y texto de marca, que además lo convierte en lo más contrastado de la tarjeta,
   que es lo que le toca siendo la única acción. */
.plan--priority .plan__accion button {
    background: #fff; color: var(--primary); box-shadow: 0 8px 20px -10px rgba(0, 0, 0, .5);
}
.plan--priority .plan__accion button:hover:not(:disabled) { background: #fff; filter: brightness(.96); }
.plan--priority .plan__accion button:disabled { background: rgba(255, 255, 255, .55); color: var(--primary-deep, #2B0B63); }
.plan--priority .plan__falta { color: #fff; opacity: .9; }

@media (prefers-reduced-motion: reduce) {
    .nf-alta .nf-planes .plan { transition: none; }
    .nf-alta .nf-planes .plan--priority { animation: none; }
    }

/* En estrecho las tarjetas se apilan y ya ocupan el ancho entero: ahí crecer solo serviría para desbordar. */
@media (max-width: 760px) {
    .nf-alta .nf-planes .plans,
    .nf-alta .nf-planes .plans:has(.plan--priority) { padding: 0; }
    .nf-alta .nf-planes .plan--priority,
    .nf-alta .nf-planes .plan--priority:hover { transform: none; animation: none; }
}

/* ═══ TÉRMINOS: UNA SOLA TARJETA, Y HAY QUE LEERLA ══════════════════════════════════════════════════════
   Eran cuatro recuadros seguidos —lo fundamental, los requisitos, el clausulado y el formulario—, cada uno
   con su borde y su sombra. Cuatro cajas en fila dejan de separar nada: dicen «aquí hay cuatro cosas» cuando
   hay una sola, el contrato que se va a aceptar.

   Y desde el 19/09 tampoco hay bloques dentro (`.nf-terminos__bloque`, retirado): la pantalla es una lista
   de cláusulas, un botón que abre el contrato entero y la firma. Medía 2.596 px en un móvil. */

/* La frase que presenta la lista. No es un titular de sección —arriba ya hay uno y la pantalla decide una
   sola cosa—, así que va en el cuerpo, en negrita y sin icono. */
.nf-terminos__lead { margin: .2rem 0 0; font-weight: 700; color: var(--ink); }

/* La firma, separada de lo que hay que leer por un poco más de aire que entre cláusula y cláusula: a partir
   de aquí ya no se lee, se decide. */
.nf-terminos__firma { margin-top: 1.6rem; }

/* La casilla cerrada: apagada pero LEGIBLE. Un gris sobre gris haría ilegible justo la frase que hay que
   leer para saber qué se acepta. */
.nf-acepto--marca.is-bloqueada { opacity: .6; cursor: not-allowed; border-color: var(--border); }
.nf-acepto--marca.is-bloqueada input { cursor: not-allowed; }
/* Y por qué está cerrada. Va debajo de la casilla y no dentro: dentro se leería como parte de lo que se
   acepta, y es una instrucción de la pantalla, no una cláusula. */
.nf-acepto__falta { display: flex; align-items: flex-start; gap: .35rem; margin: .45rem 0 0 .2rem; }
.nf-acepto__falta > .nf-ico { flex: 0 0 auto; margin-top: .1rem; }

/* Lo que el cliente AÑADIÓ, dentro del resumen del servicio. Lista aparte y con otro signo: mezclarla con
   las prestaciones del nivel haría creer que venía incluido, y es justo lo contrario — es lo que paga aparte. */
.nf-servicio__anadido-tit { margin: .8rem 0 .3rem; font-size: .84rem; font-weight: 700; color: var(--muted); }
.nf-servicio__lista--anadido li { color: var(--accent-ink); }

/* EL TÍTULO DE CADA DOCUMENTO, en una banda que cruza la tarjeta.

   Eran tres documentos seguidos y a la tercera pantalla ya no se sabía cuál se estaba leyendo — y «acepto la
   política de cancelación» exige haber sabido dónde empezaba.

   YA NO SE PEGA ARRIBA. Lo hacía contra el borde de la caja con scroll, que se retiró el 19/09 al plegar el
   clausulado; pegarlo ahora sería contra la VENTANA, y por encima ya hay cabecera propia. La banda sola
   separa igual, que es para lo que estaba. */
.nf-clausulado__doc {
    margin: 1.6rem -1.3rem .7rem; /* a sangre: la banda cruza la tarjeta de lado a lado */
    padding: .55rem 1.3rem;
    /* `--surface` y NO `--card`: ese token se declara dentro de `body.nf-landing, .nf-planes` y en la app no
       existe, así que `var(--card)` sin respaldo deja la propiedad SIN APLICAR —fondo transparente, sin
       ningún error—. Misma trampa que `--grad-brand`, y ya hay un guardián que la caza. */
    background: var(--surface);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-size: .95rem;
    color: var(--primary);
}
.nf-clausulado__doc:first-child { margin-top: 0; }
