/* Reset mínimo + estilos base (ver Project-Hydra-Negocio/tecnico/docs/archive/design/DESIGN_SYSTEM.md). */

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

/* Casillas, radios, progress y range heredan el azul del producto en vez del
   color por defecto del navegador. En tema oscuro --color-primary-500 vale
   #60a5fa (tokens.css), así que el acento sigue al tema solo. */
:root {
  accent-color: var(--color-primary-500);
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

/* La cabecera es fija (MainLayout): sin esto, el foco por Tab y las anclas dejan el elemento
   enfocado debajo de ella (WCAG 2.4.11). */
html {
  scroll-padding-top: calc(var(--navbar-height) + var(--space-4));
}

body {
  font: var(--font-body-md);
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--color-text);
  /* Reparte las líneas de un título largo en vez de dejar una palabra suelta. */
  text-wrap: balance;
}

p {
  margin: 0;
  /* Texto corrido: evita la palabra huérfana en la última línea. */
  text-wrap: pretty;
}

/* Celdas y etiquetas son texto corto y alineado: ahí el reparto no aporta. */
:where(table, label) p {
  text-wrap: wrap;
}

/* 02 § 3.2 asigna #235BC2 (--color-primary-500) a "accion primaria,
   enlaces, foco, estado activo". El -600 es el escalon de activo/pressed y
   06 § 2.1 lo marca ademas como no ratificado: no es color de enlace. */
a {
  color: var(--color-primary-500);
}

/*
  El glow en hover de enlaces se retiró (DDL-045, 07 § 5). Su función
  declarada era énfasis, pero aparecía en cada enlace de cada pantalla: un
  énfasis que se repite en todas partes se anula por repetición y pasa a ser
  decoración. Con él desaparecen las dos excepciones que existían solo para
  apagarlo (.nav-item, .buscador-item) y su regla de reduced-motion.
*/

button {
  font-family: inherit;
}

:focus-visible {
  outline: var(--border-focus);
  outline-offset: 2px;
}

/* Mismo anillo que CampoTexto/CampoSelect/CampoTextarea (outline + halo) para
   los campos que no pasan por esos componentes y se quedaban con el foco por
   defecto del navegador. Casillas, radios y range no llevan halo: son
   pequeños y conservan el outline global de arriba. */
:where(input, select, textarea):not([type="checkbox"], [type="radio"], [type="range"], [type="file"]):focus-visible {
  outline: var(--border-focus);
  outline-offset: -1px;
  box-shadow: 0 0 0 4px var(--color-primary-100);
}

/* Destinos de ancla. El desplazamiento suave va en el documento y
   en .contenido, que es el contenedor que de verdad desplaza en el shell. */
:target {
  scroll-margin-top: var(--space-6);
}

/* Entrada del contenido real que sustituye a un esqueleto (ficha 08): fundido corto con un asomo de desplazamiento. Se pone en el
   contenedor que aparece al terminar la carga; solo anima al insertarse, no en cada re-render. */
.contenido-entra {
  animation: contenido-entra var(--motion-transition) var(--ease-fluid) both;
}

@keyframes contenido-entra {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .contenido-entra {
    animation: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  html,
  .contenido {
    scroll-behavior: smooth;
  }
}

/* Barras de desplazamiento finas en los contenedores que desplazan: shell,
   barra lateral (el menú de dentro lo estiliza NavMenu.razor.css), overlays, listas y contenedores de tabla. Los estándares
   (scrollbar-width/color) mandan en Chromium 121+ y Firefox; el bloque
   ::-webkit-scrollbar solo cubre a Safari y a Chromium anterior, y por eso va
   tras @supports not: con los dos a la vez Chromium ignora el segundo. */
.contenido,
.barra-lateral,
.modal-cuerpo,
.drawer-cuerpo,
.menu-acciones-panel,
.ventana-contexto-panel,
.buscador-resultados,
.matriz-asignaciones-contenedor,
.claves-api-tabla-contenedor,
.lectura-ia-tabla-contenedor {
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}

@supports not (scrollbar-width: thin) {
  .contenido::-webkit-scrollbar,
  .barra-lateral::-webkit-scrollbar,
  .modal-cuerpo::-webkit-scrollbar,
  .drawer-cuerpo::-webkit-scrollbar,
  .menu-acciones-panel::-webkit-scrollbar,
  .ventana-contexto-panel::-webkit-scrollbar,
  .buscador-resultados::-webkit-scrollbar,
  .matriz-asignaciones-contenedor::-webkit-scrollbar,
  .claves-api-tabla-contenedor::-webkit-scrollbar,
  .lectura-ia-tabla-contenedor::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .contenido::-webkit-scrollbar-thumb,
  .barra-lateral::-webkit-scrollbar-thumb,
  .modal-cuerpo::-webkit-scrollbar-thumb,
  .drawer-cuerpo::-webkit-scrollbar-thumb,
  .menu-acciones-panel::-webkit-scrollbar-thumb,
  .ventana-contexto-panel::-webkit-scrollbar-thumb,
  .buscador-resultados::-webkit-scrollbar-thumb,
  .matriz-asignaciones-contenedor::-webkit-scrollbar-thumb,
  .claves-api-tabla-contenedor::-webkit-scrollbar-thumb,
  .lectura-ia-tabla-contenedor::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    border-radius: var(--radius-full);
  }
}

/* Fondo y letra como par con variante por tema (tokens.css): el fondo solo
   dejaba la letra heredada, ilegible en oscuro. */
::selection {
  background-color: var(--color-seleccion-fondo);
  color: var(--color-seleccion-texto);
}

.contenedor-pagina {
  padding: var(--space-8);
  max-width: 1400px;
}

.titulo-pagina {
  font: var(--font-heading-xl);
  margin-bottom: var(--space-6);
}

/*
  Texto explicativo atenuado que NO es la entradilla de la pantalla: el
  párrafo bajo un h2 de sección, el que abre una pestaña, o el que explica un
  estado concreto dentro del flujo. La entradilla de la pantalla —la que va
  justo bajo el h1— es <CabeceraPagina Descripcion=...>, y va un paso más
  grande (--font-body-lg) porque es la que sitúa la página entera.

  Global y no aislado a propósito: la deriva que sustituye venía justamente
  de copiar entre features clases declaradas en un .razor.css, donde el
  selector generado lleva el atributo de ámbito del componente de origen y no
  puede casar en el destino. Once párrafos se quedaron así sin estilo alguno.
*/
.texto-descriptivo {
  font: var(--font-body-md);
  color: var(--color-text-muted);
  max-width: 70ch;
  margin: 0 0 var(--space-4);
}

/*
  Envoltorio compartido de campo de formulario (etiqueta + control + mensaje
  de error) — CampoTexto, CampoSelect y CampoTextarea comparten el mismo
  marcado ".campo" > label + control, pero cada uno es su propio componente
  con su propio ámbito de aislamiento de CSS de Blazor: una regla ".campo"
  dentro de CampoTexto.razor.css (donde vivía antes) nunca llega al
  ".campo" que renderiza CampoSelect o CampoTextarea, aunque el HTML sea
  idéntico — mismo motivo que el resto de estilos verdaderamente
  compartidos de este archivo. Bug real encontrado en vivo (2026-08-16): la
  etiqueta y el control de un CampoSelect/CampoTextarea con Etiqueta no
  vacía se veían en línea en vez de apilados — invisible en las barras de
  filtro (Etiqueta="" ahí) pero no en un Drawer o Modal con etiqueta de
  verdad.
*/
.campo {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.campo label {
  font: var(--font-label-md);
  color: var(--color-text);
}

.campo-mensaje-error {
  font: var(--font-body-sm);
  color: var(--color-danger-700);
}

.detalle-tecnico {
  text-align: center;
  color: var(--color-text-muted);
  font: var(--font-body-sm);
  margin-top: var(--space-4);
}

/*
  Ripple de .boton-primario (ver wwwroot/js/microinteracciones.js), acotado
  a las acciones primarias por DDL-045 / 07 § 5. Va aquí, global
  y sin aislar, a propósito: el <span class="boton-ondulacion"> lo crea
  document.createElement en JS puro, y una regla dentro de Boton.razor.css
  quedaría reescrita por Blazor a ".boton-ondulacion[b-xxxxxxxx]" — un
  elemento creado fuera del árbol de Razor nunca tiene ese atributo de
  scope, así que nunca la alcanzaría (bug real: sin position:absolute el
  span queda en flujo normal con el ancho/alto que le pone el JS, inflando
  el botón en cada clic sin límite, y como la animación nunca llega a
  aplicarse tampoco, animationend nunca dispara y el span nunca se quita).
*/
.boton-ondulacion {
  position: absolute;
  border-radius: var(--radius-full);
  background-color: currentColor;
  opacity: 0.22;
  pointer-events: none;
  transform: scale(0);
  animation: expandir-ondulacion var(--motion-slow) var(--ease-standard) forwards;
}

@keyframes expandir-ondulacion {
  to {
    transform: scale(1);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .boton-ondulacion {
    display: none;
  }
}

/*
  Oculta visualmente el <input type="file"> nativo de ZonaSoltarArchivo.razor,
  accesible por foco/teclado/lectores de pantalla — el <label for> de la zona
  ya cubre "clic en cualquier parte abre el selector", así que el input no
  necesita ser el elemento clicado directamente. Va aquí, global y sin
  aislar: <InputFile> es un componente integrado de Blazor y no propaga el
  atributo de scope de CSS isolation a su <input> renderizado, así que una
  regla dentro de ZonaSoltarArchivo.razor.css nunca lo alcanzaría (bug real:
  el selector nativo "Elegir archivos / Ningún archivo seleccionado" quedaba
  visible debajo de la zona de arrastrar en todos los formularios de subida
  de documento — mismo motivo que el ripple de arriba).
*/
.zona-soltar-archivo-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/*
  Enlace "← Configuración" de las pantallas que se alcanzan desde el hub pero
  tienen ruta propia. Va aquí, global y sin aislar, porque lo usan varias
  páginas de features distintas (SeleccionarClienteLecturaIa, Plataforma,
  ConfiguracionIaCliente) y el aislamiento de CSS de Blazor lo dejaba definido
  solo dentro de la primera: las otras rendían el enlace sin estilo alguno,
  con el aspecto de un enlace por defecto del navegador. Mismo síntoma y misma
  causa que .campo más arriba.
*/
.enlace-volver-configuracion {
  font-size: 13px;
  line-height: 16px;
  font-weight: 600;
  color: var(--color-text-muted);
}

/*
  Tooltip propio (ficha 13): lo crea y coloca js/tooltip.js para los botones de
  solo icono con data-tooltip. Fondo y letra invertidos (--color-text sobre
  --color-surface): contraste alto en los dos temas. Por encima de Modal (1050),
  Drawer (1040) y toasts (1100), que es donde viven la mayoría de esos botones.
*/
.tooltip-propio {
  position: fixed;
  z-index: 1150;
  max-width: 280px;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-md);
  background-color: var(--color-text);
  color: var(--color-surface);
  font: var(--font-body-sm);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  /* Salida casi nula; la espera de entrada (400 ms) la pone el script. */
  transition: opacity var(--motion-fast) var(--ease-standard), visibility 0s linear var(--motion-fast);
}

.tooltip-propio.tooltip-propio-abajo {
  transform: translateY(-4px);
}

.tooltip-propio.tooltip-propio-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--motion-fast) var(--ease-standard), transform var(--motion-base) var(--ease-fluid);
}

/* Flecha: apunta al centro del botón aunque el tooltip se haya desplazado para no salirse. */
.tooltip-propio::after {
  content: "";
  position: absolute;
  left: var(--tooltip-flecha-x, 50%);
  top: 100%;
  margin-left: -5px;
  border: 5px solid transparent;
  border-top-color: var(--color-text);
}

.tooltip-propio.tooltip-propio-abajo::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: var(--color-text);
}

@media (prefers-reduced-motion: reduce) {
  .tooltip-propio,
  .tooltip-propio.tooltip-propio-visible {
    transition: none;
    transform: none;
  }
}

/*
  KeyTips (js/keytips.js): una letra sobre cada control declarado con data-keytip mientras
  el modo está encendido (Alt pulsada y soltada sola). La capa es aria-hidden y no recibe
  ratón; lo que se anuncia a un lector de pantalla es el cambio de modo, en .keytips-anuncio.
  Mismo esquema invertido que el tooltip propio (contraste alto en los dos temas) y por
  encima de él: mientras hay letras, mandan las letras.
*/
.keytips-capa {
  position: fixed;
  inset: 0;
  z-index: 1160;
  pointer-events: none;
}

.keytip {
  position: fixed;
  padding: 3px 5px;
  border-radius: var(--radius-sm);
  background-color: var(--color-text);
  color: var(--color-surface);
  box-shadow: 0 0 0 2px var(--color-surface);
  font: 700 11px/1 ui-monospace, Consolas, monospace;
}

.keytips-barra {
  position: fixed;
  top: var(--space-2);
  left: 50%;
  transform: translateX(-50%);
  padding: var(--space-1) var(--space-4);
  border-radius: 9999px;
  background-color: var(--color-text);
  color: var(--color-surface);
  font: var(--font-body-sm);
  white-space: nowrap;
}

.keytips-barra kbd {
  margin: 0 var(--space-1);
  padding: 0 var(--space-1);
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  font: 700 11px ui-monospace, Consolas, monospace;
}

.keytips-anuncio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* El envoltorio que da la letra N a la acción primaria no altera la fila de acciones. */
.cabecera-listado-primaria {
  display: contents;
}

/*
  Velo de cumplimiento: degradado suave del color del anillo de cumplimiento en la tarjeta de
  cabecera de una ficha 360 (decisión del 2026-10-09; .ident.deg-s de la maqueta «Páginas 360
  nuevas»). Se adopta con una línea: la clase velo-cumplimiento en el elemento que pinta el
  fondo de la tarjeta y que contiene el AnilloCumplimiento de tamaño Cabecera. El color sale
  solo del tono del anillo (verde, ámbar o rojo); sin anillo, o con el anillo sin universo,
  no hay regla que case y la tarjeta queda lisa.

  El velo es plano bajo el anillo (128 px: relleno, anillo de 84 y separación) y se funde con
  la superficie hacia el 62 % del ancho. El hueco del anillo es transparente y deja ver el
  mismo velo. Va como background-image para convivir con el background-color de la tarjeta:
  quien adopte la clase no debe fijar su fondo con el atajo background.
*/
.velo-cumplimiento:has(.anillo-cumplimiento-cabecera.anillo-cumplimiento-exito) {
  --velo-cumplimiento-color: var(--color-success-700);
}

.velo-cumplimiento:has(.anillo-cumplimiento-cabecera.anillo-cumplimiento-advertencia) {
  --velo-cumplimiento-color: var(--color-warning-700);
}

.velo-cumplimiento:has(.anillo-cumplimiento-cabecera.anillo-cumplimiento-peligro) {
  --velo-cumplimiento-color: var(--color-danger-700);
}

.velo-cumplimiento:has(.anillo-cumplimiento-cabecera:is(.anillo-cumplimiento-exito, .anillo-cumplimiento-advertencia, .anillo-cumplimiento-peligro)) {
  --velo-cumplimiento: color-mix(in srgb, var(--velo-cumplimiento-color) 9%, var(--color-surface));
  background-image: linear-gradient(90deg, var(--velo-cumplimiento) 0, var(--velo-cumplimiento) 128px, var(--color-surface) 62%);
}
