@import "tokens-GYxK_V7.css";

/* ---------- Fonts (self-hosted, see /DESIGN.md) ---------- */

@font-face {
	font-family: 'IBM Plex Sans';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal-dCzU-sz.woff2") format('woff2');
}

@font-face {
	font-family: 'IBM Plex Sans';
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal-mSIWrNY.woff2") format('woff2');
}

@font-face {
	font-family: 'IBM Plex Sans';
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal-pA5FLX3.woff2") format('woff2');
}

@font-face {
	font-family: 'IBM Plex Mono';
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal-78NWkmx.woff2") format('woff2');
}

@font-face {
	font-family: 'IBM Plex Mono';
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal-QJNNIVc.woff2") format('woff2');
}

/* ---------- Reset ---------- */

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

body {
	margin: 0;
}

img,
svg {
	display: block;
	max-width: 100%;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		transition-duration: 0.01ms !important;
	}
}

/* ---------- Base typography ---------- */

body {
	background: var(--color-bg);
	color: var(--color-ink);
	font-family: var(--font-sans);
	font-size: var(--font-size-body);
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
	font-family: var(--font-sans);
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 var(--space-3);
	text-wrap: balance;
}

h1 {
	font-size: var(--font-size-h1);
}
h2 {
	font-size: var(--font-size-h2);
}
h3 {
	font-size: var(--font-size-h3);
}

p {
	margin: 0 0 var(--space-4);
	max-width: 65ch;
}

a {
	color: var(--color-accent);
}

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

.text-muted {
	color: var(--color-ink-muted);
}

.caption {
	font-size: var(--font-size-caption);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--color-ink-muted);
}

.font-mono {
	font-family: var(--font-mono);
}

.tabular-nums {
	font-variant-numeric: tabular-nums;
}

:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

/* ---------- Layout ---------- */

/* Contenedor de toda la aplicación: el menú lateral fijo a la izquierda y el contenido
   al lado. Ver DESIGN.md, «Menú lateral». */
.app-shell {
	min-height: 100vh;
}

.app-content {
	min-width: 0;
	transition: margin-left 0.15s ease;
}

.has-sidebar .app-content {
	margin-left: var(--sidebar-rail);
}

:root[data-sidebar='open'] .has-sidebar .app-content {
	margin-left: var(--sidebar-width);
}

/* Menú lateral (#101). Cerrado: una franja de iconos. Al pasar el ratón o al entrar con
   el teclado se ensancha por encima del contenido y vuelve a encogerse al salir; el
   botón de la barra lo deja fijo abierto y entonces empuja el contenido en vez de
   taparlo. */
.sidebar {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 20;
	width: var(--sidebar-rail);
	overflow: hidden auto;
	background: var(--color-surface);
	border-right: 1px solid var(--color-border);
	transition: width 0.15s ease, box-shadow 0.15s ease;
	/* Columna para que la versión (#150) quede al pie aunque la lista sea corta. */
	display: flex;
	flex-direction: column;
}

.sidebar__list {
	list-style: none;
	margin: 0;
	padding: var(--space-2);
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	/* El contenido se maqueta siempre al ancho desplegado y lo que sobra queda recortado:
	   así los iconos no se mueven de sitio al ensancharse. */
	min-width: var(--sidebar-width);
}

.sidebar__link {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	height: var(--tap-target);
	padding: 0 calc((var(--sidebar-rail) - var(--space-4) - 20px) / 2);
	border-radius: var(--radius-sm);
	color: var(--color-ink-muted);
	text-decoration: none;
	white-space: nowrap;
	transition: background-color 0.12s ease, color 0.12s ease;
}

.sidebar__link:hover {
	background: color-mix(in srgb, var(--color-accent) 6%, var(--color-surface));
	color: var(--color-ink);
}

.sidebar__link.is-current {
	background: color-mix(in srgb, var(--color-accent) 10%, var(--color-surface));
	color: var(--color-accent);
	font-weight: 500;
}

.sidebar__link:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: -2px;
}

.sidebar__icon {
	flex: none;
	display: inline-flex;
	width: 20px;
	height: 20px;
}

/* Los nombres están siempre en el DOM —los lectores de pantalla los leen aunque no se
   vean— y solo aparecen y desaparecen visualmente con el ancho. */
.sidebar__label {
	opacity: 0;
	transition: opacity 0.12s ease;
}

.sidebar__group {
	margin-top: var(--space-3);
	padding: 0 var(--space-3);
	height: 20px;
	overflow: hidden;
}

.sidebar__group-label {
	font-size: var(--font-size-caption);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--color-ink-muted);
	font-weight: 500;
	white-space: nowrap;
	opacity: 0;
	transition: opacity 0.12s ease;
}

/* Estados desplegados: fijado abierto, foco de teclado dentro, o el puntero encima. */
:root[data-sidebar='open'] .sidebar,
.sidebar:focus-within {
	width: var(--sidebar-width);
}

@media (hover: hover) {
	.sidebar:hover {
		width: var(--sidebar-width);
	}

	.sidebar:hover .sidebar__label,
	.sidebar:hover .sidebar__group-label,
	.sidebar:hover .sidebar__version-label {
		opacity: 1;
	}

	/* Desplegado por el ratón pero no fijado: flota sobre el contenido, así que proyecta
	   sombra. Fijado no la lleva, porque entonces el contenido está a su lado. */
	:root:not([data-sidebar='open']) .sidebar:hover {
		box-shadow: var(--shadow-overlay);
	}
}

:root[data-sidebar='open'] .sidebar__label,
:root[data-sidebar='open'] .sidebar__group-label,
:root[data-sidebar='open'] .sidebar__version-label,
.sidebar:focus-within .sidebar__label,
.sidebar:focus-within .sidebar__group-label,
.sidebar:focus-within .sidebar__version-label {
	opacity: 1;
}

/* La versión desplegada (#150), al pie del menú. Cerrado, solo el número; el rótulo
   aparece con los nombres de las secciones. */
.sidebar__version {
	flex: none;
	margin: auto 0 0;
	padding: var(--space-3) var(--space-2);
	min-width: var(--sidebar-width);
	display: flex;
	flex-direction: column;
	gap: 2px;
	color: var(--color-ink-muted);
	border-top: 1px solid var(--color-border);
}

.sidebar__version-label {
	padding: 0 var(--space-3);
	font-size: var(--font-size-caption);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	font-weight: 500;
	white-space: nowrap;
	opacity: 0;
	transition: opacity 0.12s ease;
}

.sidebar__version-number {
	padding: 0 var(--space-3);
	font-family: var(--font-mono);
	font-size: var(--font-size-caption);
	font-variant-numeric: tabular-nums;
}

.sidebar__backdrop {
	display: none;
}

/* Pantallas estrechas: no hay franja; el menú se desliza sobre la página. */
@media (max-width: 767px) {
	.has-sidebar .app-content,
	:root[data-sidebar='open'] .has-sidebar .app-content {
		margin-left: 0;
	}

	.sidebar {
		width: var(--sidebar-width);
		transform: translateX(-100%);
		transition: transform 0.15s ease;
	}

	:root[data-sidebar='open'] .sidebar {
		transform: none;
		box-shadow: var(--shadow-overlay);
	}

	.sidebar__label,
	.sidebar__group-label,
	.sidebar__version-label {
		opacity: 1;
	}

	:root[data-sidebar='open'] .sidebar__backdrop {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 15;
		background: rgba(0, 0, 0, 0.45);
	}
}

.app-header {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	height: 60px;
	padding: 0 var(--space-5);
	background: var(--color-surface);
	border-bottom: 1px solid var(--color-border);
}

.app-header__brand {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-weight: 600;
	color: var(--color-ink);
	text-decoration: none;
}

/* Lo de la derecha: tema, quién ha entrado y salir. */
.app-header__actions {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	margin-left: auto;
}

.app-header__user {
	font-size: var(--font-size-small);
	text-decoration: none;
}

.app-header__logout {
	text-decoration: none;
}

/* En móvil se cae el rótulo de quién ha entrado, que es informativo. «Cerrar sesión» se
   queda: es la única salida que hay, no existe una pantalla de cuenta donde encontrarla. */
@media (max-width: 767px) {
	.app-header {
		padding: 0 var(--space-4);
	}

	.app-header__user {
		display: none;
	}
}

.page {
	padding: var(--space-6) var(--space-5);
}

.page-work {
	max-width: 720px;
	margin: 0 auto;
	padding: var(--space-6) var(--space-5);
}

.page-header {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-4);
	margin-bottom: var(--space-5);
}

.stack {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
}

.cluster {
	display: flex;
	align-items: center;
	gap: var(--space-3);
}

.login-shell {
	min-height: calc(100vh - 60px);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--space-5);
}

.login-card {
	width: 100%;
	max-width: 360px;
}

.login-card h1 {
	font-size: var(--font-size-h2);
	margin-bottom: var(--space-1);
}

/* La marca sobre el título del acceso: es lo primero que se ve de la aplicación. */
.login-card .logo {
	display: block;
	margin-bottom: var(--space-3);
	color: var(--color-ink);
}

/* ---------- Buttons ---------- */

.btn {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	height: 40px;
	padding: 0 var(--space-4);
	border-radius: var(--radius-sm);
	border: 1px solid transparent;
	font-family: var(--font-sans);
	font-size: var(--font-size-small);
	font-weight: 500;
	cursor: pointer;
	text-decoration: none;
	transition: background-color 0.12s ease, border-color 0.12s ease;
}

.btn-primary {
	background: var(--color-accent);
	color: var(--color-accent-contrast);
}

.btn-primary:hover {
	background: var(--color-accent-hover);
	color: var(--color-accent-contrast);
}

.btn-secondary {
	background: transparent;
	border-color: var(--color-border);
	color: var(--color-ink);
}

.btn-secondary:hover {
	border-color: var(--color-accent);
	color: var(--color-accent);
}

.btn-ghost {
	background: transparent;
	color: var(--color-accent);
	height: auto;
	padding: 0;
}

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

.btn-icon {
	width: 40px;
	padding: 0;
	justify-content: center;
	background: transparent;
	border-color: var(--color-border);
	color: var(--color-ink-muted);
}

.btn-icon:hover {
	border-color: var(--color-accent);
	color: var(--color-accent);
}

/* ---------- Forms ---------- */

.field {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

/* Un grupo (etiqueta + control + ayuda) se separa 8px por dentro, así que necesita
   bastante más aire por fuera o el texto de ayuda queda casi equidistante entre su
   propio campo y el siguiente. Sumado al gap de 16px del contenedor da 24px, un
   ratio 3:1 que deja claro qué pertenece a qué. Va como margen —y no subiendo el gap
   de .stack— para no alterar el resto de composiciones que usan esa utilidad. */
.field + .field {
	margin-top: var(--space-2);
}

/* Salvo cuando los campos van en horizontal (p. ej. inicio/fin de ensayo), donde el
   margen superior los desalinearía. */
.cluster > .field + .field {
	margin-top: 0;
}

.field label {
	font-size: var(--font-size-small);
	font-weight: 500;
}

.field .help {
	font-size: var(--font-size-caption);
	color: var(--color-ink-muted);
}

.field input,
.field select,
.field textarea {
	height: 40px;
	padding: 0 var(--space-3);
	background: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	color: var(--color-ink);
	font-family: var(--font-sans);
	font-size: var(--font-size-body);
}

.field textarea {
	height: auto;
	/* 6 líneas (24px de line-height + 24px de padding). Los textarea de la app llevan
	   texto largo de verdad y las 2 líneas por defecto del navegador obligan a escribir
	   por una rendija; la medida está tomada de la cita normativa real de Quesos, la más
	   larga del catálogo, que a este alto entra entera sin scroll. */
	min-height: 144px;
	padding: var(--space-3);
	/* Los controles de formulario no heredan el line-height del body. */
	line-height: 1.5;
	/* Solo vertical: redimensionar a lo ancho se sale de la tarjeta. */
	resize: vertical;
}

input[type='checkbox'],
input[type='radio'] {
	height: 16px;
	width: 16px;
	accent-color: var(--color-accent);
}

/* Keeps the visible control small while giving it a real ~40px hit area
   (native checkboxes ignore padding, so a wrapping label is what actually
   works) — see .claude/skills/interface-design. */
.hit-target {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	cursor: pointer;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
	outline: 2px solid var(--color-accent);
	outline-offset: -1px;
	border-color: var(--color-accent);
}

/* «Mostrar» / «Ocultar» dentro del campo de contraseña (#175). Es un botón de texto, no
   un ojo: dice lo que hace sin tener que reconocer un dibujo. El campo deja sitio a su
   derecha para que lo escrito no quede debajo del botón. */
.password-field {
	position: relative;
	display: flex;
}

.field .password-field input {
	flex: 1;
	min-width: 0;
	padding-right: 88px;
}

.password-toggle {
	position: absolute;
	top: 4px;
	right: 4px;
	height: 32px;
	padding: 0 var(--space-3);
	border: 0;
	border-radius: var(--radius-sm);
	background: transparent;
	color: var(--color-accent);
	font-family: var(--font-sans);
	font-size: var(--font-size-small);
	font-weight: 500;
	cursor: pointer;
}

.password-toggle:hover {
	background: color-mix(in srgb, var(--color-accent) 8%, transparent);
}

.password-toggle:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 0;
}

/* La etiqueta con su enlace a la derecha: «Contraseña» y «¿Olvidaste tu contraseña?». */
.field-label-row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-3);
}

.field-label-row a {
	font-size: var(--font-size-small);
}

.field-check {
	flex-direction: row;
	align-items: center;
	gap: var(--space-2);
}

/* ---------- Card ---------- */

.card {
	background: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	padding: var(--space-5);
}

/* Las páginas de detalle (informe, hoja de ruta) apilan tarjetas directamente dentro de
   <main>, que es un bloque sin gap, así que se tocaban entre sí: los bordes de dos
   tarjetas contiguas se leían como una sola caja partida. Mismo criterio que con los
   grupos de formulario — ver la excepción documentada en DESIGN.md. */
.card + .card {
	margin-top: var(--space-4);
}

/* Cuando el contenedor ya aporta separación (formularios apilados, p. ej. una tarjeta
   por muestra en la parte externa), la pone él y no hay que duplicarla. */
.stack > .card + .card,
.cluster > .card + .card {
	margin-top: 0;
}

/* ---------- Table ---------- */

.table-wrap {
	overflow-x: auto;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
}

table.table-data {
	width: 100%;
	border-collapse: collapse;
	background: var(--color-surface);
}

.table-data th,
.table-data td {
	padding: var(--space-3) var(--space-4);
	text-align: left;
	border-bottom: 1px solid var(--color-border);
	font-size: var(--font-size-small);
}

.table-data th {
	font-size: var(--font-size-caption);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--color-ink-muted);
	font-weight: 500;
	position: sticky;
	top: 0;
	background: var(--color-surface);
}

.table-data tbody tr:last-child td {
	border-bottom: none;
}

.table-data tbody tr:hover {
	background: color-mix(in srgb, var(--color-accent) 4%, var(--color-surface));
}

/* Secondary line inside a table cell: a breakdown that qualifies the main value
   (e.g. the sample types behind a sample count). Deliberately not a pill — those are
   reserved for status — and not a tooltip, which hides the information from touch
   and from keyboard users. */
.table-data .cell-detail {
	display: block;
	margin-top: var(--space-1);
	font-family: var(--font-sans);
	font-size: var(--font-size-caption);
	color: var(--color-ink-muted);
	font-variant-numeric: normal;
}

/* Section header inside a results table: the water/pool report types split their
   determinations into EXAMEN ORGANOLÉPTICO / PARÁMETROS FÍSICO QUÍMICOS / PARÁMETROS
   MICROBIOLÓGICOS. Not sticky like the real <thead>, and slightly inset from the
   surface so it reads as a divider inside the table rather than a second header. */
.table-data tbody th.row-section {
	position: static;
	background: color-mix(in srgb, var(--color-ink) 4%, var(--color-surface));
	color: var(--color-ink);
	font-weight: 600;
}

.table-data tbody tr:hover th.row-section {
	background: color-mix(in srgb, var(--color-ink) 4%, var(--color-surface));
}

.table-data td.numeric,
.table-data th.numeric {
	text-align: right;
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
}

/* ---------- Tarjeta-enlace y rejilla de navegación ---------- */

/* Una tarjeta que además es un enlace: sin subrayado, hereda el color del texto y
   responde al puntero con el mismo tinte de acento al 4% que ya usan las filas de
   tabla. Sustituye a los estilos en línea que se repetían en cada tarjeta. */
.card-link,
.card-link:hover {
	display: block;
	text-decoration: none;
	/* Sin esto, el `a:hover` global teñiría de acento todo el texto de la tarjeta, no
	   solo su título; el cuerpo debe seguir leyéndose como texto. */
	color: inherit;
	transition: background-color 0.12s ease, color 0.12s ease;
}

.card-link:hover {
	background: color-mix(in srgb, var(--color-accent) 4%, var(--color-surface));
}

/* El título sí toma el acento: junto al tinte de fondo es lo que hace que la tarjeta
   entera se lea como un enlace y no como un panel de contenido. */
.card-link:hover h3 {
	color: var(--color-accent-hover);
}

.nav-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: var(--space-4);
}

/* `.card + .card` separa tarjetas apiladas en flujo normal; dentro de una rejilla, que
   ya separa con `gap`, desplazaría hacia abajo todas menos la primera y las
   desalinearía. Se anula igual que dentro de .stack y .cluster (ver DESIGN.md). */
.nav-grid > .card + .card {
	margin-top: 0;
}

.nav-group + .nav-group {
	margin-top: var(--space-5);
}

.nav-group__title {
	font-size: var(--font-size-caption);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--color-ink-muted);
	font-weight: 500;
	margin: 0 0 var(--space-3);
}

/* ---------- Recorrido de los informes (Panel, #58) ---------- */

/* Una tira con los informes por estado, en el orden en que avanzan. Las columnas salen del
   número de pasos: el Director ve cuatro y el técnico tres. */
.report-flow {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	background: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	overflow: hidden;
}

.report-flow__step {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	padding: var(--space-4);
	border-right: 1px solid var(--color-border);
	color: inherit;
	text-decoration: none;
	transition: background-color 0.12s ease;
}

.report-flow__step:last-child {
	border-right: none;
}

a.report-flow__step:hover {
	color: inherit;
	background: color-mix(in srgb, var(--color-accent) 4%, var(--color-surface));
}

a.report-flow__step:hover .report-flow__label {
	color: var(--color-accent-hover);
}

/* La punta de flecha sobre el borde: un cuadrado con dos bordes, girado. */
.report-flow__step:not(:last-child)::after {
	content: '';
	position: absolute;
	top: 50%;
	right: -5px;
	z-index: 1;
	width: 8px;
	height: 8px;
	border-top: 1px solid var(--color-border);
	border-right: 1px solid var(--color-border);
	background: var(--color-surface);
	transform: translateY(-50%) rotate(45deg);
}

.report-flow__value {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	font-size: var(--font-size-h2);
	font-weight: 500;
	line-height: 1.2;
}

.report-flow__value.is-warning {
	color: var(--color-warning);
}

.report-flow__label {
	font-size: var(--font-size-small);
	color: var(--color-ink-muted);
}

.report-flow__aside {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2) var(--space-3);
	margin-top: var(--space-3);
}

a.pill {
	text-decoration: none;
}

/* Sin esto, el `a:hover` global teñiría la ficha de acento y perdería el color de su estado. */
a.pill:hover {
	text-decoration: underline;
}

a.pill-critical:hover {
	color: var(--color-critical);
}

a.pill-neutral:hover {
	color: var(--color-ink-muted);
}

@media (max-width: 559px) {
	.report-flow {
		grid-auto-flow: row;
	}

	/* Apilados, cifra y etiqueta van en la misma línea para que la tira no ocupe la pantalla. */
	.report-flow__step {
		flex-direction: row;
		align-items: baseline;
		gap: var(--space-3);
		padding: var(--space-3) var(--space-4);
		border-right: none;
		border-bottom: 1px solid var(--color-border);
	}

	.report-flow__step:last-child {
		border-bottom: none;
	}

	.report-flow__step:not(:last-child)::after {
		display: none;
	}
}

/* ---------- Búsqueda y filtros de listado ---------- */

.listing-filters {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--space-4);
	margin-bottom: var(--space-4);
}

/* El campo de texto se lleva el espacio sobrante; los desplegables se quedan en su
   ancho natural, que ya lo marca el contenido. */
.listing-filters__search {
	flex: 1 1 220px;
	min-width: 200px;
}

/* Anula el margen entre grupos de formulario apilados: aquí van en horizontal. */
.listing-filters .field + .field {
	margin-top: 0;
}

.listing-filters__active {
	margin-bottom: var(--space-4);
}

/* Criterio activo, con su propio aspa para quitarlo. Redondeo completo como los pills de
   estado: aquí también es semántico —es una etiqueta suelta, no un bloque— y además lo
   distingue de un botón. */
.filter-chip {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-1) var(--space-3);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	font-size: var(--font-size-small);
	color: var(--color-ink);
	text-decoration: none;
	transition: background-color 0.12s ease, border-color 0.12s ease;
}

.filter-chip:hover {
	background: color-mix(in srgb, var(--color-accent) 6%, var(--color-surface));
	border-color: var(--color-accent);
	color: var(--color-ink);
}

/* Texto solo para lectores de pantalla: el aspa se ve, pero "×" no dice qué hace. */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ---------- Paginación ---------- */

.pagination {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	margin-top: var(--space-4);
}

/* El estado va en medio y empuja los dos controles a los extremos: la posición de
   «Anterior» y «Siguiente» no se mueve al cambiar de página, aunque el texto de en medio
   cambie de ancho. Es un <p>, así que hay que quitarle el tope de 65ch de los párrafos:
   con él, `flex: 1` no crecía más allá y «Siguiente» se quedaba a media anchura en
   ordenador (#154). */
.pagination__status {
	flex: 1;
	max-width: none;
	margin: 0;
	text-align: center;
	font-size: var(--font-size-small);
}

/* Extremo de la lista: se deja el control visible pero inerte, en vez de esconderlo, para
   que los dos botones no bailen de sitio en la primera y la última página. */
.btn.is-disabled {
	opacity: 0.45;
	pointer-events: none;
}

/* ---------- Bloque plegable (<details> nativo) ---------- */

/* Agrupa un listado largo bajo cabeceras que se abren y cierran. Se apoya en <details>
   nativo: sin JavaScript, accesible por teclado y con búsqueda del navegador incluida
   en los que la soportan. */
.collapse {
	background: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	overflow: hidden;
}

.collapse + .collapse {
	margin-top: var(--space-3);
}

.collapse__summary {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-3) var(--space-4);
	cursor: pointer;
	font-weight: 500;
	/* Oculta el triángulo del navegador: abajo se dibuja uno propio que sí gira. */
	list-style: none;
}

.collapse__summary::-webkit-details-marker {
	display: none;
}

/* Triángulo dibujado con bordes, no un emoji ni un icono externo (ver DESIGN.md). */
.collapse__summary::before {
	content: '';
	flex: none;
	width: 0;
	height: 0;
	border-left: 5px solid var(--color-ink-muted);
	border-top: 4px solid transparent;
	border-bottom: 4px solid transparent;
	transition: transform 0.12s ease;
}

.collapse[open] > .collapse__summary::before {
	transform: rotate(90deg);
}

.collapse__summary:hover {
	background: color-mix(in srgb, var(--color-accent) 4%, var(--color-surface));
}

.collapse__summary:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: -2px;
}

/* Contador o estado del grupo, alineado al extremo opuesto de la cabecera. */
.collapse__meta {
	margin-left: auto;
	font-size: var(--font-size-small);
	color: var(--color-ink-muted);
	font-weight: 400;
}

.collapse__body {
	border-top: 1px solid var(--color-border);
}

.collapse__empty {
	padding: var(--space-4);
	margin: 0;
	color: var(--color-ink-muted);
	font-size: var(--font-size-small);
}

/* ---------- Status pill ---------- */

.pill {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	height: 24px;
	padding: 0 var(--space-3);
	border-radius: var(--radius-pill);
	font-size: var(--font-size-caption);
	font-weight: 500;
	letter-spacing: 0.02em;
	white-space: nowrap;
}

.pill::before {
	content: '';
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: currentColor;
}

.pill-success {
	background: var(--color-success-bg);
	color: var(--color-success);
}

.pill-warning {
	background: var(--color-warning-bg);
	color: var(--color-warning);
}

.pill-critical {
	background: var(--color-critical-bg);
	color: var(--color-critical);
}

.pill-neutral {
	background: var(--color-bg);
	color: var(--color-ink-muted);
	border: 1px solid var(--color-border);
}

.pill-neutral::before {
	display: none;
}

/* ---------- Theme toggle ---------- */

/* Los dos botones de icono de la barra —el del menú y el del tema— se escriben juntos
   porque tienen que verse iguales. El del menú nació con `.btn-icon`, que es un
   modificador de `.btn` y por sí solo no aporta ni forma ni borde: el navegador lo
   pintaba con su botón por defecto, biselado y a media altura. */
.sidebar-toggle,
.theme-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 36px;
	height: 36px;
	border-radius: var(--radius-sm);
	border: 1px solid var(--color-border);
	background: transparent;
	color: var(--color-ink-muted);
	cursor: pointer;
}

.sidebar-toggle:hover,
.theme-toggle:hover {
	border-color: var(--color-accent);
	color: var(--color-accent);
}

.sidebar-toggle:focus-visible,
.theme-toggle:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

/* ---------- Modal (native <dialog>, driven by confirm_controller.js) ---------- */

.modal {
	width: min(420px, calc(100vw - var(--space-6)));
	padding: var(--space-5);
	background: var(--color-surface);
	color: var(--color-ink);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	/* A real floating element, so this is one of the few places we use a shadow. */
	box-shadow: var(--shadow-overlay);
}

.modal::backdrop {
	background: rgba(0, 0, 0, 0.45);
}

.modal-title {
	margin: 0 0 var(--space-3);
	font-size: var(--font-size-h3);
}

.modal-body {
	margin: 0 0 var(--space-5);
	color: var(--color-ink-muted);
}

.modal-actions {
	display: flex;
	justify-content: flex-end;
	gap: var(--space-3);
}

/* ---------- Firma dibujada en pantalla (#115) ---------- */

/* Siempre blanca, como la placa de la firma en el resto de la aplicación: lo que se
   dibuja aquí acaba sobre el papel del informe, y una firma trazada sobre fondo oscuro
   engaña sobre cómo va a quedar. */
.signature-pad {
	position: relative;
	user-select: none;
	-webkit-user-select: none;
	background: var(--color-signature-bg);
	border: 1px dashed var(--color-border);
	border-radius: var(--radius-sm);
	max-width: 520px;
}

.signature-pad canvas {
	display: block;
	width: 100%;
	height: 180px;
	touch-action: none;
	cursor: crosshair;
}

.signature-pad__placeholder {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	color: #6b7280;
	font-size: var(--font-size-small);
	pointer-events: none;
}

/* `display: grid` ganaría al atributo hidden. */
.signature-pad__placeholder[hidden] {
	display: none;
}

.signature-preview {
	max-height: 80px;
	background: var(--color-signature-bg);
	border-radius: var(--radius-sm);
	padding: var(--space-2);
}

/* ---------- Muestras de la hoja de ruta (#122) ---------- */

/* Cada muestra en su caja, numerada, con el botón de quitarla dentro de su propia
   cabecera: que no quede duda de a cuál afecta. */
.sample-rows {
	counter-reset: sample;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	margin-bottom: var(--space-4);
}

.sample-row {
	counter-increment: sample;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	padding: var(--space-3) var(--space-4) var(--space-4);
}

.sample-row__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	padding-bottom: var(--space-3);
	margin-bottom: var(--space-3);
	border-bottom: 1px solid var(--color-border);
}

.sample-row__title {
	font-weight: 600;
}

.sample-row__title::after {
	content: ' ' counter(sample);
}

.sample-row__remove {
	color: var(--color-critical);
}

.sample-row__fields {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: var(--space-3) var(--space-4);
	align-items: start;
}

.sample-row__fields > .field + .field {
	margin-top: 0;
}
