/* Identidad ITEVOX — portal público, login y web forms.
 *
 * Este archivo lleva el portal del ERP al mismo lenguaje visual de itevox.tech:
 * base cálida, acento ámbar, Archivo para títulos e Instrument Sans para el
 * cuerpo. La referencia es `itevox-web/src/styles/globals.css`; los valores del
 * tema oscuro son los mismos hexadecimales, no aproximaciones.
 *
 * **Desde el 2026-08-05 hay DOS temas**, claro y oscuro, y los decide el sistema
 * operativo con `prefers-color-scheme`. El detalle de por qué no hay otra opción
 * está en el bloque de tokens.
 *
 * ── Cómo está construido ────────────────────────────────────────────────────
 *
 * Frappe deriva CASI TODO el color del portal de una sola rampa de grises
 * (`--gray-50` … `--gray-900`, en `frappe/public/scss/espresso/_colors.scss`):
 * `--border-color` es `--gray-200`, `--control-bg` es `--gray-100`,
 * `--text-muted` es `--gray-700`, y así. Entonces el tema oscuro se hace
 * **invirtiendo y entibiando esa rampa**, no persiguiendo componente por
 * componente: 50 pasa a ser el fondo más profundo y 900 el texto. Con eso
 * caen solos tarjetas, controles, bordes, scrollbars, dropdowns y hovers.
 *
 * El tema claro no invierte nada: esa lectura de la rampa es la de fábrica.
 *
 * Lo que NO cae solo son los valores que Bootstrap **compiló** a hexadecimal
 * cuando se construyó el bundle del sitio (`$body-color`, `$input-bg`,
 * `$primary`, `$headings-color`…): esos ya no son variables en tiempo de
 * ejecución, así que hay que reescribirlos con reglas explícitas. Ese es todo
 * el bloque de la mitad para abajo, y esa es la razón de que exista.
 *
 * El selector es `html:root` y no `:root` a secas, y eso NO es cosmético.
 * Medido contra el sitio real el 2026-07-31: la página de login mete
 * `login.bundle.css` en un bloque POSTERIOR a `head.html` —que es donde Frappe
 * recorre `web_include_css`—, y ese bundle vuelve a declarar `:root {
 * --bg-color: white; … }`. Con la misma especificidad (0,1,0) gana el último en
 * el orden, o sea Frappe, y todo este bloque quedaba pisado: el login salía
 * blanco con nuestro CSS cargado y aplicándose a nada.
 *
 * `html:root` es (0,1,1) y le gana a cualquier `:root` o `[data-theme="…"]` de
 * Frappe sin importar el orden del <head> y sin recurrir a `!important`. (Los
 * pocos `!important` del archivo están abajo, en la sección de login, y cada
 * uno dice contra qué regla concreta pelea y por qué la especificidad no basta.)
 *
 * Y tampoco se filtra por `data-theme`: el <html> del portal no trae ese
 * atributo (`<html lang="es" dir="ltr">`), es cosa del escritorio. Filtrar por
 * él aquí equivalía a no matchear nunca — y es también la razón de que el
 * conmutador claro/oscuro sea el del sistema y no uno por usuario: aquí no hay
 * dónde guardar esa preferencia.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   El portal tiene DOS temas, y el conmutador es el sistema operativo.

   No hay alternativa: el portal **no tiene `data-theme`** —es
   `<html lang="es" dir="ltr">`, ese atributo es del escritorio— ni un ajuste por
   usuario donde guardar la preferencia. `prefers-color-scheme` es lo único que
   llega hasta aquí.

   ── Cómo está montado, y por qué así ────────────────────────────────────────

   **Claro es el default y oscuro va en la media query.** Se hizo en ese orden a
   propósito: el bloque oscuro es el que ya estaba medido y verificado en el
   sitio —los 70 tokens de la familia ink/surface/outline, el par cableado del
   botón de login, la rejilla de contactos— y entra aquí **sin tocar un solo
   valor**. Lo nuevo es sólo la rama clara, que es donde puede haber errores.

   **La rampa se invierte SÓLO en oscuro.** Ésa era la clave que hacía corto el
   tema: el portal no tenía modo oscuro, así que Frappe lee la rampa como
   "50 = fondo, 900 = texto" e invertirla voltea el portal entero. En claro esa
   lectura es la correcta de fábrica, así que la rampa va natural y no hay nada
   que voltear.

   **En claro casi no hay que declarar nada más.** Los 70 tokens
   ink/surface/outline y los `--alert-text-*` existen en el bloque oscuro porque
   había que reponer a mano el tema oscuro que el portal no trae. Para claro los
   valores de Frappe ya son los correctos, así que aquí sólo se entibian los
   neutros y se pone el acento.
   ═══════════════════════════════════════════════════════════════════════════ */

html:root {
	/* Marca ITEVOX en claro. Papel cálido, no blanco puro: el blanco puro con
	   acento ámbar se lee frío y barato, y además deja el borde invisible.

	   Medido el 2026-08-05 contra los tres fondos (bg / tarjeta / blanco):
	   text 16.37–18.10, text-muted 6.82–7.54, text-help 5.18–5.73. */
	--itevox-bg: #f7f3ec;
	--itevox-bg-elev: #fffdf9;
	--itevox-bg-elev-2: #ffffff;
	--itevox-border: #e2d9cb;
	--itevox-text: #1a1512;
	--itevox-text-muted: #5c5348;
	--itevox-text-dim: #8b8175;
	--itevox-text-help: #6e6558;

	/* Los colores de marca **no sirven para texto sobre claro**, y está medido:
	   el ámbar da 1.83–2.03:1, el cherry 3.54 y el verde 1.70. Se quedan como
	   relleno, borde e indicador —que es su función— y para TEXTO se usan las
	   variantes oscurecidas de abajo. En oscuro no hace falta: ahí el ámbar da
	   9.75:1 y pinta texto sin problema. */
	--itevox-amber: #f5a623;
	--itevox-cherry: #e5484d;
	--itevox-teal: #1db6a8;
	--itevox-violet: #8b5cf6;
	--itevox-success: #3dd68c;

	/* Las de texto: 5.36–5.93 el ámbar, 5.91–6.53 el cherry, 4.86–5.38 el verde. */
	--itevox-amber-texto: #8a5a00;
	--itevox-cherry-texto: #b3252a;
	--itevox-success-texto: #0f7a4a;

	--accent: var(--itevox-amber);

	/* Lo que va ENCIMA del acento. El ámbar es claro en los dos temas, así que
	   siempre lleva texto oscuro — pero cuál es "oscuro" cambia: en oscuro es el
	   fondo de la página, en claro es el color de texto. Sin este token, el botón
	   de login heredaba `--itevox-bg` y en claro quedaba casi blanco sobre ámbar
	   (1.83:1). */
	--itevox-sobre-acento: var(--itevox-text);

	/* Rampa natural y entibiada: 50 = claro, 900 = oscuro. Es la orientación que
	   Frappe supone de fábrica para el portal. */
	--gray-50: #f7f3ec;
	--gray-100: #ece5d9;
	--gray-200: #e2d9cb;
	--gray-300: #cabca6;
	--gray-400: #a1927c;
	--gray-500: #7d7264;
	--gray-600: #6e6558;
	--gray-700: #5c5348;
	--gray-800: #3a332c;
	--gray-900: #1a1512;
}

@media (prefers-color-scheme: dark) {
	html:root {
		/* Marca ITEVOX — espejo de los tokens de itevox-web. El mapeo
		   producto→color es regla de marca y no se cambia aquí:
		   ITEVOX = ámbar · PROVISIONIX = cherry · NEOIDEX = teal · STAFFLY = violeta.
		   El ERP es superficie corporativa, así que su acento es el ámbar. */
		--itevox-bg: #0c0a08;
		--itevox-bg-elev: #15110d;
		--itevox-bg-elev-2: #1f1a14;
		--itevox-border: #2a2118;
		--itevox-text: #f4ede4;
		--itevox-text-muted: #a89b8a;
		--itevox-text-dim: #6b5f50;

		/* El texto secundario NO usa `--itevox-text-dim`, y eso está medido: sobre
		   nuestros tres fondos da 2.78–3.18:1, o sea que no pasa AA en ninguno. Se
		   vio en vivo el 2026-08-01 en el web form de alta — las ayudas bajo RFC y
		   Uso del CFDI quedaban casi ilegibles (3.02:1).

		   `--itevox-text-dim` se queda declarado porque es el token de marca que
		   viene del sitio, pero para TEXTO se usa éste: 4.79:1 sobre la tarjeta,
		   sigue siendo recesivo y sí se lee. */
		--itevox-text-help: #8b7f6d;

		--itevox-amber: #f5a623;
		--itevox-cherry: #e5484d;
		--itevox-teal: #1db6a8;
		--itevox-violet: #8b5cf6;
		--itevox-success: #3dd68c;

		--accent: var(--itevox-amber);

		/* Ver la nota del bloque claro. */
		--itevox-sobre-acento: var(--itevox-bg);
		--itevox-amber-texto: var(--itevox-amber);
		--itevox-cherry-texto: var(--itevox-cherry);
		--itevox-success-texto: var(--itevox-success);

		/* Rampa de grises invertida y entibiada. 50 = fondo, 900 = texto.
		   Los extremos son tokens de marca; los intermedios interpolan entre ellos
		   para que sombras, bordes y hovers escalen parejo. */
		--gray-50: #15110d;
		--gray-100: #1f1a14;
		--gray-200: #2a2118;
		--gray-300: #362c20;
		--gray-400: #4d4032;
		--gray-500: #6b5f50;
		--gray-600: #8b7f6d;
		--gray-700: #a89b8a;
		--gray-800: #d3c8ba;
		--gray-900: #f4ede4;

		/* ── Familia ink / surface / outline ────────────────────────────────────
		   Frappe v16 arrastra DOS sistemas de color a la vez: la rampa `--gray-*`
		   de arriba (la vieja) y ésta, más nueva y semántica. Invertir solo la
		   primera dejaba componentes enteros en claro — el botón de "Iniciar sesión
		   con Google" salía gris claro sobre el fondo oscuro porque toma
		   `--surface-gray-2` y `--ink-gray-4`.

		   Estos 70 valores NO son inventados: salen del bloque `[data-theme="dark"]`
		   de `frappe/public/scss/espresso/_colors.scss`, o sea del tema oscuro que
		   Frappe ya mantiene. De ahí se entibiaron los 28 neutros a nuestra paleta;
		   los 42 cromáticos (rojo, verde, ámbar, azul de estado) se quedan con el
		   valor de Frappe: ya están calibrados para fondo oscuro y no son marca
		   nuestra.

		   Al actualizar Frappe conviene volver a mirar ese bloque: si agregan
		   tokens, aquí faltarán y ese componente saldrá claro. Es el costo de no
		   depender de que el portal traiga `data-theme="dark"`, que no lo trae. */
		--outline-white: #15110d;
		--outline-gray-1: #1f1a14;
		--outline-gray-2: #2a2118;
		--outline-gray-3: #362c20;
		--outline-gray-4: #8b7f6d;
		--outline-red-1: #521515;
		--outline-red-2: #681916;
		--outline-red-3: #901818;
		--outline-green-1: #0a3f27;
		--outline-green-2: #035831;
		--outline-amber-1: #4b2606;
		--outline-amber-2: #603007;
		--outline-blue-1: #052b53;
		--outline-orange-1: #683108;
		--outline-gray-modals: #2a2118;
		--surface-white: #0c0a08;
		--surface-gray-1: #1f1a14;
		--surface-gray-2: #241e17;
		--surface-gray-3: #2a2118;
		--surface-gray-4: #362c20;
		--surface-gray-5: #b8ab99;
		--surface-gray-6: #d3c8ba;
		--surface-gray-7: #f4ede4;
		--surface-red-1: #361515;
		--surface-red-2: #361515e6;
		--surface-red-3: #521515e6;
		--surface-red-4: #681916;
		--surface-red-5: #e43838;
		--surface-red-6: #c12020;
		--surface-red-7: #901818;
		--surface-green-1: #0b2e1c;
		--surface-green-2: #0a3f27;
		--surface-green-3: #1ba964;
		--surface-amber-1: #371e06;
		--surface-amber-2: #4b2606;
		--surface-amber-3: #e37d00;
		--surface-blue-1: #0e2037;
		--surface-blue-2: #052b53;
		--surface-blue-3: #3294e3;
		--surface-orange-1: #401f07cc;
		--surface-violet-1: #221c42;
		--surface-cyan-1: #0b252d;
		--surface-pink-1: #471432cc;
		--surface-menu-bar: #0c0a08;
		--surface-cards: #15110d;
		--surface-modal: #1f1a14;
		--surface-selected: #362c20;
		--ink-white: #0c0a08;
		--ink-gray-1: #1f1a14;
		--ink-gray-2: #362c20;
		--ink-gray-3: #6b5f50;
		--ink-gray-4: #6b5f50;
		--ink-gray-5: #8b7f6d;
		--ink-gray-6: #a89b8a;
		--ink-gray-7: #b8ab99;
		--ink-gray-8: #d3c8ba;
		--ink-gray-9: #f4ede4;
		--ink-red-2: #681916;
		--ink-red-3: #e43838;
		--ink-red-4: #fc7474;
		--ink-green-2: #1ba964;
		--ink-green-3: #58c08e;
		--ink-amber-2: #e37d00;
		--ink-amber-3: #e79913;
		--ink-blue-2: #3294e3;
		--ink-blue-3: #5aaef2;
		--ink-cyan-1: #3cb8dc;
		--ink-pink-1: #e359ab;
		--ink-violet-1: #9d7cea;
		/* Único cromático que sí pisamos: es el color de los enlaces, y en ITEVOX
		   los enlaces son ámbar. El nombre dice "blue" porque es de Frappe. */
		--ink-blue-link: var(--accent);

		/* Superficies que Frappe fija en `white` literal (no salen de la rampa). */
		--bg-color: var(--itevox-bg);
		--fg-color: var(--itevox-bg-elev);
		--modal-bg: var(--itevox-bg-elev);
		--popover-bg: var(--itevox-bg-elev);
		--navbar-bg: var(--itevox-bg);
		--code-block-bg: var(--itevox-bg-elev-2);
		--code-block-text: var(--itevox-text-muted);

		/* `--text-dark` significa "texto sobre fondo oscuro", y Frappe lo deriva de
		   --fg-color asumiendo que es blanco. Invertido el tema, hay que fijarlo. */
		--text-dark: var(--itevox-text);

		/* El primario de Frappe es gris-900 (negro). Aquí es el ámbar de marca. */
		--primary: var(--accent);
		--primary-color: var(--accent);
		--btn-primary: var(--accent);
		--border-primary: var(--accent);
		--checkbox-color: var(--accent);
		--checkbox-focus-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent);

		/* Fondos de alerta: la escala azul/verde/roja de Frappe es clarísima y
		   sobre el fondo cálido se ve como parches. Se retintan las cuatro que sí
		   aparecen en el portal (validación de formularios, acuse de envío). */
		--alert-bg-danger: color-mix(in oklab, var(--itevox-cherry) 16%, var(--itevox-bg-elev));
		--alert-bg-warning: color-mix(in oklab, var(--itevox-amber) 16%, var(--itevox-bg-elev));
		--alert-bg-info: color-mix(in oklab, var(--itevox-teal) 14%, var(--itevox-bg-elev));
		--alert-bg-success: color-mix(in oklab, var(--itevox-success) 14%, var(--itevox-bg-elev));
		--alert-text-danger: #f8a1a4;
		--alert-text-warning: #f7c46c;
		--alert-text-info: #6fd8ce;
		--alert-text-success: #85e5b4;

		--font-stack: "Instrument Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
		--itevox-font-display: "Archivo", ui-sans-serif, system-ui, sans-serif;
		--itevox-font-mono: "IBM Plex Mono", ui-monospace, monospace;

		/* La curva de estados del sitio (`--ease-snappy` en globals.css). */
		--itevox-ease: cubic-bezier(0.2, 0, 0, 1);
	}
}

/* ═══════════════════════════════════════════════════════════════════════════
   Base
   ═══════════════════════════════════════════════════════════════════════════ */

body {
	background-color: var(--bg-color);
	color: var(--itevox-text-muted);
	font-family: var(--font-stack);
	font-feature-settings: "cv11", "ss01";
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

/* Archivo en su corte Expanded para los títulos grandes, igual que en el sitio.
   De H3 para abajo se queda en el ancho normal: a tamaño chico el Expanded
   pierde legibilidad y se lee como un error de tracking. */
h1,
h2,
.web-form-title h1,
.page-header h1 {
	font-family: var(--itevox-font-display);
	font-weight: 800;
	font-stretch: 125%;
	line-height: 1.05;
	letter-spacing: -0.02em;
	color: var(--itevox-text);
}

h3,
h4,
h5,
h6,
.section-head,
.head-title {
	font-family: var(--itevox-font-display);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--itevox-text);
}

p,
li,
td,
label,
.control-label {
	color: var(--itevox-text-muted);
}

a {
	color: var(--accent);
	text-decoration: none;
	transition: color 0.15s var(--itevox-ease);
}

a:hover,
a:focus {
	color: color-mix(in oklab, var(--accent) 78%, white);
	text-decoration: none;
}

/* Foco visible en todos lados, en el color de acento. Es requisito de
   accesibilidad y además es el detalle que más delata un tema a medio hacer. */
:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: 2px;
}

::selection {
	background-color: color-mix(in oklab, var(--accent) 35%, transparent);
	color: var(--itevox-text);
}

hr {
	border-color: var(--itevox-border);
}

/* Cifras tabulares donde hay números que se comparan en columna (importes,
   RFC, códigos postales): evita que la columna baile entre renglones. */
.tnum,
td.text-right,
.indicator-pill {
	font-variant-numeric: tabular-nums;
}

/* Eyebrow mono en versalitas — el recurso tipográfico de la casa.
 *
 * Es OPT-IN por clase y no se cuelga de ningún selector de Frappe a propósito.
 * La versión anterior apuntaba a `.web-form-head .text-muted` creyendo que ahí
 * vivía un rótulo corto, y lo que hay es el párrafo de descripción del web
 * form: una oración completa quedaba en mayúsculas con tracking de 0.14em,
 * ilegible. Un eyebrow son dos o tres palabras; si no lo controlamos nosotros,
 * no lo tipografiamos así. */
.text-eyebrow {
	font-family: var(--itevox-font-mono);
	font-size: 0.8125rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--itevox-text-help);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Navbar y footer
   ═══════════════════════════════════════════════════════════════════════════ */

.navbar,
.navbar-light,
.navbar-expand-lg {
	background-color: var(--navbar-bg) !important;
	border-bottom: 1px solid var(--itevox-border);
}

.navbar .nav-link,
.navbar .navbar-brand {
	color: var(--itevox-text) !important;
}

.navbar .nav-link:hover {
	color: var(--accent) !important;
}

/* El item activo ya trae `border-bottom: 1px solid var(--primary)` de Frappe,
   así que hereda el ámbar solo. Aquí solo se engrosa para que se note. */
.navbar .nav-item.active {
	border-bottom-width: 2px;
}

.navbar-brand img {
	height: 26px;
	width: auto;
}

.web-footer,
footer {
	background-color: var(--itevox-bg);
	border-top: 1px solid var(--itevox-border);
	color: var(--itevox-text-help);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Superficies
   ═══════════════════════════════════════════════════════════════════════════ */

.card,
.web-form-header,
.web-form-container,
.portal-section,
.box,
.modal-content,
.dropdown-menu {
	background-color: var(--itevox-bg-elev);
	border-color: var(--itevox-border);
	color: var(--itevox-text-muted);
}

.dropdown-item {
	color: var(--itevox-text-muted);
}

.dropdown-item:hover,
.dropdown-item:focus {
	background-color: var(--itevox-bg-elev-2);
	color: var(--itevox-text);
}

/* Rejilla "blueprint" tenue de fondo — la textura de infraestructura del sitio.
   Va solo en el shell de la página para que no interfiera con la lectura de los
   formularios. */
.page-content-wrapper {
	background-image:
		linear-gradient(to right, color-mix(in oklab, var(--itevox-text) 3%, transparent) 1px, transparent 1px),
		linear-gradient(to bottom, color-mix(in oklab, var(--itevox-text) 3%, transparent) 1px, transparent 1px);
	background-size: 64px 64px;
}

/* Filete de acento que degrada: el "hairline" que cose las secciones en el
   sitio. Aquí corona el encabezado del web form. */
.web-form-header {
	position: relative;
	overflow: hidden;
}

.web-form-header::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 1px;
	background: linear-gradient(90deg, var(--accent), transparent 75%);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Controles

   `$input-bg`, `$input-border-color` y `$input-focus-bg` quedaron compilados a
   hexadecimal claro en el bundle de Bootstrap, así que van explícitos.
   ═══════════════════════════════════════════════════════════════════════════ */

.form-control,
.frappe-control input,
.frappe-control textarea,
.frappe-control select,
select.form-control,
textarea.form-control,
.like-disabled-input {
	background-color: var(--itevox-bg-elev-2);
	border: 1px solid var(--itevox-border);
	border-radius: 0.75rem;
	color: var(--itevox-text);
	transition:
		border-color 0.15s var(--itevox-ease),
		background-color 0.15s var(--itevox-ease);
}

.form-control:focus,
.frappe-control input:focus,
.frappe-control textarea:focus,
.frappe-control select:focus {
	background-color: var(--itevox-bg-elev-2);
	border-color: color-mix(in oklab, var(--accent) 55%, var(--itevox-border));
	box-shadow: none;
	color: var(--itevox-text);
}

.form-control::placeholder {
	color: var(--itevox-text-help);
}

.form-control:disabled,
.form-control[readonly] {
	background-color: var(--itevox-bg-elev);
	color: var(--itevox-text-help);
}

/* La flecha del <select> viene como SVG con el trazo en gris oscuro embebido
   (`--right-arrow-svg`); sobre fondo oscuro desaparece. */
select.form-control {
	background-image: url("data:image/svg+xml;utf8,<svg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M1 1l4 4 4-4' stroke='%23a89b8a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
	background-repeat: no-repeat;
	background-position: right 0.85rem center;
	padding-right: 2.25rem;
	appearance: none;
}

.help-box,
.form-text,
small.text-muted {
	color: var(--itevox-text-help);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Página de login

   Es la única superficie del portal que carga SU PROPIA hoja (`login.bundle`)
   DESPUÉS de `web_include_css`, y no hay forma de reordenar eso desde el app.
   Todo lo de aquí es, por tanto, pelea de especificidad, y cada regla dice
   contra qué pelea.

   El problema de fondo: `login.bundle` fija `color:#fff` a mano en el botón y
   saca el fondo de `var(--gray-900)`. Con la rampa invertida, gray-900 pasó de
   negro a `#f4ede4` y el par quedó en blanco sobre blanco — 1.05:1, ilegible.
   Medido contra el sitio real el 2026-07-31; no es teórico.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Se omiten los prefijos `.for-*` (login, forgot, signup, reset-password…) a
   propósito: sin ellos la regla cubre los seis estados de la tarjeta con un
   solo selector.

   El `!important` del fondo está MEDIDO, no puesto por si acaso. `html:root
   .page-card .page-card-actions .btn-login` es (0,4,1) contra el (0,4,0) de
   Frappe, y aun así `color` se aplicaba y `background` no. Con `!important`
   el botón computa `rgb(245,166,35)` y se verificó que el único `!important`
   sobre ese elemento es el nuestro — no estamos ganándole a otro. */
html:root .page-card .page-card-actions .btn-login,
html:root .page-card .page-card-actions .btn-ldap-login {
	background: var(--accent) !important;
	color: var(--itevox-sobre-acento) !important;
	font-weight: 600;
	border: none;
}

html:root .page-card .page-card-actions .btn-login:hover,
html:root .page-card .page-card-actions .btn-login:focus,
html:root .page-card .page-card-actions .btn-ldap-login:hover {
	background: var(--accent) !important;
	color: var(--itevox-sobre-acento) !important;
	filter: brightness(1.1);
}

/* El de "Iniciar sesión con Google" y demás secundarios. */
html:root .page-card .page-card-actions .btn-signup,
html:root .page-card .page-card-actions .btn-signup:not(:disabled) {
	background: var(--itevox-bg-elev-2);
	color: var(--itevox-text);
	border: 1px solid var(--itevox-border);
}

/* …salvo en /update-password, donde `.btn-signup` NO es el secundario: es el
   ÚNICO botón, y confirma la contraseña.

   Frappe reutiliza esa clase con dos significados opuestos —en /login viene
   junto a `.btn-forgot` y es el enlace secundario; aquí es la acción
   principal—, así que la regla de arriba lo dejaba apagado justo en la primera
   pantalla que ve un cliente al aceptar su invitación. Lo señaló David el
   2026-08-31: «nada que ver con el login».

   Se distingue por `data-path`, que Frappe sí pone en el <body> — y no por el
   `id="page-update-password"`, que vive en un <div> interno. Confundir esos dos
   es exactamente lo que dejó el «Plano de identidad» sin activarse en 0.25.0.

   Especificidad: (0,5,2) contra el (0,4,1) de la regla de arriba, así que gana
   sin `!important`. El `background` sí lo lleva porque pelea contra el de
   Frappe, igual que en `.btn-login`. */
html:root body[data-path="update-password"] .page-card .page-card-actions .btn-signup {
	background: var(--accent) !important;
	color: var(--itevox-sobre-acento) !important;
	font-weight: 600;
	border: none;
}

html:root body[data-path="update-password"] .page-card .page-card-actions .btn-signup:hover,
html:root body[data-path="update-password"] .page-card .page-card-actions .btn-signup:focus {
	background: var(--accent) !important;
	color: var(--itevox-sobre-acento) !important;
	filter: brightness(1.1);
}

/* Frappe lo sirve `disabled` hasta que las dos contraseñas coinciden. Apagado
   pero legible: un botón principal en gris ilegible se lee como "roto", no como
   "todavía no".

   `--itevox-text-muted` y no `--itevox-text-help`, y está MEDIDO: sobre
   `--itevox-bg-elev-2` el help da 5.73:1 en claro pero **4.40:1 en oscuro**, o
   sea que se queda a un pelo de AA justo en el tema que más se usa de noche. El
   muted da 7.54 y 6.35. Es la misma familia del hallazgo que obligó a crear
   `--itevox-text-help`: el token que "se ve bien" no siempre pasa en los dos
   temas, y sólo se sabe midiendo. */
html:root body[data-path="update-password"] .page-card .page-card-actions .btn-signup:disabled {
	background: var(--itevox-bg-elev-2) !important;
	color: var(--itevox-text-muted) !important;
	border: 1px solid var(--itevox-border);
	filter: none;
}

/* Aquí sí va `!important`, y es una decisión, no flojera. El selector de Frappe
   es `.for-<estado> .page-card .page-card-body input[type="…"]` → (0,4,1), y
   ganarle por especificidad obligaría a repetir los seis estados por los tres
   tipos de input (18 selectores) o a meter trucos tipo `[class*="for-"]`. Entre
   eso y tres `!important` acotados a la tarjeta de login, esto se lee mejor y
   se rompe igual de poco. */
html:root .page-card .page-card-body input[type="text"],
html:root .page-card .page-card-body input[type="email"],
html:root .page-card .page-card-body input[type="password"] {
	background-color: var(--itevox-bg-elev-2) !important;
	color: var(--itevox-text) !important;
	border: 1px solid var(--itevox-border) !important;
}

/* El logo del login NO sale de `app_logo_url` (eso es el escritorio): Frappe
   sirve ahí su propia marca por defecto. `itevox_login.js` la reemplaza por
   la nuestra (fijar `.src` a mano es más sólido entre navegadores que
   `content: url(...)` sobre un elemento reemplazado como `<img>`). */
html:root .page-card .app-logo {
	border-radius: 8px;
	width: 28px;
	height: 28px;
}

/* La franja de marca del login: `.page-card-head` pasa de fondo transparente
   a la tinta oscura de siempre (`#1a1510`, la misma del membrete impreso) —
   FIJA, no la variable de tema, porque esto es la marca, no una superficie
   que deba seguir claro/oscuro del sistema. `overflow: hidden` en `.page-card`
   es lo que le da las esquinas redondeadas de la tarjeta sin tener que
   adivinar su radio.

   El logo y la palabra "ITEVOX" los pone `itevox_login.js` como texto real
   del DOM — no `content` de un `::after`, que muchos lectores de pantalla no
   anuncian. */
html:root .page-card {
	overflow: hidden;
}

html:root .page-card-head {
	background: #1a1510;
	padding: 28px 32px 24px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
}

/* El lockup: ícono + "ITEVOX" en una sola fila. `itevox_login.js` MUEVE el
   <img> del logo aquí adentro (no lo copia), así que el estilo del ícono va
   sobre `.itevox-login-marca .app-logo`, no sobre el selector suelto de
   abajo (ver la nota de compatibilidad con `/documentos` etc. más arriba). */
html:root .page-card-head .itevox-login-marca {
	display: flex;
	align-items: center;
	gap: 8px;
}

html:root .page-card-head .itevox-login-marca .app-logo {
	margin: 0;
	width: 22px;
	height: 22px;
}

html:root .page-card-head .itevox-login-wordmark {
	font-family: 'Archivo', -apple-system, sans-serif;
	font-weight: 800;
	font-stretch: 125%;
	font-size: 1.05rem;
	letter-spacing: 0.02em;
	color: #f5a623;
}

html:root .page-card-head .itevox-login-lema {
	font-family: 'Instrument Sans', -apple-system, sans-serif;
	font-size: 0.8rem;
	color: #f7f3ec;
	opacity: 0.72;
	margin: 0;
}

html:root .page-card-head-text h4 {
	color: #f7f3ec;
	font-weight: 700;
	margin: 0;
}

html:root .page-card-head-text .page-card-subtitle {
	color: #f7f3ec;
	opacity: 0.78;
	margin: 0;
}

/* ─────────────────────────────────────────────────────────────────────────
   /login — el «Plano de identidad» (docs/mockups/login/direction-3.html).

   Sólo `/login` lo recibe: `itevox_login.js` pone `id="page-login"` en el
   <body> —único entre las páginas con `.page-card-head`— así que
   `/forgot-password` y `/reset-password` se quedan con la franja simple de
   arriba. Colores FIJOS, no `var(--itevox-*)` de tema: son exactamente los
   valores que esas variables ya toman en `prefers-color-scheme: dark` (ver
   el bloque `[data-theme=dark]`/`@media` de este archivo), copiados a mano
   porque esto es la marca del login, no una superficie que deba seguir el
   claro/oscuro del sistema — el mismo argumento que ya vale para la franja
   café de `.page-card-head`.

   Por debajo de 1100px el grafo se oculta y todo vuelve a la tarjeta
   centrada de siempre — un SVG de 940×560 con quince etiquetas no cabe en
   una pantalla de celular sin volverse ilegible, y el reclamo original era
   sobre el monitor de escritorio, no el teléfono.
   ───────────────────────────────────────────────────────────────────────── */
body.itevox-plano-de-identidad {
	--itevox-plano-bg: #0c0a08;
	--itevox-plano-bg-elev: #15110d;
	--itevox-plano-bg-elev-2: #1f1a14;
	--itevox-plano-border: #2a2118;
	--itevox-plano-text: #f4ede4;
	--itevox-plano-text-muted: #a89b8a;
	--itevox-plano-text-dim: #6b5f50;
	--itevox-plano-text-help: #8b7f6d;

	/* `--itevox-amber-texto`/`--itevox-cherry-texto`/`--itevox-success-texto`
	   NO sirven aquí: cambian con `prefers-color-scheme` (oscurecidos en
	   claro para pasar AA sobre un fondo BLANCO), y este panel es oscuro
	   fijo sin importar el tema del sistema — con el sistema en claro esas
	   variantes se ven apagadas sobre un fondo que sigue oscuro. Mismo
	   argumento que ya vale para `--itevox-plano-bg` y compañía: valores
	   fijos, iguales a los que los tokens de marca YA tienen en oscuro
	   (donde sí pasan AA — el ámbar da 9.75:1 sobre este fondo, medido).
	   Ver `scripts/check_tema.py:ACENTOS_SIN_TEXTO`. */
	--itevox-plano-amber-texto: #f5a623;
	--itevox-plano-cherry-texto: #e5484d;
	--itevox-plano-success-texto: #3dd68c;
}

html:root body.itevox-plano-de-identidad {
	background: var(--itevox-plano-bg);
}

html:root body.itevox-plano-de-identidad .page-content-wrapper {
	padding-top: 0;
}

/* Cabecera monumental: el wordmark que en el resto del sitio va a 1.05rem
   aquí cruza casi todo el ancho — es la tesis de la página, no un logo de
   esquina. `font-stretch` usa el eje `wdth` de Archivo, igual que el resto
   de la marca. */
html:root .itevox-plano-cabecera {
	max-width: 1290px;
	margin: 0 auto;
	padding: 44px 24px 22px;
}

html:root .itevox-plano-wordmark {
	font-family: 'Archivo', -apple-system, sans-serif;
	font-weight: 800;
	font-stretch: 125%;
	font-size: clamp(2.75rem, 9vw, 6.75rem);
	line-height: 0.92;
	letter-spacing: 0.015em;
	color: var(--itevox-plano-text);
}

html:root .itevox-plano-x {
	color: var(--itevox-plano-amber-texto);
}

html:root .itevox-plano-subfila {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 20px;
	margin-top: 14px;
}

html:root .itevox-plano-lema {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 0.7rem;
	letter-spacing: 0.35em;
	text-transform: uppercase;
	color: var(--itevox-plano-text-muted);
}

html:root .itevox-plano-telemetria {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 0.65rem;
	letter-spacing: 0.14em;
	color: var(--itevox-plano-text-dim);
	display: flex;
	align-items: center;
	gap: 9px;
}

html:root .itevox-plano-punto {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--itevox-success);
	flex: none;
	animation: itevox-plano-latido 2.8s steps(2, jump-none) infinite;
}

@keyframes itevox-plano-latido {
	50% {
		opacity: 0.3;
	}
}

html:root .itevox-plano-regla {
	max-width: 1290px;
	margin: 0 auto;
	height: 1px;
	background: var(--itevox-plano-border);
}

/* El cuerpo deja de ser un contenedor de una sola columna y se vuelve la
   rejilla panel+grafo. Sigue siendo el MISMO elemento que Frappe ya trae
   —nada se reemplaza, sólo se le agregan una clase y un hermano nuevo
   (`.itevox-grafo`)—.

   **Se engancha por `.itevox-plano-cuerpo` y no por `section.for-login`.** Esa
   sección sólo existe en `/login`; en `/update-password` el formulario cuelga
   directo de la tarjeta, así que atarse al selector de Frappe dejaba sin plano
   justamente a la pantalla que más lo necesita — la de establecer contraseña es
   la primera que ve un cliente al aceptar su invitación. La clase la pone el
   JS sobre el elemento que corresponda en cada página. */
html:root .itevox-plano-cuerpo {
	max-width: 1290px;
	margin: 0 auto;
	padding: 28px 24px 36px;
	display: grid;
	grid-template-columns: minmax(320px, 420px) minmax(0, 1fr);
	gap: 48px;
	align-items: center;
}

html:root .itevox-plano-pie {
	/* `<footer>` ya trae borde y margen superior de la regla genérica del
	   pie de página (más abajo en este archivo) — no aplica aquí, este pie
	   es parte del plano, no el `web-footer` de una página normal. */
	border-top: none;
	margin: 0 auto;
	max-width: 1290px;
	padding: 10px 24px 26px;
	display: flex;
	flex-wrap: wrap;
	gap: 4px 16px;
	justify-content: space-between;
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 0.65rem;
	letter-spacing: 0.12em;
	color: var(--itevox-plano-text-dim);
}

/* El panel: `.page-card` pasa de tarjeta blanca centrada a panel elevado
   sobre el café — un solo tono para cabeza, cuerpo y acciones, no la franja
   de dos tonos que usan /forgot-password y /reset-password. */
html:root body.itevox-plano-de-identidad .page-card {
	max-width: none;
	margin: 0;
	background: var(--itevox-plano-bg-elev);
	border: 1px solid var(--itevox-plano-border);
	border-radius: 12px;
	box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.9);
}

html:root body.itevox-plano-de-identidad .page-card-head {
	background: transparent;
	padding: 36px 38px 0;
	gap: 6px;
}

html:root body.itevox-plano-de-identidad .page-card-head-text h4 {
	font-family: 'Archivo', -apple-system, sans-serif;
	font-stretch: 120%;
	font-size: 1.6rem;
	color: var(--itevox-plano-text);
}

html:root body.itevox-plano-de-identidad .page-card-head-text .page-card-subtitle {
	color: var(--itevox-plano-text-help);
	opacity: 1;
	font-size: 0.9rem;
}

html:root body.itevox-plano-de-identidad .page-card-body,
html:root body.itevox-plano-de-identidad .page-card-actions {
	padding-left: 38px;
	padding-right: 38px;
}

html:root body.itevox-plano-de-identidad .page-card-body {
	padding-top: 20px;
	padding-bottom: 0;
}

/* `.page-card-body` y `.page-card-actions` son dos cajas separadas que
   Frappe pinta con su propio padding cada una — bien cuando son dos tonos
   distintos (la franja café + el cuerpo blanco de siempre), pero aquí son
   el MISMO panel, y sumar el padding inferior de una con el superior de la
   otra dejaba un vacío de más entre "¿Olvidaste tu contraseña?" y
   "Continuar". */
html:root body.itevox-plano-de-identidad .page-card-actions {
	padding-top: 4px;
}

html:root body.itevox-plano-de-identidad .form-label {
	color: var(--itevox-plano-text-muted);
	font-weight: 600;
	font-size: 0.8rem;
}

/* Mismo `!important` que ya justifica el bloque de arriba de este archivo
   (Frappe gana por `.for-<estado>` a menos que se le iguale con `!important`)
   — aquí con colores fijos, no `var(--itevox-bg-elev-2)`, que cambia con el
   tema del sistema y aquí no debe. */
html:root body.itevox-plano-de-identidad .page-card-body input[type="text"],
html:root body.itevox-plano-de-identidad .page-card-body input[type="email"],
html:root body.itevox-plano-de-identidad .page-card-body input[type="password"] {
	background-color: var(--itevox-plano-bg-elev-2) !important;
	color: var(--itevox-plano-text) !important;
	border: 1px solid var(--itevox-plano-text-dim) !important;
}

html:root body.itevox-plano-de-identidad .page-card-body input[type="text"]::placeholder,
html:root body.itevox-plano-de-identidad .page-card-body input[type="email"]::placeholder,
html:root body.itevox-plano-de-identidad .page-card-body input[type="password"]::placeholder {
	color: var(--itevox-plano-text-help);
}

html:root body.itevox-plano-de-identidad .page-card-body input[type="text"]:focus,
html:root body.itevox-plano-de-identidad .page-card-body input[type="email"]:focus,
html:root body.itevox-plano-de-identidad .page-card-body input[type="password"]:focus {
	border-color: var(--itevox-amber) !important;
	box-shadow: 0 0 0 3px rgba(245, 166, 35, 0.25);
}

html:root body.itevox-plano-de-identidad .field-icon,
html:root body.itevox-plano-de-identidad .toggle-password {
	color: var(--itevox-plano-text-dim);
}

html:root body.itevox-plano-de-identidad .forgot-password-message a {
	color: var(--itevox-plano-amber-texto);
}

html:root body.itevox-plano-de-identidad .page-card-actions .btn-signup,
html:root body.itevox-plano-de-identidad .page-card-actions .btn-google {
	background: var(--itevox-plano-bg-elev-2);
	color: var(--itevox-plano-text);
	border: 1px solid var(--itevox-plano-text-dim);
}

html:root body.itevox-plano-de-identidad .page-card-actions .btn-signup:hover,
html:root body.itevox-plano-de-identidad .page-card-actions .btn-google:hover {
	background: var(--itevox-plano-border);
}

/* El grafo de confianza — ver el encabezado de itevox_login.js. Nombres de
   clase con prefijo `itevox-` para no chocar con nada de Frappe/Bootstrap;
   los datos que dibuja (identidades, certificados, decisiones de acceso)
   son ILUSTRATIVOS, marcados como tal en su propia leyenda. */
html:root .itevox-grafo {
	position: relative;
	height: 100%;
	min-height: 420px;
}

html:root .itevox-grafo svg {
	width: 100%;
	height: 100%;
	display: block;
}

html:root .itevox-aro {
	fill: none;
	stroke: var(--itevox-plano-border);
	stroke-width: 1;
	stroke-dasharray: 1 6;
	stroke-linecap: round;
}

html:root .itevox-arista {
	fill: none;
	stroke: var(--itevox-amber);
	stroke-width: 1.8;
	stroke-linecap: round;
	opacity: 0.75;
}

html:root .itevox-arista.itevox-flujo {
	stroke: var(--itevox-plano-text);
	stroke-width: 1.5;
	opacity: 0.95;
	stroke-dasharray: 3 21;
	animation: itevox-plano-flujo 2.8s linear infinite;
}

@keyframes itevox-plano-flujo {
	to {
		stroke-dashoffset: -48;
	}
}

html:root .itevox-arista.itevox-pendiente {
	stroke: var(--itevox-plano-text-dim);
	stroke-dasharray: 2 7;
	opacity: 0.9;
	animation: none;
}

html:root .itevox-arista.itevox-revocada {
	stroke: var(--itevox-cherry);
	stroke-dasharray: 2 7;
	opacity: 0.7;
	animation: none;
}

html:root .itevox-anillo {
	fill: none;
	stroke: var(--itevox-amber);
	opacity: 0.35;
}

html:root .itevox-anillo.itevox-pulso {
	animation: itevox-plano-pulso 3.4s ease-out infinite;
	transform-origin: center;
	transform-box: fill-box;
}

@keyframes itevox-plano-pulso {
	0% {
		opacity: 0.5;
		stroke-width: 1.5;
	}
	70% {
		opacity: 0;
		stroke-width: 0.5;
	}
	100% {
		opacity: 0;
	}
}

html:root .itevox-nodo-nucleo,
html:root .itevox-nodo-verificado {
	fill: var(--itevox-amber);
}

html:root .itevox-nodo-sesion {
	fill: none;
	stroke: var(--itevox-amber);
	stroke-width: 1.5;
	stroke-dasharray: 2.4 2.4;
}

html:root .itevox-nodo-pendiente {
	fill: none;
	stroke: var(--itevox-plano-text-help);
	stroke-width: 1.5;
	stroke-dasharray: 2.4 2.4;
}

html:root .itevox-nodo-revocado {
	fill: none;
	stroke: var(--itevox-cherry);
	stroke-width: 1.5;
}

html:root .itevox-nodo-revocado-linea {
	stroke: var(--itevox-cherry);
	stroke-width: 1.5;
}

html:root .itevox-grafo-etq-nombre {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 13px;
	fill: var(--itevox-plano-text);
	font-weight: 600;
}

html:root .itevox-grafo-etq-r0 {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 9.5px;
	fill: var(--itevox-plano-amber-texto);
	opacity: 0.8;
	letter-spacing: 1.5px;
}

html:root .itevox-grafo-etq-nodo {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 12px;
	fill: var(--itevox-plano-text-muted);
}

html:root .itevox-grafo-etq-protocolo {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 9px;
	fill: var(--itevox-plano-text-dim);
}

html:root .itevox-grafo-etq-anillo {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 9.5px;
	fill: var(--itevox-plano-text-dim);
	letter-spacing: 2px;
}

html:root .itevox-grafo-permitido {
	fill: var(--itevox-plano-success-texto);
}

html:root .itevox-grafo-denegado {
	fill: var(--itevox-plano-cherry-texto);
}

html:root .itevox-leyenda {
	position: absolute;
	right: 4px;
	bottom: 0;
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: 10px;
	letter-spacing: 0.1em;
	color: var(--itevox-plano-text-dim);
	display: flex;
	gap: 18px;
	align-items: center;
	flex-wrap: wrap;
}

html:root .itevox-marca-verificada {
	color: var(--itevox-plano-amber-texto);
}

html:root .itevox-marca-pendiente {
	color: var(--itevox-plano-text-dim);
}

html:root .itevox-marca-revocada {
	color: var(--itevox-plano-cherry-texto);
}

html:root .itevox-muestra-mtls {
	display: inline-block;
	width: 20px;
	height: 0;
	vertical-align: middle;
	margin-right: 6px;
	border-top: 2px solid var(--itevox-amber);
}

html:root .itevox-leyenda-nota {
	opacity: 0.7;
}

/* Por debajo de esto el grafo no cabe sin volverse ilegible: se oculta y el
   panel vuelve a ser una tarjeta centrada de ancho completo — la misma
   experiencia de celular que ya existía antes de este rediseño. */
@media (max-width: 1099px) {
	html:root .itevox-grafo,
	html:root .itevox-plano-regla {
		display: none;
	}

	html:root .itevox-plano-cabecera {
		padding: 28px 24px 18px;
	}

	html:root .itevox-plano-wordmark {
		font-size: clamp(2rem, 11vw, 3rem);
	}

	html:root .itevox-plano-subfila {
		margin-top: 8px;
	}

	html:root .itevox-plano-telemetria {
		display: none;
	}

	html:root .itevox-plano-cuerpo {
		display: block;
		max-width: 480px;
		padding: 8px 24px 24px;
	}

	html:root body.itevox-plano-de-identidad .page-card {
		margin: 0 auto;
	}
}

@media (prefers-reduced-motion: reduce) {
	html:root .itevox-arista.itevox-flujo,
	html:root .itevox-anillo.itevox-pulso,
	html:root .itevox-plano-punto {
		animation: none !important;
	}
}

/* ═══════════════════════════════════════════════════════════════════════════
   Botones — píldora, como en itevox.tech
   ═══════════════════════════════════════════════════════════════════════════ */

.btn {
	border-radius: 999px;
	font-weight: 500;
	transition:
		filter 0.15s var(--itevox-ease),
		border-color 0.15s var(--itevox-ease),
		background-color 0.15s var(--itevox-ease);
}

.btn-primary,
.btn-primary:not(:disabled):not(.disabled) {
	background-color: var(--accent);
	border-color: var(--accent);
	/* Texto oscuro sobre ámbar: el ámbar es demasiado luminoso para texto
	   blanco encima (no pasa AA). */
	color: var(--itevox-bg);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:not(:disabled):not(.disabled):active {
	background-color: var(--accent);
	border-color: var(--accent);
	color: var(--itevox-bg);
	filter: brightness(1.1);
}

.btn-default,
.btn-secondary,
.btn-light {
	background-color: var(--itevox-bg-elev-2);
	border: 1px solid var(--itevox-border);
	color: var(--itevox-text);
}

.btn-default:hover,
.btn-secondary:hover,
.btn-light:hover {
	background-color: var(--itevox-bg-elev);
	border-color: color-mix(in oklab, var(--accent) 50%, var(--itevox-border));
	color: var(--itevox-text);
}

.btn-link {
	color: var(--accent);
}

.btn:disabled,
.btn.disabled {
	opacity: 0.5;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Web form — la superficie que de verdad ve el cliente (Alta de Cliente)
   ═══════════════════════════════════════════════════════════════════════════ */

.web-form .form-section {
	border-color: var(--itevox-border);
}

.web-form .section-head {
	color: var(--itevox-text);
}

/* Progreso por pasos: el paso completado y el activo, en ámbar. */
.slides-progress .slide-step-indicator {
	background-color: var(--itevox-border);
}

.slides-progress .slide-step-complete .slide-step-indicator,
.slides-progress .slide-step.active .slide-step-indicator {
	background-color: var(--accent);
}

.slides-progress .slide-step-complete .step-success {
	color: var(--accent);
}

/* Zona de adjuntos (constancia de situación fiscal, comprobante de domicilio). */
.attachment,
.box-area,
.box-container {
	background-color: var(--itevox-bg-elev-2);
	border-color: var(--itevox-border);
	color: var(--itevox-text-muted);
}

/* Pantalla de acuse tras enviar la solicitud. */
.success-page .success-icon {
	color: var(--itevox-success-texto);
}

.success-page .success-title {
	color: var(--itevox-text);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Tablas y migas
   ═══════════════════════════════════════════════════════════════════════════ */

.table,
.table td,
.table th {
	color: var(--itevox-text-muted);
	border-color: var(--itevox-border);
}

.table thead th {
	color: var(--itevox-text);
	border-bottom-color: var(--itevox-border);
}

.breadcrumb,
.breadcrumb-container ol.breadcrumb {
	background-color: transparent;
}

.breadcrumb a {
	color: var(--itevox-text-help);
}

.breadcrumb a:hover {
	color: var(--accent);
}

/* Los iconos de Frappe se dibujan con `stroke` desde `--icon-stroke`, que sale
   de --gray-800: con la rampa invertida ya salen claros. Esto solo evita que el
   relleno se quede blanco sobre el fondo oscuro. */
.icon {
	--icon-fill-bg: var(--itevox-bg-elev);
}

/* Respetar la preferencia de movimiento reducido, igual que en el sitio. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* ═══════════════════════════════════════════════════════════════════════════
   La rejilla de la tabla hija (Contactos)

   Medido en el sitio el 2026-08-04: el texto capturado salía a **1.05:1** —el
   mismo número que dio el escritorio cuando la rampa estaba al revés—, o sea
   ilegible. La causa es la de siempre en este archivo: Frappe fija una pareja
   (color, fondo) a mano, y aquí la fija DOS veces en hexadecimal literal.

       website.bundle:  .form-control { color:#525252; background-color:#f3f3f3 }
       desk.bundle:     .grid-static-col { background-color: var(--fg-color) }
                        .data-row        { color: var(--text-muted) }

   Y hay un detalle de cascada que no se ve en el HTML: la página sólo enlaza
   cuatro hojas —la nuestra al final, que por eso normalmente gana—, pero el
   `desk.bundle` **no está entre ellas**: lo inyecta el JS al dibujar la rejilla,
   así que entra DESPUÉS y le gana a igual especificidad. De ahí el `html:root`,
   que sube a (0,2,1) y no depende del orden.

   El control se deja transparente en vez de darle fondo propio: dentro de la
   celda Frappe ya le quita bordes, y dos superficies apiladas se ven como un
   parche. Así el par que cuenta es texto contra celda: **16.17:1**.

   Los marcadores de posición van con `--itevox-text-muted` y NO con
   `--itevox-text-help`: sobre el fondo de la celda ése da **4.40:1**, que no
   pasa AA. Es el mismo hallazgo que obligó a crear el token de ayuda, una
   superficie más abajo.
   ═══════════════════════════════════════════════════════════════════════════ */

html:root .form-grid,
html:root .web-form-grid {
	background-color: var(--itevox-bg-elev);
	border-color: var(--itevox-border);
	color: var(--itevox-text);
}

html:root .grid-heading-row,
html:root .grid-heading-row .grid-static-col {
	background-color: var(--itevox-bg-elev-2);
	color: var(--itevox-text-muted);
}

/* `.grid-static-col` es el ancla segura: Frappe la pone en TODAS las celdas
   (`grid_row.js`, líneas 256, 377 y 1064). La primera versión de este bloque
   colgaba de `.form-grid .grid-body .editable-row`, y en el web form eso no
   siempre matchea — las celdas vacías se pusieron oscuras y las que traían un
   control se quedaron blancas, que fue justo lo que se vio en pantalla. */
html:root .grid-static-col,
html:root .grid-body .data-row,
html:root .grid-body .data-row .row-index,
html:root .grid-body .data-row .row-check {
	background-color: var(--itevox-bg-elev);
	color: var(--itevox-text);
}

/* El control dentro de la celda: sin superficie propia, sólo el texto. Frappe
   ya le quita bordes ahí, y dos superficies apiladas se ven como un parche. */
html:root .grid-static-col input,
html:root .grid-static-col select,
html:root .grid-static-col textarea,
html:root .grid-static-col .form-control,
html:root .web-form-grid-row input,
html:root .web-form-grid-row select {
	background-color: transparent;
	border-color: transparent;
	color: var(--itevox-text);
}

html:root .grid-static-col input::placeholder,
html:root .grid-static-col textarea::placeholder,
html:root .grid-static-col .form-control::placeholder {
	color: var(--itevox-text-muted);
}

/* La casilla de «Principal» va en su color de marca y con tamaño de blanco de
   toque: en una columna angosta, una casilla del tamaño por omisión no se lee
   como algo que haya que tocar. */
html:root .grid-static-col input[type="checkbox"] {
	accent-color: var(--accent);
	width: 1rem;
	height: 1rem;
}

html:root .grid-static-col .static-area {
	color: var(--itevox-text);
}

/* ═══════════════════════════════════════════════════════════════════════════
   El aviso de privacidad dentro del alta

   Caja con altura fija y barra propia: un muro de texto legal empujaría los
   campos fuera de la pantalla, y con tope se ve de un vistazo que hay algo que
   leer y hasta dónde llega. `tabindex` va en el HTML para que la caja se pueda
   recorrer con el teclado, no sólo con el ratón.

   Texto en `--itevox-text-muted` y no en el normal: es texto largo de lectura,
   y a 6.35:1 sobre la caja pasa AA de sobra sin competir con los campos.
   ═══════════════════════════════════════════════════════════════════════════ */

html:root .itevox-aviso-caja {
	max-height: 22rem;
	overflow-y: auto;
	padding: 1rem 1.25rem;
	background-color: var(--itevox-bg-elev-2);
	border: 1px solid var(--itevox-border);
	border-radius: 0.75rem;
	color: var(--itevox-text-muted);
	font-size: 0.9375rem;
	line-height: 1.6;
}

html:root .itevox-aviso-caja:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

html:root .itevox-aviso-caja h4 {
	color: var(--itevox-text);
	font-size: 0.9375rem;
	font-weight: 600;
	margin: 1.25rem 0 0.35rem;
}

html:root .itevox-aviso-caja h4:first-child {
	margin-top: 0;
}

html:root .itevox-aviso-caja p {
	margin: 0 0 0.65rem;
}

html:root .itevox-aviso-pie {
	margin-top: 0.6rem;
	color: var(--itevox-text-help);
	font-size: 0.8125rem;
}

/* La página pública, que usa el mismo texto. */
html:root .itevox-legal {
	max-width: 44rem;
	margin: 0 auto;
	color: var(--itevox-text-muted);
	line-height: 1.7;
}

html:root .itevox-legal h1 {
	color: var(--itevox-text);
}

html:root .itevox-legal h3 {
	color: var(--itevox-text);
	margin-top: 2rem;
}

html:root .itevox-legal-version {
	color: var(--itevox-text-help);
	font-size: 0.875rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   La página de inicio del cliente

   Sustituye al `/me` de Frappe —«Welcome to the Portal» sobre una cuadrícula
   vacía—. Lo que manda es la tarjeta de estado: es lo único que el cliente
   necesita al entrar, así que va a lo ancho y arriba de todo.
   ═══════════════════════════════════════════════════════════════════════════ */

html:root .itevox-inicio {
	max-width: 52rem;
	margin: 0 auto;
	padding-bottom: 3rem;
}

html:root .itevox-inicio-saludo h1 {
	color: var(--itevox-text);
	font-family: var(--itevox-font-display);
	margin-bottom: 0.25rem;
}

html:root .itevox-inicio-saludo p {
	color: var(--itevox-text-muted);
	margin-bottom: 2rem;
}

html:root .itevox-tarjeta {
	background-color: var(--itevox-bg-elev);
	border: 1px solid var(--itevox-border);
	border-radius: 1rem;
	padding: 1.5rem;
	display: block;
}

/* El estado, con una barra de acento arriba que cambia según dónde va el alta:
   el color dice de un vistazo si hay algo que hacer o sólo hay que esperar. */
html:root .itevox-estado {
	border-top: 3px solid var(--accent);
	margin-bottom: 2rem;
}

html:root .itevox-estado--en_revision {
	border-top-color: var(--itevox-teal);
}

html:root .itevox-estado--aprobado {
	border-top-color: var(--itevox-success-texto);
}

html:root .itevox-estado--rechazado {
	border-top-color: var(--itevox-cherry-texto);
}

/* Falta un dato fiscal: hay algo que hacer, pero nada está mal. El ámbar de
   marca es el indicador correcto —borde, no texto—, así que va el token crudo. */
html:root .itevox-estado--incompleto {
	border-top-color: var(--itevox-amber);
}

/* El interno que entró por curiosidad: recesivo, porque no es su lugar. */
html:root .itevox-estado--interno {
	border-top-color: var(--itevox-border);
}

html:root .itevox-estado h2 {
	color: var(--itevox-text);
	font-size: 1.375rem;
	margin: 0 0 0.5rem;
}

html:root .itevox-estado p {
	color: var(--itevox-text-muted);
	margin: 0 0 1.25rem;
}

html:root .itevox-boton {
	display: inline-block;
	background-color: var(--accent);
	color: var(--itevox-bg);
	font-weight: 600;
	padding: 0.6rem 1.25rem;
	border-radius: 0.75rem;
	text-decoration: none;
	transition: filter 0.15s var(--itevox-ease);
}

html:root .itevox-boton:hover,
html:root .itevox-boton:focus {
	color: var(--itevox-bg);
	filter: brightness(1.08);
	text-decoration: none;
}

/* El resumen del cliente: cotizaciones, facturas y tickets.
   Reemplazó a las tarjetas de acceso y al bloque de marcas. Ésas eran ligas a
   listas vacías y publicidad dentro de la sesión del cliente — «para el portal
   del cliente no aporta nada», dicho por David el 2026-08-05. */
html:root .itevox-bloque {
	margin-top: 2rem;
}

html:root .itevox-bloque h2 {
	color: var(--itevox-text);
	font-size: 1.125rem;
	margin-bottom: 0.75rem;
}

html:root .itevox-lista {
	list-style: none;
	margin: 0 0 0.75rem;
	padding: 0;
}

html:root .itevox-lista li {
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
	flex-wrap: wrap;
	padding: 0.6rem 0;
	border-bottom: 1px solid var(--itevox-border);
}

html:root .itevox-lista li > a {
	color: var(--itevox-text);
	flex: 1 1 12rem;
	min-width: 0;
}

/* 5.04:1 sobre el fondo de la página y 4.79:1 sobre la tarjeta — medido, no
   estimado. `--itevox-text-dim` daría 3.18 y no pasa AA; ver el comentario de
   los tokens. */
html:root .itevox-fecha,
html:root .itevox-ayuda,
html:root .itevox-vacio {
	color: var(--itevox-text-help);
	font-size: 0.875rem;
}

html:root .itevox-ayuda {
	margin: -0.25rem 0 0.75rem;
}

html:root .itevox-vacio {
	margin: 0 0 0.75rem;
}

html:root .itevox-etiqueta {
	background: var(--itevox-bg-elev-2);
	border-radius: 999px;
	color: var(--itevox-text-muted);
	font-size: 0.75rem;
	padding: 0.15rem 0.6rem;
	white-space: nowrap;
}

/* El token `-texto` es lo que hace que esto funcione en los dos temas: en
   oscuro apunta al cherry de marca (4.80:1 sobre la tarjeta) y en claro a su
   variante oscurecida (5.91-6.53). El cherry crudo sobre claro da 3.54 y no
   pasa AA — lo atrapó `check_tema.py` al escribir el tema claro. */
html:root .itevox-alerta {
	color: var(--itevox-cherry-texto);
}

html:root .itevox-liga {
	display: inline-block;
	font-size: 0.875rem;
	margin-right: 1rem;
}

html:root .itevox-inicio-pie {
	margin-top: 2.5rem;
	padding-top: 1.5rem;
	border-top: 1px solid var(--itevox-border);
	color: var(--itevox-text-help);
	font-size: 0.875rem;
}

html:root .itevox-inicio-pie p {
	margin: 0 0 0.35rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   El armazón del portal: fondo, barra superior y pie

   La página de inicio ya dice lo que hay que decir, pero el marco seguía siendo
   el de Frappe: barra con la palabra «Inicio» en texto plano y un fondo liso.
   El cliente entraba a algo que no se parecía a ITEVOX por ningún lado.

   La marca se pone desde `hooks.py` (`website_context.brand_html`), que gana
   sobre `Website Settings` — o sea que no hace falta estado del sitio. Aquí sólo
   va cómo se ve.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Un velo ámbar muy tenue arriba, que se disuelve. Da profundidad sin competir
   con el contenido: a 4% el color se percibe, no se mira. */
html:root body {
	background-image:
		radial-gradient(
			70rem 32rem at 50% -12rem,
			color-mix(in oklab, var(--accent) 4%, transparent),
			transparent
		);
	background-repeat: no-repeat;
	background-attachment: fixed;
}

html:root .navbar {
	background-color: color-mix(in oklab, var(--itevox-bg) 88%, transparent);
	backdrop-filter: blur(10px);
	border-bottom: 1px solid var(--itevox-border);
}

html:root .navbar .navbar-brand {
	display: inline-flex;
	align-items: center;
	gap: 0.55rem;
	color: var(--itevox-text);
	font-family: var(--itevox-font-display);
	font-weight: 600;
	letter-spacing: 0.02em;
}

html:root .itevox-marca-navbar {
	height: 1.5rem;
	width: auto;
}

html:root .navbar .navbar-brand:hover,
html:root .navbar .navbar-brand:focus {
	color: var(--accent);
	text-decoration: none;
}

/* El pie: separado, recesivo, y sin la caja blanca que trae Bootstrap. */
html:root .web-footer,
html:root footer {
	background-color: transparent;
	border-top: 1px solid var(--itevox-border);
	margin-top: 3rem;
	color: var(--itevox-text-help);
}

html:root footer a {
	color: var(--itevox-text-muted);
}

html:root footer a:hover,
html:root footer a:focus {
	color: var(--accent);
}

/* La elección DISI/FIEL de /contrato (#82): dos tarjetas clicables, sobre
   .itevox-tarjeta. La restricción real de la API —el tipo es del documento
   completo, no por firmante— se traduce en el aviso de que no se puede
   cambiar después de continuar; por eso va como texto normal, no como error. */
html:root .itevox-firma-opciones {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 1rem;
	margin: 1.25rem 0;
}

html:root .itevox-firma-opcion {
	cursor: pointer;
	transition:
		border-color 0.15s var(--itevox-ease),
		background-color 0.15s var(--itevox-ease);
}

html:root .itevox-firma-opcion:hover {
	border-color: var(--accent);
}

html:root .itevox-firma-opcion input[type="radio"] {
	margin-right: 0.5rem;
}

html:root .itevox-firma-opcion h3 {
	display: inline;
	font-size: 1rem;
	color: var(--itevox-text);
}

html:root .itevox-firma-opcion p {
	margin: 0.5rem 0 0;
	color: var(--itevox-text-muted);
	font-size: 0.9rem;
}

html:root .itevox-firma-opcion--elegida {
	border-color: var(--accent);
	background-color: var(--itevox-bg-elev-2);
}

/* El widget del proveedor de firma (Mifiel) vive sólo en esta página, nunca
   en `web_include_js`. AllSign no tiene widget embebible — ver `allsign.py`. */
html:root .itevox-widget {
	margin: 1.25rem 0;
}
