/* Consultor de Beneficios · Procabell
   Paleta dorada de la calculadora de comisiones sobre escala de grises.
   El dorado marca acción y foco; los estados son los únicos con color propio. */

/* Tipografías de Salvus, servidas desde el propio hosting. Son fuentes
   variables: un solo archivo cubre todos los pesos, así que pesan 87 KB entre
   las dos y se cachean en la primera visita. No se piden a Google en cada
   carga: la app no depende de un tercero ni le informa quién la usa. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fuentes/inter.woff2') format('woff2');
}

@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url('fuentes/nunito.woff2') format('woff2');
}

:root {
  --brand: #9A7420;
  --brand-text: #FFFFFF;
  --brand-strong: #7A5210;
  --brand-mark: #C4952A;
  --brand-light: #DDB96A;
  --brand-12: #FDF4E3;
  --brand-06: #FEFAF3;
  --mist: #F6F6F6;

  --page-bg: #FAFAFA;
  --card-bg: #FFFFFF;
  --card-border: #DDDDDD;
  --border-soft: #E2E2E2;
  --divider: #EEEEEE;

  --text: #1a1a1a;
  /* #999 sobre blanco da 2.8:1 de contraste, por debajo del mínimo legible.
     #6E6E6E llega a 5.2:1 sin dejar de leerse como texto secundario. */
  --text-muted: #6E6E6E;
  --text-slate: #4A4A4A;

  --table-head-bg: #F0F0F0;
  --table-head-color: #5F5F5F;
  --table-row-odd: #FAFAFA;

  --ok-bg: #EDF5EF;   --ok-fg: #2F6A47;   --ok-mark: #3D7A55;
  --warn-bg: #FBEEDF; --warn-fg: #A85A14; --warn-mark: #C2691B;
  --bad-bg: #FAEAEC;  --bad-fg: #972C36;  --bad-mark: #A8323C;
  --off-bg: #F1F1F1;  --off-fg: #7A7A7A;  --off-mark: #C0C0C0;

  --t-sesion-bg: #EDEDED;  --t-sesion-fg: #4A4A4A;
  --t-desc-bg: #F4F4F4;    --t-desc-fg: #6A6A6A;
  --t-unico-bg: #F8F8F8;   --t-unico-fg: #808080;

  --gray-300: #CCCCCC;
  --gray-200: #E2E2E2;
  --text-off: #AAAAAA;

  /* Barra de desplazamiento. La canaleta lleva el grafito de la barra superior,
     así que el pulgar se aclara al pasar el mouse en vez de oscurecerse: sobre
     ese fondo, oscurecerlo lo haría desaparecer. */
  --barra-pulgar: #6E6E6E;
  --barra-pulgar-fuerte: #9C9C9C;

  /* Riel de los controles segmentados (menú superior y de administración). */
  --rail-bg: #F3F3F3;
  --rail-line: #EAEAEA;
  --rail-hover: #FBFBFB;
  --rail-activo: #FFFFFF;
  --rail-sombra: 0 1px 2px rgba(0, 0, 0, .07), 0 0 0 1px rgba(154, 116, 32, .16);

  /* Campos de formulario. */
  --input-bg: #FFFFFF;
  --pill-bg: #FFFFFF;
  --input-line: #E6E6E6;
  --input-line-fuerte: #DCDCDC;
  --input-focus: #A8A8A8;
  --placeholder: #A8A8A8;
  --label: #5F5F5F;

  /* Bordes de los avisos flotantes, un paso más marcados que su fondo. */
  --ok-line: #CFE4D6;
  --warn-line: #EFD9B8;
  --bad-line: #EBCBCE;

  /* Nota de advertencia dentro de formularios y modales. */
  --nota-bg: linear-gradient(90deg, #FDF4E3, #FEFAF3);
  --nota-line: #EFDCB0;
  --nota-fg: #7A5C1A;

  --pill-sombra: 0 1px 3px rgba(0, 0, 0, .05), 0 10px 30px rgba(0, 0, 0, .09);
  --pill-sombra-alta: 0 1px 3px rgba(0, 0, 0, .06), 0 14px 40px rgba(0, 0, 0, .13);

  /* Uve de los desplegables, del mismo trazo que los iconos del menú. Va como
     máscara, así que el color lo pone quien la usa. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");

  /* Flecha del enlace de regreso, del mismo trazo que la uve. */
  --flecha-izq: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 5l-7 7 7 7'/%3E%3C/svg%3E");

  /* Visto de las casillas. Va en blanco fijo porque siempre cae sobre el
     dorado de marca. */
  --visto: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6.5L9.2 17.3 4 12.1'/%3E%3C/svg%3E");

  /* El mismo visto pero como máscara: toma el color de quien lo usa. */
  --visto-gris: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6.5L9.2 17.3 4 12.1'/%3E%3C/svg%3E");

  /* Barra superior oscura.
     El dorado de marca (#9A7420) sobre este grafito da 2.4:1 de contraste, muy
     por debajo de lo legible: para la barra se levanta a #D9AE4A, que llega a
     8.7:1 y sigue leyéndose como el mismo oro. Las superficies son blanco
     translúcido en vez de grises fijos, así la barra gana profundidad sin
     abrir una segunda escala de grises en el proyecto. */
  --bar-bg: #1C1D22;
  --bar-line: rgba(255, 255, 255, .09);
  --bar-text: #E7E7EC;
  --bar-text-dim: #8E8F99;
  --bar-surface: rgba(255, 255, 255, .055);
  --bar-hover: rgba(255, 255, 255, .075);
  --bar-gold: #D9AE4A;
  --bar-gold-soft: rgba(217, 174, 74, .13);
  --bar-gold-line: rgba(217, 174, 74, .30);
  /* Un escalón por encima de la barra: si fuera el mismo tono, el menú se
     leería como una prolongación de la barra en vez de una capa sobre ella. */
  --bar-menu-bg: #26272E;
  --bar-salir: #E9909A;

  --shadow-card: 0 2px 8px rgba(0,0,0,.05), 0 12px 40px rgba(0,0,0,.06);
  --shadow-modal: 0 16px 40px rgba(0,0,0,.18), 0 4px 12px rgba(0,0,0,.10);

  --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
  --font-display: 'Nunito', 'Inter', system-ui, sans-serif;
  --font-num: ui-monospace, 'Cascadia Mono', Consolas, Menlo, monospace;

  --r-card: 16px;
  --r-btn: 10px;
  --r-row: 8px;
  --r-head: 12px;
}

/* ─────────── Tema oscuro ───────────
   Solo redefine tokens; ninguna regla de componente cambia. Se enciende con
   la clase en <body> desde config.php, y apagarlo es quitar esa clase.

   El dorado de marca (#9A7420) sobre estos fondos queda en 4:1 y no alcanza
   para texto pequeño: en oscuro el acento es el mismo oro levantado que ya
   usaba la barra superior. Los fondos de estado (verde, ámbar, rojo) pasan de
   pasteles claros a tintes translúcidos del mismo tono, para que no aparezcan
   cinco manchas claras sobre un lienzo oscuro. */
body.oscuro {
  --brand: #D9AE4A;
  --brand-text: #1C1D22;
  --brand-strong: #E9C270;
  --brand-mark: #C4952A;
  --brand-light: #DDB96A;
  --brand-12: rgba(217, 174, 74, .14);
  --brand-06: rgba(217, 174, 74, .07);
  --mist: rgba(255, 255, 255, .06);

  /* Un punto más oscura que la barra superior: con el mismo tono, la barra
     dejaba de leerse como una capa aparte. */
  --page-bg: #131418;
  --card-bg: #1F2026;
  --card-border: #33343C;
  --border-soft: #2C2D34;
  --divider: #2A2B32;

  --text: #E9E9EE;
  --text-muted: #9A9BA5;
  --text-slate: #C3C4CC;
  --text-off: #6B6C75;
  --label: #8E8F99;

  --table-head-bg: #262731;
  --table-head-color: #9A9BA5;
  --table-row-odd: #22232A;

  --ok-bg: rgba(77, 160, 110, .15);   --ok-fg: #7FCB9C;   --ok-mark: #4DA06E;
  --warn-bg: rgba(200, 130, 40, .16); --warn-fg: #E3AC63; --warn-mark: #C88228;
  --bad-bg: rgba(190, 70, 85, .16);   --bad-fg: #E98E9A;  --bad-mark: #BE4655;
  --off-bg: rgba(255, 255, 255, .07); --off-fg: #8E8F99;  --off-mark: #5A5B64;

  --t-sesion-bg: rgba(255, 255, 255, .08);  --t-sesion-fg: #C3C4CC;
  --t-desc-bg: rgba(255, 255, 255, .055);   --t-desc-fg: #9A9BA5;
  --t-unico-bg: rgba(255, 255, 255, .04);   --t-unico-fg: #85868F;

  --gray-300: #4E4F58;
  --gray-200: #3A3B43;

  --barra-pulgar: #55565F;
  --barra-pulgar-fuerte: #74757F;

  --rail-bg: rgba(255, 255, 255, .05);
  --rail-line: #2E2F37;
  --rail-hover: rgba(255, 255, 255, .075);
  --rail-activo: rgba(217, 174, 74, .13);
  --rail-sombra: inset 0 0 0 1px rgba(217, 174, 74, .30);

  --input-bg: #1A1B20;
  /* La barra de búsqueda va al revés que los campos de formulario: los campos
     se hunden bajo la tarjeta, la barra flota sobre la página. */
  --pill-bg: #23242B;
  --input-line: #34353D;
  --input-line-fuerte: #45464F;
  --input-focus: #5E5F69;
  --placeholder: #86878F;

  --ok-line: rgba(77, 160, 110, .32);
  --warn-line: rgba(200, 130, 40, .34);
  --bad-line: rgba(190, 70, 85, .34);

  --nota-bg: rgba(200, 130, 40, .10);
  --nota-line: rgba(200, 130, 40, .28);
  --nota-fg: #E0B478;

  /* En oscuro una sombra negra sobre fondo negro no separa nada: la
     profundidad la da un filo claro en el canto superior, como el reflejo en
     el borde de una superficie, más una sombra ancha y muy abierta. */
  --shadow-card: inset 0 1px 0 rgba(255, 255, 255, .045), 0 2px 4px rgba(0, 0, 0, .45);
  --shadow-modal: inset 0 1px 0 rgba(255, 255, 255, .06), 0 26px 64px rgba(0, 0, 0, .65);
  --pill-sombra: inset 0 1px 0 rgba(255, 255, 255, .07), 0 18px 40px rgba(0, 0, 0, .55);
  --pill-sombra-alta: inset 0 1px 0 rgba(255, 255, 255, .10), 0 24px 56px rgba(0, 0, 0, .72);
}

/* El velo de los modales va más denso que en claro para que la tarjeta oscura
   de encima se despegue. */
body.oscuro .backdrop { background: rgba(0, 0, 0, .68); }

/* Los tokens de este bloque viven en `body`, así que la regla de `html` se
   queda con los del tema claro. Va dentro del mismo @supports que la de la
   raíz: en Chrome, declarar `scrollbar-color` acá desactivaría los
   pseudo-elementos de WebKit para la barra del documento. */
@supports not selector(::-webkit-scrollbar) {
  body.oscuro { scrollbar-color: var(--barra-pulgar) var(--bar-bg); }
}

/* Halo cálido detrás del contenido. Sin esto la pantalla del buscador es un
   rectángulo de un solo valor y la barra no se apoya en nada. El dorado va a
   siete centésimas: se percibe como aire, no como color. */
body.oscuro.dentro {
  background-image:
    radial-gradient(ellipse 1200px 620px at 50% 20%, rgba(217, 174, 74, .085), transparent 70%),
    radial-gradient(ellipse 1000px 800px at 50% 108%, rgba(255, 255, 255, .028), transparent 72%);
}

* { box-sizing: border-box; }

/* ─────────── Barras de desplazamiento ───────────

   Delgadas y sin canaleta en toda la app: la barra ancha del sistema le mete
   una franja gris al costado de cada tabla y de cada modal con desborde, y en
   una pantalla que ya es mayormente blanco compite con el contenido.

   El ancho lo fijan los pseudo-elementos de WebKit y no `scrollbar-width`,
   que solo ofrece "thin" —10px acá— y no baja de ahí. Con 5px el pulgar es
   más una referencia de posición que un agarre: se arrastra con la rueda o
   con el gesto del trackpad, no tomándolo con el puntero. Los dos no pueden
   convivir: desde Chrome 121, declarar `scrollbar-width` desactiva los
   pseudo-elementos. De ahí el @supports: donde el selector existe mandan los
   pseudo-elementos; donde no (Firefox), queda "thin", que es lo más angosto
   que ese motor sabe hacer.

   No hace falta prefijar cada contenedor: sin selector, estas reglas alcanzan
   a todo lo que desborde —tablas, modales, el desplegable de los selects. */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: var(--bar-bg); }
::-webkit-scrollbar-corner { background: var(--bar-bg); }

::-webkit-scrollbar-thumb {
  background: var(--barra-pulgar);
  border-radius: 999px;
}

::-webkit-scrollbar-thumb:hover { background: var(--barra-pulgar-fuerte); }

@supports not selector(::-webkit-scrollbar) {
  /* `scrollbar-color` se hereda y con ponerlo en la raíz alcanza a todo;
     `scrollbar-width` no se hereda, y sin el `*` las tablas y los modales con
     desborde se quedaban con la barra ancha del sistema. */
  * { scrollbar-width: thin; }
  html { scrollbar-color: var(--barra-pulgar) var(--bar-bg); }
}

body {
  margin: 0;
  min-height: 100vh;
  /* Trama de puntos sobre el degradado plateado. La trama se desvanece hacia
     abajo con una máscara, igual que en el fondo original de Procabell. */
  background: var(--page-bg);
  background-attachment: fixed;
  color: var(--text);
  position: relative;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Textura de halftone: puntos que crecen y se densifican hacia los bordes y
   se apagan en el centro, para que el contenido siempre caiga sobre limpio.
   Son dos capas fijas al viewport, detrás de todo y sin capturar clics:
   la fina llega más adentro, la gruesa se queda pegada al borde. Cada una
   necesita su propia máscara, y una máscara no puede aplicarse a una sola
   capa de `background`; de ahí los dos pseudo-elementos. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-repeat: repeat;
}

/* Puntos finos: entran hacia el centro pero mueren antes de llegar */
body::before {
  background-image: radial-gradient(circle, #EDEDED 1.25px, transparent 1.35px);
  background-size: 12px 12px;
  -webkit-mask-image: radial-gradient(ellipse 60% 52% at 50% 50%, transparent 46%, #000 96%);
  mask-image: radial-gradient(ellipse 60% 52% at 50% 50%, transparent 46%, #000 96%);
}

/* Puntos gruesos: el filo del halftone */
body::after {
  background-image: radial-gradient(circle, #E5E5E5 2.8px, transparent 2.9px);
  background-size: 12px 12px;
  background-position: 6px 6px;
  -webkit-mask-image: radial-gradient(ellipse 74% 64% at 50% 50%, transparent 66%, #000 100%);
  mask-image: radial-gradient(ellipse 74% 64% at 50% 50%, transparent 66%, #000 100%);
}

/* Los campos marcan el foco con su propio borde dorado, sin halo ni contorno.
   Enlaces y botones sí conservan el contorno: no tienen otra señal de foco. */
:where(a, button):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

:where(input, select, textarea):focus-visible { outline: none; }

/* Los títulos van en la tipografía de display, como en Salvus; el resto de la
   interfaz en Inter. */
.page-head h1,
.card-head h3,
.patient-head h2,
.pkg-bar h4,
.modal-head h3,
.login-card .titulo strong,
.preview .ph {
  font-family: var(--font-display);
}

/* ─────────── Barra superior ─────────── */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 18px;
  height: 62px;
  padding: 0 28px;
  /* Tono plano, sin degradado: el color viene dado y un degradado lo
     convertiría en dos tonos distintos.

     Encima va una trama de grano fino generada con feTurbulence y desaturada,
     en un SVG incrustado. Rompe la superficie lisa lo justo para que el
     grafito se lea mate en vez de impreso, y al ir en el CSS no agrega una
     petición más ni un archivo que mantener. La malla es de 160 px con los
     bordes cosidos, así que al repetirse no deja costura visible.

     Va en soft-light y no superpuesta sin más: el ruido promedia gris medio,
     así que encimado tal cual aclaraba la barra entera. En soft-light el gris
     medio no altera nada y solo trabajan las desviaciones, que es justo lo
     que se quiere: textura, no un tono distinto.

     La matriz de color hace dos cosas: pasa el ruido a gris promediando RGB y
     fuerza el alfa a 1. feTurbulence también agita el canal alfa, y con la
     trama medio transparente el promedio dejaba de ser gris medio y la barra
     se aclaraba igual. */
  background-color: var(--bar-bg);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0.33 0.33 0.33 0 0 0.33 0.33 0.33 0 0 0.33 0.33 0.33 0 0 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='0.45'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  background-blend-mode: soft-light;
  border-bottom: 1px solid var(--bar-line);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14);
}

.brand { display: flex; align-items: center; gap: 11px; text-decoration: none; }

/* El margen inferior sube la marca 2 px dentro del centrado de la fila.

   Centradas por su caja, la llama y la palabra quedaban exactas —y aun así se
   veían caídas, cosa que la línea divisoria delataba—. El ojo no centra por la
   caja sino por dónde está el peso: la llama es ancha abajo y fina arriba, y
   "PROCABELL" tiene la P grande con versalitas apoyadas en la línea base, así
   que en las dos el peso cae por debajo del centro de su caja. Medido a 3x
   sobre la barra (centro 91.5), su centro de masa estaba en 94.0 y 94.9,
   mientras la línea y "Beneficios Premium" pesaban en 91.6 y 91.9.

   Va en el margen y no en un transform para no crear una capa de composición
   encima de la trama de grano de la barra. */

/* Isotipo: es alto y angosto, así que se mide por alto y ocupa poco ancho. */
.brand .logo { height: 34px; width: auto; display: block; margin-bottom: 4px; }

/* La palabra "PROCABELL" al lado del isotipo. Va bastante más baja que él
   porque es solo caja de mayúsculas: igualadas por altura, la palabra se vería
   enorme al costado de una llama que tiene su propio aire arriba y abajo. */
.brand .logotipo { height: 15px; width: auto; display: block; opacity: .9; margin-bottom: 4px; }

.brand .bar { color: rgba(255, 255, 255, .22); font-size: 15px; font-weight: 300; }
.brand .app {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--bar-text);
  opacity: .8;
  letter-spacing: .01em;
  white-space: nowrap;
}

/* La edición acompaña al nombre: mismo color y misma familia, y solo el peso
   la separa. */
.brand .app .edicion { font-weight: 300; }

/* Control segmentado: el menú se lee como un conmutador de una aplicación,
   no como enlaces sueltos de una web. La pestaña activa es una pastilla
   blanca elevada sobre el riel gris. */
.topnav {
  display: flex;
  gap: 2px;
  padding: 4px;
  background: var(--bar-surface);
  border: 1px solid var(--bar-line);
  border-radius: 12px;
}

.topnav a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 8px;
  color: var(--bar-text-dim);
  text-decoration: none;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .01em;
  white-space: nowrap;
  transition: background .15s, color .15s;
}

.topnav svg { width: 15px; height: 15px; flex-shrink: 0; opacity: .7; }
.topnav a[aria-current] svg { opacity: 1; }

/* Navegación entre pantallas de administración: mismo lenguaje que la barra
   superior, un escalón más discreto. */
.subnav {
  display: inline-flex;
  gap: 2px;
  padding: 4px;
  background: var(--rail-bg);
  border: 1px solid var(--rail-line);
  border-radius: 12px;
  align-self: flex-start;
}

.subnav a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 8px;
  color: var(--text-slate);
  text-decoration: none;
  font-size: 12.5px;
  font-weight: 500;
  white-space: nowrap;
  transition: background .15s, color .15s;
}

.subnav a:hover { background: var(--rail-hover); color: var(--text); }

.subnav a[aria-current] {
  background: var(--rail-activo);
  color: var(--brand);
  font-weight: 600;
  box-shadow: var(--rail-sombra);
}

.subnav svg { width: 15px; height: 15px; flex-shrink: 0; opacity: .75; }
.subnav a[aria-current] svg { opacity: 1; }

.topnav a:hover { background: var(--bar-hover); color: var(--bar-text); }

/* La pestaña activa no se eleva con blanco como en el resto del proyecto: sobre
   grafito se marca con el oro, que es lo único que destaca sin ensuciar. */
.topnav a[aria-current] {
  background: var(--bar-gold-soft);
  color: var(--bar-gold);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--bar-gold-line);
}

.topbar .spacer { flex: 1; }

.who { position: relative; font-size: 12.5px; color: var(--bar-text-dim); }

.who .nombre { color: var(--bar-text); font-weight: 500; }

/* El rol va como etiqueta, no como texto corrido: se distingue del nombre de
   un vistazo y el dorado avisa cuándo la sesión puede autorizar y borrar. */
.who .rol {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bar-surface);
  border: 1px solid var(--bar-line);
  color: var(--bar-text-dim);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.who .rol.admin {
  background: var(--bar-gold-soft);
  border-color: var(--bar-gold-line);
  color: var(--bar-gold);
}

/* El nombre abre el menú de la cuenta. */
.who .yo {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 9px;
  border: 0;
  border-radius: var(--r-btn);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* Abierto y al pasar el ratón se ven igual: un escalón de luz, sin dorado. */
.who .yo:hover,
.who .yo[aria-expanded="true"] { background: var(--bar-hover); }

/* La misma uve de los desplegables, no el carácter ▾: así el gesto de "esto
   abre una lista" se dibuja igual en toda la aplicación. Como es una máscara,
   toma el color del texto de la barra. */
.who .flecha {
  width: 13px;
  height: 13px;
  flex: none;
  background-color: currentColor;
  opacity: .7;
  transition: transform .15s;
  -webkit-mask: var(--chevron) center / contain no-repeat;
  mask: var(--chevron) center / contain no-repeat;
}
.who .yo[aria-expanded="true"] .flecha { transform: rotate(180deg); }

.who .menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  min-width: 190px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  /* El menú cuelga de la barra, así que sigue siendo barra: si fuera claro
     parecería parte de la página que hay debajo. */
  background: var(--bar-menu-bg);
  border: 1px solid var(--bar-line);
  border-radius: var(--r-btn);
  box-shadow: 0 14px 34px rgba(0, 0, 0, .38);
  animation: menuEntra 140ms ease-out;
}

.who .menu[hidden] { display: none; }

.who .menu a {
  padding: 9px 11px;
  border-radius: var(--r-row);
  color: var(--bar-text-dim);
  font-size: 13px;
  text-decoration: none;
  white-space: nowrap;
}

.who .menu a:hover { background: var(--bar-hover); color: var(--bar-text); }
.who .menu a[aria-current] { background: var(--bar-gold-soft); color: var(--bar-gold); font-weight: 600; }
.who .menu a.salir { color: var(--bar-salir); }
.who .menu a.salir:hover { background: rgba(233, 144, 154, .12); color: var(--bar-salir); }
.who .menu .sep { height: 1px; margin: 5px 4px; background: var(--bar-line); }

@keyframes menuEntra {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.avatar {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(217, 174, 74, .15);
  box-shadow: inset 0 0 0 1px var(--bar-gold-line);
  color: var(--bar-gold);
  font-size: 11px;
  font-weight: 700;
}

/* ─────────── Estructura ─────────── */

main { max-width: 1160px; margin: 0 auto; padding: 26px 28px 64px; display: flex; flex-direction: column; gap: 18px; }

.page-head { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; }
.page-head h1 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.01em; }
.page-head p { margin: 2px 0 0; color: var(--text-muted); font-size: 13px; }

/* Miga de pan: la salida va antes del título, no debajo. */
.miga { margin: 0 0 10px; font-size: 13px; }

/* ─────────── Enlace de regreso ───────────

   Va en gris y recién al pasar el mouse toma el dorado: es la salida de la
   pantalla, no su acción principal, y compite todo el día con los botones que
   sí importan. La pastilla lo separa del fondo sin darle peso de botón, y la
   flecha —máscara, no texto— se corre un pelo hacia la izquierda al pasar por
   encima, que es a donde lleva el enlace. */
.volver {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px 6px 10px;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  transition: color .15s, background .15s, border-color .15s;
}

.volver::before {
  content: "";
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: var(--flecha-izq) center / contain no-repeat;
  mask: var(--flecha-izq) center / contain no-repeat;
  transition: transform .15s;
}

.volver:hover { color: var(--brand); background: var(--brand-06); border-color: var(--brand-mark); }
.volver:hover::before { transform: translateX(-2px); }
.volver:focus-visible { outline: 2px solid var(--brand-mark); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .volver::before { transition: none; }
  .volver:hover::before { transform: none; }
}

/* El estado acompaña al nombre del paquete en el mismo renglón: es parte de
   su identidad, no un dato más de la tarjeta. */
.page-head h1 .badge { margin-left: 10px; vertical-align: middle; }

/* ─────────── Zona de riesgo ───────────
   Lo que no se deshace vive aparte y al final, nunca en la misma fila que
   "Guardar cambios": ahí el error se comete por inercia de la mano. */
.zona-riesgo {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 22px;
  padding: 16px 20px;
  border-color: #EBCBCE;
  background: linear-gradient(90deg, var(--bad-bg), var(--card-bg) 70%);
  box-shadow: none;
}

.zona-riesgo .texto { flex: 1; min-width: 0; }

/* Dentro de un cuadro de diálogo no es una tarjeta suelta sino la última
   franja del cuadro: se separa con la misma línea que el resto de secciones y
   sigue el redondeo de la esquina inferior. */
.zona-riesgo.dentro-modal {
  margin-top: 0;
  padding: 14px 20px;
  border-top: 1px solid var(--divider);
  border-radius: 0 0 14px 14px;
}

/* Convenios de una empresa: casillas en columna, no un desplegable múltiple.
   Son pocos y se ven todos de una. */
.lista-convenios { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }

/* Aviso de cuota de RENIEC. Ámbar mientras avisa —todavía hay margen— y rojo
   cuando ya se acabó, que es cuando el mostrador empieza a teclear a mano. */
.aviso-cuota {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px 20px;
  border-color: var(--warn-line);
  background: linear-gradient(90deg, var(--warn-bg), var(--card-bg) 70%);
  box-shadow: none;
}

.aviso-cuota h3 { margin: 0; font-size: 13.5px; font-weight: 700; color: var(--warn-fg); }
.aviso-cuota p { margin: 3px 0 0; font-size: 12.5px; color: var(--text-muted); }
.aviso-cuota .texto { flex: 1; min-width: 0; }

.aviso-cuota.agotada { border-color: #EBCBCE; background: linear-gradient(90deg, var(--bad-bg), var(--card-bg) 70%); }
.aviso-cuota.agotada h3 { color: var(--bad-fg); }
.zona-riesgo h3 { margin: 0; font-size: 13.5px; font-weight: 700; color: var(--bad-fg); }
.zona-riesgo p { margin: 3px 0 0; font-size: 12.5px; color: var(--text-muted); }
.page-head .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.card {
  background: var(--card-bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
}

.card-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 15px 20px;
  border-bottom: 1px solid var(--divider);
}

.card-head h3 { margin: 0; font-size: 14.5px; font-weight: 700; }
.card-head .count { color: var(--text-muted); font-size: 12.5px; }
.card-head .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* ─────────── Estado del guardado automático ───────────
   Va en la cabecera de su tarjeta, en grises: informa sin llamar la atención.
   Solo el fallo se sale de la escala, porque ahí sí hay algo que hacer. */
.estado-guardado {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-muted);
  transition: color .2s;
}

/* Un punto mientras trabaja; un visto cuando terminó. Los dos del mismo gris:
   el estado informa, no celebra. */
.estado-guardado::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: .55;
}

.estado-guardado.guardado::before {
  width: 13px;
  height: 13px;
  border-radius: 0;
  opacity: 1;
  -webkit-mask: var(--visto-gris) center / contain no-repeat;
  mask: var(--visto-gris) center / contain no-repeat;
}

.estado-guardado:empty { display: none; }
.estado-guardado.pendiente { color: var(--gray-300); }
.estado-guardado.guardando { color: var(--text-muted); }
.estado-guardado.guardado { color: var(--text-slate); }
.estado-guardado.falla { color: var(--bad-fg); font-weight: 600; }

.card-body { padding: 20px; }

/* ─────────── Botones ─────────── */

.btn {
  display: inline-block;
  padding: 8px 15px;
  border: 1px solid transparent;
  border-radius: var(--r-btn);
  background: var(--brand);
  color: var(--brand-text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}

.btn:hover { background: var(--brand-strong); color: var(--brand-text); }
.btn.ghost { background: var(--card-bg); border-color: var(--card-border); color: var(--text-slate); font-weight: 500; }
.btn.ghost:hover { background: var(--mist); border-color: var(--brand-mark); color: var(--brand); }
.btn.danger { background: var(--card-bg); border-color: var(--card-border); color: var(--bad-fg); font-weight: 500; }
.btn.danger:hover { background: var(--bad-bg); border-color: var(--bad-mark); }
/* Botón en gris claro: acción principal de su tarjeta, pero sin gastar el
   dorado, que en esa pantalla ya lo lleva otra cosa. El borde lo separa del
   deshabilitado, que es del mismo tono pero plano y con el texto apagado. */
.btn.gris { background: var(--gray-200); color: var(--text-slate); border-color: var(--card-border); }
.btn.gris:hover { background: var(--gray-300); color: var(--text); }

/* Acción que todavía no empezó. El trazo discontinuo dice "esto está por
   arrancar" sin gastar un color: el gris sólido ya es el de registrar, y el
   dorado es de las acciones de pantalla. Al pasar el mouse el trazo se cierra
   y toma la marca, que es lo que va a pasar al pulsarlo. */
.btn.punteado {
  background: none;
  border: 1px dashed var(--gray-300);
  color: var(--text-slate);
}

.btn.punteado:hover {
  border-style: solid;
  border-color: var(--brand-mark);
  background: var(--brand-12);
  color: var(--brand);
}

.btn.sm { padding: 6px 11px; font-size: 12.5px; }
.btn[disabled], .btn.off { background: var(--divider); color: var(--text-off); border-color: transparent; cursor: not-allowed; pointer-events: none; }

.link { background: none; border: 0; padding: 0; color: var(--brand); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; text-decoration: none; }
.link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ─────────── Avisos flotantes ───────────
   Van fijos en la esquina inferior derecha para no empujar el contenido ni
   provocar una barra de desplazamiento. Se cierran solos a los 4 segundos;
   la barra inferior indica cuánto queda y se detiene al pasar el ratón. */

.avisos {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  pointer-events: none;
}

.aviso {
  pointer-events: auto;
  width: min(360px, calc(100vw - 40px));
  border: 1px solid;
  border-radius: var(--r-btn);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
  overflow: hidden;
  font-size: 13px;
  cursor: pointer;
  animation: avisoSube 200ms ease-out;
}

.aviso .txt { display: block; padding: 12px 15px; line-height: 1.4; }

/* Contador: se encoge de izquierda a derecha durante los 4 segundos. */
.aviso .barra {
  display: block;
  height: 3px;
  background: currentColor;
  opacity: .4;
  transform-origin: left center;
  animation: avisoCuenta 4s linear forwards;
}

.aviso:hover .barra { animation-play-state: paused; }
.aviso.saliendo { animation: avisoSale 200ms ease-in forwards; }

@keyframes avisoSube {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes avisoSale {
  to { opacity: 0; transform: translateX(14px); }
}

@keyframes avisoCuenta {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

.aviso.ok { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-fg); }
.aviso.aviso-warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-fg); }
.aviso.error { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad-fg); }

@media (max-width: 560px) {
  .avisos { right: 12px; left: 12px; bottom: 12px; align-items: stretch; }
  .aviso { width: auto; }
}

/* ─────────── Buscar ─────────── */

/* La caja de búsqueda no ocupa todo el ancho: se centra, porque es lo único
   que hay que mirar en esta pantalla. */
/* El centrado vertical vive en las dos variantes, no solo en la vacía: es lo
   que hace que al encoger la zona la barra suba sola, sin animar su posición
   por separado. Con la zona en su altura mínima el centrado no hace nada. */
.buscar-zona { display: flex; justify-content: center; align-items: center; }
.buscar-zona.sola { min-height: calc(100vh - 230px); }

/* ── Transición entre el buscador vacío y el buscador con resultados ──
   La aplicación recarga en cada búsqueda, así que no hay un estado que
   animar: lo que se anima es la entrada a cada pantalla, partiendo de la
   forma que tenía la anterior. El resultado se ve igual que una transición
   continua, y no necesita JavaScript.

   Lo que se anima es la barra, no la altura de la zona. Encoger la zona
   obligaba a reservar la pantalla completa mientras duraba el movimiento, y
   como la tarjeta de resultados ya estaba debajo, el documento arrancaba más
   alto que la ventana: aparecía una barra de desplazamiento que se iba sola a
   la mitad de la animación. Con una transformación la disposición es la final
   desde el primer cuadro, no hay recálculo por cuadro y no aparece nada.

   El desplazamiento es la distancia entre la barra centrada y la barra
   arriba. Sale de media zona, corregida por lo que baja la barra cuando el
   rótulo entra en el centrado: media altura del rótulo menos la mitad de lo
   que ocupa junto a su separación. Esa separación son 30 px —16 de margen más
   los 14 del gap del contenedor—, no 16: olvidar el gap dejaba la barra 8 px
   arriba de donde la pone la pantalla siguiente, y se veía como un salto al
   terminar la animación. */
@keyframes buscadorSube {
  from { transform: translateY(calc((100vh - 230px) / 2 - 3px)); }
  to   { transform: none; }
}

@keyframes buscadorBaja {
  from { transform: translateY(calc(-1 * ((100vh - 230px) / 2 - 11px))); }
  to   { transform: none; }
}

@keyframes rotuloSale {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes rotuloEntra {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes resultadosEntran {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* Estado sin animación: es lo que se ve al recargar o al volver con el botón
   atrás, y también con movimiento reducido. Cada pantalla se dibuja ya en su
   forma final. */
.buscar-zona:not(.sola) .titulo-buscador { display: none; }

/* La clase la pone el script del layout, y solo cuando se llegó navegando. */
.animar .buscar-zona.sola .buscador { animation: buscadorBaja 460ms cubic-bezier(.4, 0, .2, 1) both; }
.animar .buscar-zona.sola .titulo-buscador { animation: rotuloEntra 320ms 200ms both; }

.animar .buscar-zona:not(.sola) .buscador { animation: buscadorSube 460ms cubic-bezier(.4, 0, .2, 1) both; }

/* El rótulo se saca del flujo para apagarse: si colapsara su alto movería la
   barra por su cuenta y se sumaría al desplazamiento, que ya lo contempla. */
.animar .buscar-zona:not(.sola) .titulo-buscador {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  /* 30 px, no 16: en el flujo lo separan su margen de 16 más los 14 del gap
     del contenedor. Con 16 el rótulo animaba 14 px por debajo de su sitio y
     saltaba al terminar. */
  bottom: calc(100% + 30px);
  margin: 0;
  /* Fuera del flujo pierde el centrado que le daba el contenedor flexible. */
  text-align: center;
  animation: rotuloSale 300ms cubic-bezier(.4, 0, .2, 1) both;
}

/* Entra cuando la barra ya está llegando arriba, no antes: si aparecen a la
   vez se leen como dos cosas sueltas en vez de una secuencia. */
.animar .card.resultados { animation: resultadosEntran 380ms 280ms cubic-bezier(.4, 0, .2, 1) both; }

/* Búsqueda encadenada: se llegó a los resultados desde otros resultados, así
   que la barra ya está donde tiene que estar y moverla sería un viaje de ida y
   vuelta sin motivo. Solo cambia la tabla, y sin esperar a nada entra de
   inmediato. */
.animar.sin-barra .buscar-zona:not(.sola) .buscador { animation: none; }
.animar.sin-barra .buscar-zona:not(.sola) .titulo-buscador { display: none; animation: none; }
.animar.sin-barra .card.resultados { animation: resultadosEntran 300ms cubic-bezier(.4, 0, .2, 1) both; }

/* ── Salida hacia el buscador vacío ──
   Es la entrada al revés, y corre en la página que se va: la marca la pone el
   JS al interceptar el enlace. Va después de las reglas de entrada porque
   tienen la misma especificidad y debe ganar esta. */
@keyframes buscadorVuelve {
  from { transform: none; }
  to   { transform: translateY(calc((100vh - 230px) / 2 - 3px)); }
}

@keyframes resultadosSalen {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(10px); }
}

.saliendo .buscar-zona:not(.sola) .buscador { animation: buscadorVuelve 340ms cubic-bezier(.4, 0, .2, 1) both; }
.saliendo .card.resultados { animation: resultadosSalen 200ms cubic-bezier(.4, 0, .2, 1) both; }

/* Lo escrito no puede seguir en el campo hasta el final: al cargar la pantalla
   vacía desaparecería de golpe. Se apaga, el JS vacía el campo con la barra ya
   invisible, y vuelve a encenderse mostrando el marcador de posición. Así se
   llega al destino con el campo tal como va a quedar. */
@keyframes textoCambia {
  0%   { opacity: 1; }
  42%  { opacity: 0; }
  100% { opacity: 1; }
}

.saliendo .pill input { animation: textoCambia 280ms cubic-bezier(.4, 0, .2, 1) both; }

/* El rótulo vuelve a encenderse mientras la barra baja, para llegar a la
   pantalla vacía con él ya puesto. */
.saliendo .buscar-zona:not(.sola) .titulo-buscador {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  /* 30 px, no 16: en el flujo lo separan su margen de 16 más los 14 del gap
     del contenedor. Con 16 el rótulo animaba 14 px por debajo de su sitio y
     saltaba al terminar. */
  bottom: calc(100% + 30px);
  margin: 0;
  text-align: center;
  animation: rotuloEntra 260ms 60ms both;
}

/* Buscador suelto, sin marco. Para que no se pierda sobre el gris de la página
   no se le pone borde encima: se le da tamaño, una elevación permanente y el
   bloque dorado del botón, que es lo que ancla la vista. */
.buscador { position: relative; display: flex; flex-direction: column; align-items: center; gap: 14px; width: min(640px, 100%); }

/* Rótulo sobre la barra, a la manera de un buscador: grande y centrado cuando
   la pantalla no tiene nada más. En cuanto hay resultados desaparece — la
   tarjeta de abajo ya dice qué se buscó y el título sobraría. */
/* Etiqueta, no titular: nombra la pantalla y se aparta. Es el mismo gesto de
   las cabeceras de tabla del proyecto —versalitas muy espaciadas en gris—,
   así que no introduce un lenguaje nuevo para un solo rótulo. */
.titulo-buscador {
  margin: 0 0 16px;
  /* Nunito: es la familia redondeada que el proyecto ya carga. En versalitas
     pequeñas sus curvas se leen como suavidad, no como blandura, que era lo
     que fallaba cuando se probó de titular grande. */
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--text-muted);
}


.pill {
  display: flex;
  align-items: center;
  width: 100%;
  height: 58px;
  padding-left: 20px;
  background: var(--pill-bg);
  border: 1px solid var(--input-line);
  border-radius: 999px;
  overflow: hidden;
  box-shadow: var(--pill-sombra);
  transition: box-shadow .18s, border-color .18s;
}

.pill:hover,
.pill:focus-within { border-color: var(--input-line-fuerte); box-shadow: var(--pill-sombra-alta); }

/* La barra de búsqueda no se tiñe de rojo al fallar: el aviso y la sacudida ya
   señalan el error, y el borde rojo en un campo de este tamaño se lee como si
   algo estuviera roto. */

.pill .lupa { display: grid; place-items: center; color: var(--gray-300); }
.pill .lupa svg { width: 18px; height: 18px; display: block; }

/* Un solo campo para todo: el texto puede ser un documento o un apellido, así
   que va en la tipografía de interfaz y no en la de cifras. */
.pill input {
  flex: 1;
  min-width: 0;
  height: 100%;
  padding: 0 14px;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text);
  font-size: 16px;
  font-weight: 500;
}

.pill input::placeholder { color: var(--placeholder); font-weight: 400; }

/* El botón cierra la píldora por la derecha: es la masa oscura que impide que
   la barra desaparezca contra el fondo. Va en el grafito de la barra superior
   y no en dorado: el dorado ya está en el título, y repetirlo acá dejaba dos
   acentos peleando en una pantalla que solo tiene dos elementos. */
.pill .ir {
  flex: none;
  height: 100%;
  padding: 0 32px;
  border: 0;
  background: var(--bar-bg);
  color: #FFFFFF;
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .15s;
}

.pill .ir:hover { background: #2C2D35; }

.buscador .estado-error { margin: 0; color: var(--bad-fg); font-weight: 600; font-size: 12.5px; }

/* ─────────── Ficha del paciente ─────────── */

.patient-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; padding: 18px 20px; }

.pic {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--brand-12);
  color: var(--brand);
  font-size: 16px;
  font-weight: 700;
}

.patient-head h2 { margin: 0 0 5px; font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
/* Los botones se centran contra el bloque del nombre; el resto de la fila
   sigue arrancando arriba, que es donde tiene que quedar la inicial. */
.patient-head .actions { margin-left: auto; align-self: center; display: flex; gap: 8px; flex-wrap: wrap; }

.meta { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  background: var(--card-bg);
  font-size: 12px;
  color: var(--text-slate);
}

.chip .doc { font-family: var(--font-num); font-weight: 600; color: var(--text); }

.pkg-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 20px;
  background: var(--mist);
  border-bottom: 1px solid var(--divider);
  border-radius: var(--r-card) var(--r-card) 0 0;
}

.pkg-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brand-mark); flex-shrink: 0; }
.pkg-bar h4 { margin: 0; font-size: 14.5px; font-weight: 700; }
.pkg-bar .sold { font-size: 12.5px; color: var(--text-muted); }
.pkg-bar .sold b { color: var(--text-slate); font-weight: 600; font-family: var(--font-num); }

.rows { padding: 8px; display: flex; flex-direction: column; }

/* Anchos fijos y no "auto" en las columnas de datos: cada fila es una grilla
   propia, así que con auto cada una mediría distinto y las columnas saldrían
   escalonadas. Fijos, se leen como una tabla.

   La del botón también va fija, y esa es la que importa: siendo "auto" se
   encogía con su texto —"Activar" mide la mitad que "Registrar consumo"— y el
   sobrante se lo llevaba la columna del nombre, que es 1fr. Resultado: en esas
   filas todo lo del medio se corría a la derecha. */
.row {
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr) 96px 96px 92px 82px 112px 152px;
  align-items: center;
  gap: 16px;
  border-radius: var(--r-row);
  overflow: hidden;
}

.rows.aliado .row { grid-template-columns: 3px minmax(0, 1fr) 96px 92px 82px 112px 164px; }

.row:nth-child(even) { background: var(--table-row-odd); }
.row:hover { background: var(--brand-06); }

.row .stripe { align-self: stretch; background: var(--off-mark); }
.row[data-state="disponible"] .stripe { background: var(--ok-mark); }
.row[data-state="por_vencer"] .stripe { background: var(--warn-mark); }
.row[data-state="vencido"] .stripe { background: var(--bad-mark); }

.row .info { padding: 13px 0 13px 7px; min-width: 0; }
.row .name { font-size: 13.5px; font-weight: 600; margin-bottom: 2px; }
.row .sub { font-size: 12px; color: var(--text-muted); display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.row .sub .sep { color: var(--gray-300); }
.row[data-state="agotado"] .name, .row[data-state="vencido"] .name { font-weight: 500; color: var(--text-slate); }
/* Todos los botones de fila miden lo mismo: la columna de acciones se lee como
   una pila y no como un borde dentado, y ninguno pesa más por ser más largo. */
.row .cta { padding-right: 12px; justify-self: stretch; }
.row .cta > * { display: block; width: 100%; text-align: center; }

.balance, .row .celda { text-align: right; font-family: var(--font-num); font-variant-numeric: tabular-nums; line-height: 1.15; }
.balance .lbl, .row .celda .lbl { display: block; font-family: var(--font-sans); font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px; }

/* Caducidad y vencimiento: mismo bloque etiqueta-dato que el saldo, pero sin
   su peso —el número que manda en la fila sigue siendo el que queda. */
.row .celda .val { font-size: 13px; font-weight: 600; color: var(--text-slate); white-space: nowrap; }

/* El tipo tiene columna propia y va a la izquierda, no alineado a la derecha
   como las cifras: es una etiqueta, no un número que se compare hacia abajo. */
.row .celda.tipo-col { text-align: left; }
.row .celda .val.muted { font-weight: 500; color: var(--text-muted); }
.row[data-state="vencido"] .celda:last-of-type .val { color: var(--bad-fg); }
.balance .n { font-size: 18px; font-weight: 700; }
.balance .of { color: var(--text-muted); font-size: 12.5px; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  background: var(--off-bg);
  color: var(--off-fg);
}

.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge.ok { background: var(--ok-bg); color: var(--ok-fg); }
.badge.warn { background: var(--warn-bg); color: var(--warn-fg); }
.badge.bad { background: var(--bad-bg); color: var(--bad-fg); }
.badge.brand { background: var(--brand-12); color: var(--brand); }

/* Empresa a la que pertenece una persona. Va más chica que los demás badges
   —es un dato de contexto, no un estado— y con el punto en hueco, para que no
   se confunda con los llenos que sí marcan estado. */
.badge.empresa {
  padding: 2px 9px;
  font-size: 10.5px;
  background: var(--mist);
  border: 1px solid var(--border-soft);
  color: var(--text-slate);
}

.badge.empresa::before {
  width: 5px;
  height: 5px;
  background: none;
  box-shadow: inset 0 0 0 1.5px currentColor;
}

/* La casa propia va en dorado: separa de un vistazo al equipo de los aliados. */
.badge.empresa.propia { background: var(--brand-06); border-color: var(--brand-light); color: var(--brand); }

.bajo-nombre { margin-top: 5px; }

/* Beneficio del convenio en la lista de derivados: el estado manda, el nombre
   acompaña. Van varios por celda cuando el convenio trae más de uno. */
.linea-benef { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
.linea-benef + .linea-benef { margin-top: 6px; }
.linea-benef .que { color: var(--text-slate); }

.tipo {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .03em;
  white-space: nowrap;
  background: var(--t-sesion-bg);
  color: var(--t-sesion-fg);
}

.tipo::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.tipo.descuento { background: var(--t-desc-bg); color: var(--t-desc-fg); box-shadow: inset 0 0 0 1px var(--gray-200); }
.tipo.unico { background: var(--t-unico-bg); color: var(--t-unico-fg); box-shadow: inset 0 0 0 1px var(--gray-200); }

.vacio { padding: 40px 20px; text-align: center; color: var(--text-muted); font-size: 13.5px; }

/* Un estado vacío puede ofrecer la salida en vez de solo describir el vacío.
   El botón va debajo del texto, centrado y con aire propio. */
.vacio p { margin: 0; }
.vacio .btn { display: inline-block; margin-top: 20px; }

/* ─────────── Tarjetas de resumen ─────────── */

.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }

.stat {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 15px 17px;
  background: var(--card-bg);
  border: 1px solid var(--border-soft);
  border-left: 4px solid var(--gray-300);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
}

.stat.lead { border-left-color: var(--brand-mark); }
.stat .fig { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-size: 26px; font-weight: 700; line-height: 1; color: var(--text-slate); }
.stat.lead .fig { color: var(--brand); }
.stat .txt { font-size: 12.5px; color: var(--text-muted); line-height: 1.35; }
.stat .txt b { display: block; color: var(--text); font-size: 13px; font-weight: 600; }

/* ─────────── Formularios ─────────── */

.form-grid { padding: 20px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field.wide { grid-column: 1 / -1; }
.field.tercio { grid-column: span 1; }

/* Casilla que acompaña al campo de al lado, sin rótulo propio.
   Antes se calzaba con una etiqueta vacía de «&nbsp;», que dejaba la casilla
   pegada al borde superior del campo vecino. Ahora se ancla abajo y ocupa
   exactamente el alto de un campo, así su centro coincide con el del campo que
   tiene a la izquierda. */
/* Se alinea desde arriba y no desde abajo: si el campo vecino lleva una nota
   debajo, su celda crece hacia abajo y anclar al pie dejaba la casilla suelta,
   muy por debajo del campo. El rótulo invisible reserva la altura del rótulo
   real, y la casilla cae justo a la altura del campo. */
.field.a-la-par { justify-content: flex-start; }
.field.a-la-par::before { content: "\00a0"; }

/* 42 px es el alto de un campo con el relleno y el tipo actuales (medido:
   42,3). Intenté armarlo con el mismo relleno y borde para que saliera solo,
   pero la caja de la casilla crece distinto a la de un input y quedaba 1,7 px
   más alta. Un valor fijo acierta mejor. */
.field.a-la-par .check { min-height: 42px; align-items: center; }

/* El pseudoelemento hace de rótulo invisible en las casillas que acompañan a
   otro campo: comparte la regla para que su alto siga siendo el de un rótulo
   aunque mañana cambie el tipo o el tamaño. */
.field label,
.field.a-la-par::before { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--label); }

.field input, .field select, .field textarea {
  padding: 10px 12px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-btn);
  background: var(--input-bg);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}

.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--input-focus);
}

.field input::placeholder { color: var(--placeholder); }

/* Un desplegable no se escribe, se elige: la mano lo dice antes de pulsarlo. */
.field select { cursor: pointer; }

/* ─────────── Lista desplegable de los select ───────────
   La lista que abre un <select> la dibuja el sistema operativo, y por eso
   aparecía con el azul de Windows en medio de una pantalla dorada. Desde
   Chrome 135 se puede reemplazar por una lista de verdad, estilable con CSS.

   Va dentro de @supports a propósito: donde no exista, no se aplica nada y el
   navegador sigue dibujando la suya. No hay JavaScript de por medio, así que
   el campo sigue siendo un <select> nativo —teclado, validación y envío del
   formulario funcionan igual. */
@supports (appearance: base-select) {
  select,
  select::picker(select) { appearance: base-select; }

  select {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
  }

  /* El triángulo relleno del navegador no pega con el resto: todos los iconos
     de la aplicación son trazos abiertos de punta redonda. Se reemplaza por
     una uve dibujada igual, y como va de máscara toma el color por CSS y no
     hay que mantener dos versiones para el tema claro y el oscuro. */
  select::picker-icon {
    content: "";
    width: 13px;
    height: 13px;
    flex: none;
    background-color: var(--text-muted);
    transition: transform .15s;
    -webkit-mask: var(--chevron) center / contain no-repeat;
    mask: var(--chevron) center / contain no-repeat;
  }

  select:hover::picker-icon { background-color: var(--text-slate); }

  select:open::picker-icon { transform: rotate(180deg); }

  /* La lista repite al menú de la cuenta: tarjeta blanca, esquinas del
     sistema, sombra de capa flotante. */
  select::picker(select) {
    padding: 6px;
    margin-top: 6px;
    border: 1px solid var(--border-soft);
    border-radius: var(--r-btn);
    background: var(--card-bg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
    max-height: 320px;
  }

  select:open::picker(select) { animation: menuEntra 140ms ease-out; }

  option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 11px;
    border-radius: var(--r-row);
    background: transparent;
    color: var(--text-slate);
    font-size: 13.5px;
  }

  option:hover,
  option:focus { background: var(--mist); color: var(--text); outline: none; }

  /* La opción elegida, en dorado como la pantalla activa del menú. */
  option:checked { background: var(--brand-12); color: var(--brand); font-weight: 600; }

  /* El visto que agrega el navegador sobra: el fondo dorado ya lo dice. */
  option::checkmark { display: none; }
}
.field input.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-weight: 600; }

/* Identidad del paciente: mismo peso que el documento, porque son el mismo
   dato leído de dos maneras. El marcador de posición no lo hereda, para que
   siga distinguiéndose de un valor escrito. */
.field input.fuerte { font-weight: 600; }
.field input.fuerte::placeholder { font-weight: 400; }

/* Cifras que no son identidad —una fecha, un importe— conservan la tipografía
   de datos pero no el peso: no compiten con el nombre ni con el documento. */
.field input.liviana { font-weight: 400; }
.field .hint { font-size: 11.5px; color: var(--text-muted); }

/* Resultado de la consulta a RENIEC. Nunca en el rojo de validación: no es un
   error del asesor y no impide guardar, así que se queda en el registro de
   los avisos suaves. */
.field .hint.buscando { color: var(--text-muted); }
.field .hint.bueno-suave { color: var(--ok-fg); font-weight: 600; }
.field .hint.malo-suave { color: var(--warn-fg); font-weight: 600; }

/* Sello dentro del campo: dice que ese dato lo trajo RENIEC y no una persona.
   Va pegado al dato en vez de en una línea aparte, y el campo le reserva
   espacio a la derecha para que el número no se le meta debajo. */
.field .con-marca { position: relative; display: flex; }
.field .con-marca input { flex: 1; min-width: 0; padding-right: 96px; }

.marca-reniec {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--ok-bg);
  color: var(--ok-fg);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  white-space: nowrap;
  pointer-events: auto;
  cursor: default;
}

.marca-reniec[hidden] { display: none; }
.marca-reniec svg { width: 12px; height: 12px; stroke-width: 2.6; }

/* Mientras consulta: mismo sitio, tono neutro y sin el visto, que todavía no
   corresponde. */
.marca-reniec.buscando { background: var(--off-bg); color: var(--off-fg); }
.marca-reniec.buscando svg { display: none; }

/* Paciente que ya estaba en la base: es un hecho del sistema, no algo que
   confirmó un registro externo, así que va en gris y no en verde. */
.marca-reniec.registrado { background: var(--t-sesion-bg); color: var(--t-sesion-fg); }

/* ─────────── Calendario de la fecha de venta ───────────
   El calendario nativo del navegador no se puede estilar, así que se dibuja
   uno con el mismo lenguaje que la lista de los desplegables. El campo sigue
   siendo de texto: quien teclea rápido no pierde el atajo. */
.field .con-marca .abre-calendario {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background .15s, color .15s;
}

.field .con-marca .abre-calendario:hover { background: var(--mist); color: var(--text-slate); }
.field .con-marca .abre-calendario svg { width: 16px; height: 16px; }

/* Todo el campo abre el calendario, así que se anuncia como algo que se
   pulsa. Sigue siendo escribible: el cursor de texto aparece al enfocarlo. */
.field .con-marca input[data-calendario] { padding-right: 44px; cursor: pointer; }
.field .con-marca input[data-calendario]:focus { cursor: text; }

.calendario {
  position: absolute;
  z-index: 140;
  /* Siete columnas de 36 px más las separaciones y el relleno: si se queda
     corto, la última columna del mes se recorta contra el borde. */
  width: 300px;
  padding: 10px;
  background: var(--card-bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-btn);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
  animation: menuEntra 140ms ease-out;
}

.calendario .cab { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }

.calendario .cab .mes {
  flex: 1;
  text-align: center;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  text-transform: capitalize;
}

.calendario .cab button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  font-size: 15px;
  cursor: pointer;
}

.calendario .cab button:hover { background: var(--mist); color: var(--text); }

/* minmax(0, 1fr) y no 1fr a secas: en una cuadrícula, 1fr no baja del ancho
   mínimo del contenido, así que las siete columnas se desbordaban hacia la
   derecha y el último día quedaba pegado al borde. */
.calendario .semana,
.calendario .dias { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; }

/* Altura fija de fila: si la deja libre, la fila con celdas vacías se estira y
   el primer renglón del mes queda separado del resto. */
.calendario .dias { grid-auto-rows: 32px; }

.calendario .semana span {
  padding: 4px 0;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--text-muted);
}

.calendario .dias button {
  height: 32px;
  border: 0;
  border-radius: var(--r-row);
  background: transparent;
  color: var(--text-slate);
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  cursor: pointer;
  transition: background .12s, color .12s;
}

.calendario .dias button:hover:not(:disabled) { background: var(--mist); color: var(--text); }
.calendario .dias button:disabled { color: var(--gray-300); cursor: not-allowed; }
.calendario .dias .vacio { visibility: hidden; }

/* Hoy se señala con un punto; el día elegido, en dorado como la opción activa
   de un desplegable. */
.calendario .dias button.hoy { box-shadow: inset 0 0 0 1px var(--gray-200); }
.calendario .dias button.elegido { background: var(--brand-12); color: var(--brand); font-weight: 700; }

.calendario .pie {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--divider);
  text-align: center;
}

.calendario .pie button {
  border: 0;
  background: transparent;
  color: var(--brand);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.calendario .pie button:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Mensaje de validación. Lo pinta el servidor al recargar y también el JS
   antes de enviar, con la misma marca visual en ambos casos. */
.malo {
  display: block;
  margin-top: 5px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--bad-fg);
}

.field .malo { margin-top: 0; }

.malo-borde,
.field input.malo-borde,
.field select.malo-borde,
.field textarea.malo-borde { border-color: var(--bad-mark); }

/* Aviso flotante de validación: cuelga de <body> anclado al campo, para que
   no lo recorte el modal ni la tarjeta. Reemplaza al globo del navegador. */
.aviso-flotante {
  position: absolute;
  z-index: 120;
  max-width: 270px;
  padding: 8px 12px;
  border: 1px solid var(--bad-mark);
  border-radius: var(--r-btn);
  background: var(--card-bg);
  color: var(--bad-fg);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
  animation: avisoEntra 140ms ease-out;
}

/* Pico que apunta al campo */
.aviso-flotante::before {
  content: "";
  position: absolute;
  top: -5px;
  left: 16px;
  width: 8px;
  height: 8px;
  background: var(--card-bg);
  border-left: 1px solid var(--bad-mark);
  border-top: 1px solid var(--bad-mark);
  transform: rotate(45deg);
}

/* Misma forma, otro tono: esto no es un error sino una instrucción de uso, así
   que va en el gris de los textos de apoyo y no en el rojo de la validación. */
.aviso-flotante.pista {
  border-color: var(--card-border);
  color: var(--text-slate);
  font-weight: 500;
}

.aviso-flotante.pista::before {
  border-left-color: var(--card-border);
  border-top-color: var(--card-border);
}

@keyframes avisoEntra {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

/* Sacudida del campo incompleto */
@keyframes sacudir {
  0%, 100% { transform: translateX(0); }
  18%      { transform: translateX(-5px); }
  38%      { transform: translateX(5px); }
  58%      { transform: translateX(-3px); }
  78%      { transform: translateX(3px); }
}

.sacudir { animation: sacudir 380ms ease-in-out; }

/* La trama vive solo en el ingreso. Dentro de la aplicación el fondo queda
   liso: ahí compite con tablas, fichas y formularios, y lo que debe destacar
   es el dato del paciente, no la textura. */
body.dentro::before,
body.dentro::after { display: none; }

/* ─────────── Casilla ───────────
   La nativa dibuja el sistema operativo: un cuadro azul con un visto que no
   se parece a nada más de la pantalla. Se apaga y se dibuja una con el mismo
   lenguaje que los botones —esquinas del sistema, dorado de marca— sin perder
   el input real, que es lo que envía el formulario y responde al teclado. */
/* Doble selector a propósito: dentro de un formulario, `.field label` impone
   versalitas espaciadas, y una casilla no es un rótulo de campo sino una frase
   que se lee. */
.check,
.field label.check {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}

.check input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid var(--card-border);
  /* Cuadrado con las esquinas apenas matadas: más radio y empieza a leerse
     como pastilla, que es otro control. */
  border-radius: 4px;
  background: var(--input-bg);
  cursor: pointer;
  transition: background .15s, border-color .15s;
}

.check input:checked {
  background: var(--brand) var(--visto) center / 12px no-repeat;
  border-color: var(--brand);
}

.check input:focus-visible { outline: 2px solid var(--brand-mark); outline-offset: 2px; }
.check:hover input:not(:checked) { border-color: var(--gray-300); }

/* La aclaración sigue en la misma línea: es una frase sola, y partirla en dos
   renglones la hacía pesar más de lo que dice. La abre un icono de
   información en vez de un guion, que dice de qué tipo de texto se trata. */
/* Texto corrido, no contenedor flexible: un `inline-flex` crea su propia línea
   base y se desalinea del texto que tiene al lado. Así comparten renglón y el
   único que hay que ajustar es el icono. */
.check small,
.field label.check small {
  margin-left: 3px;
  font-size: 12.5px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}

.check small svg,
.field label.check small svg {
  width: 13px;
  height: 13px;
  margin-right: 4px;
  stroke-width: 1.8;
  opacity: .65;
  /* Respecto de la línea base del texto, no del centro de su caja. */
  vertical-align: -2.5px;
}

.form-foot { display: flex; justify-content: flex-end; gap: 9px; padding: 14px 20px; border-top: 1px solid var(--divider); }

.preview { margin: 0 20px 20px; border: 1px solid var(--border-soft); border-radius: var(--r-card); overflow: hidden; }
.preview .ph { padding: 10px 15px; background: var(--mist); border-bottom: 1px solid var(--divider); font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }

/* ─────────── Tablas ─────────── */

/* La franja de encabezados es una placa con las esquinas superiores
   redondeadas, o sea que está pensada para flotar dentro de la tarjeta. Sin
   aire arriba se pegaba a la línea del título y las esquinas no se veían: el
   redondeo quedaba comido contra el filete. */
.table-wrap { padding: 14px 16px 16px; overflow-x: auto; }

table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13.5px; }

th {
  text-align: left;
  padding: 12px 16px;
  background: var(--table-head-bg);
  color: var(--table-head-color);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}

th:first-child { border-top-left-radius: var(--r-head); }
th:last-child { border-top-right-radius: var(--r-head); }

td { padding: 12px 16px; border-bottom: 1px solid var(--divider); vertical-align: middle; }

tbody tr:nth-child(even) { background: var(--table-row-odd); }
tbody tr:hover { background: var(--brand-06); }
tbody tr td:first-child { border-top-left-radius: var(--r-row); border-bottom-left-radius: var(--r-row); }
tbody tr td:last-child { border-top-right-radius: var(--r-row); border-bottom-right-radius: var(--r-row); }
tbody tr:last-child td { border-bottom: 0; }

/* ─────────── Orden por arrastre ─────────── */

th.asa, td.asa { width: 34px; padding-left: 12px; padding-right: 0; }

.asa-mover {
  display: block;
  width: 22px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--gray-300);
  cursor: grab;
}

.asa-mover:hover { color: var(--text-muted); background: var(--mist); }
.asa-mover:active { cursor: grabbing; }
.asa-mover:focus-visible { outline: 2px solid var(--brand-mark); outline-offset: 1px; color: var(--brand); }

/* Los seis puntos del asa, dibujados con dos columnas de degradado radial: es
   el mismo trazo que un icono y no agrega otro archivo que mantener. */
.asa-mover span {
  display: block;
  width: 100%;
  height: 100%;
  background-image:
    radial-gradient(currentColor 1.4px, transparent 1.5px),
    radial-gradient(currentColor 1.4px, transparent 1.5px);
  background-size: 50% 33.33%;
  background-position: 2px center, 12px center;
  background-repeat: repeat-y;
}

/* La fila en viaje se atenúa para que se lea el hueco donde va a caer. */
tr.arrastrando { opacity: .4; }
tr.arrastrando td { background: var(--brand-06); }

.pie-tabla {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 20px 16px;
  color: var(--text-muted);
  font-size: 12px;
}

/* Visible para los lectores de pantalla, no para el ojo. */
.oculto-visual {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Columnas de cifras: angostas y alineadas a la derecha, para que los números
   se comparen de un vistazo en vez de quedar sueltos en medio de la celda. */
th.cifra, td.cifra { width: 120px; text-align: right; }
th.estado, td.estado { width: 130px; }
/* El rótulo encabeza la columna desde la izquierda; los botones siguen a la
   derecha, alineados con el borde de la tabla. */
th.acc { width: 220px; text-align: left; }
td.acc { width: 220px; text-align: right; white-space: nowrap; }

/* Un formulario dentro de una celda no debe romper la fila: solo envuelve a su
   botón. */
.en-linea { display: inline; }

/* Anchos por tipo de dato. Las columnas sin clase —nombre, detalle— no llevan
   ancho: se reparten lo que sobra, que es donde el texto largo hace falta. */
th.quien, td.quien { width: 165px; }

/* Resultados de búsqueda: el documento cuelga del nombre en vez de ocupar
   columna propia, porque nunca se lee sin él. */
td.name .doc { margin-top: 3px; font-weight: 400; font-size: 12px; color: var(--text-muted); }

td.paquete .linea { display: flex; align-items: center; gap: 7px; font-weight: 600; color: var(--text-slate); }

td.paquete .mas {
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--off-bg);
  color: var(--off-fg);
  font-family: var(--font-num);
  font-size: 11px;
  font-weight: 700;
}

th.benef, td.benef { width: 130px; }

/* Pastilla con el saldo de beneficios: "3 / 5". Al apuntarla se despliega el
   detalle, así que se anuncia como interactiva. */
.chip-benef {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--off-bg);
  color: var(--off-fg);
  font-family: var(--font-num);
  font-size: 12px;
  font-weight: 600;
  cursor: default;
  transition: background .15s, color .15s;
}

.chip-benef b { font-weight: 700; }
.chip-benef.con-saldo { background: var(--ok-bg); color: var(--ok-fg); }
.chip-benef:hover, .chip-benef:focus-visible { background: var(--brand-12); color: var(--brand); outline: none; }

/* Detalle flotante. Cuelga de <body> y no de la celda: dentro de .table-wrap
   lo recortaría el contenedor con desplazamiento. */
.lista-benef {
  position: absolute;
  z-index: 130;
  min-width: 290px;
  max-width: 360px;
  padding: 10px 8px;
  background: var(--card-bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-btn);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
  animation: avisoEntra 130ms ease-out;
}

.lista-benef .grupo {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 10px 0 6px;
  padding: 0 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* La fecha de venta desempata cuando el mismo paquete se vendió dos veces. */
.lista-benef .grupo span {
  margin-left: auto;
  font-family: var(--font-num);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--gray-300);
}

.lista-benef .grupo:first-child { margin-top: 0; }

.lista-benef .fila {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px;
  border-radius: 7px;
  font-size: 12.5px;
  box-shadow: inset 0 1px 0 var(--divider);
}

.lista-benef .grupo + .fila { box-shadow: none; }
.lista-benef .fila:hover { background: var(--mist); box-shadow: none; }

/* El nombre cede: si es largo se recorta antes que empujar la cifra. */
.lista-benef .fila .que {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-slate);
}

/* Ancho fijo para que las cifras formen columna y ninguna quede debajo del
   nombre de al lado. */
.lista-benef .fila .cuanto {
  width: 52px;
  flex: none;
  text-align: right;
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}

/* Verde si queda algo por usar; gris si no, y ahí el renglón entero se
   apaga: lo consumido no compite con lo que todavía se puede ofrecer. */
.lista-benef .punto { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--ok-mark); }
.lista-benef .fila.usado .punto { background: var(--gray-300); }

/* En el detalle del saldo cada renglón es una atención ya ocurrida, no algo
   por usar: el verde de "disponible" ahí no dice nada. */
.lista-benef .punto.neutro { background: var(--gray-300); }
.lista-benef .fila .que.fecha { font-family: var(--font-num); font-variant-numeric: tabular-nums; }
.lista-benef .fila .que small {
  margin-left: 7px;
  font-family: var(--font-sans);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--warn-fg);
}

/* El saldo con detalle: no es un enlace, se consulta. */
.balance.con-detalle { cursor: help; }
.balance.con-detalle:focus-visible { outline: 2px solid var(--brand-mark); outline-offset: 3px; border-radius: 6px; }
.lista-benef .fila.usado .que,
.lista-benef .fila.usado .cuanto { color: var(--gray-300); }

/* "Por activar" no es una cifra y no entra en los 52px de la columna. Rompe la
   alineación en ese renglón a propósito: mejor eso que mostrar un saldo que
   todavía no se puede usar. */
.lista-benef .fila .cuanto.texto {
  width: auto;
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  color: var(--brand);
}
th.fecha, td.fecha { width: 155px; }
th.accion, td.accion { width: 145px; }
th.entidad, td.entidad { width: 130px; }
th.ip, td.ip { width: 115px; text-align: right; }

/* Etiqueta neutra: nombra la acción de la bitácora sin competir con el
   contenido de la fila. */
.marca {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--t-sesion-bg);
  color: var(--t-sesion-fg);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
}

/* Por familia, para poder barrer la columna buscando un tipo de movimiento sin
   leer cada frase: lo que toca a un paciente en dorado, la configuración en
   gris, los accesos en azul-gris y lo que huele a problema en rojo. */
.marca.paciente  { background: var(--brand-12); color: var(--brand); }
.marca.catalogo  { background: var(--t-sesion-bg); color: var(--t-sesion-fg); }
.marca.acceso    { background: var(--ok-bg); color: var(--ok-fg); }
.marca.seguridad,
.marca.falla     { background: var(--bad-bg); color: var(--bad-fg); }

/* El detalle de la bitácora es JSON. Se muestra como pares clave/valor: leer
   llaves y comillas en una tabla cuesta más que leer los datos. */
td.detalle { display: flex; flex-wrap: wrap; gap: 5px; }

.dato {
  display: inline-flex;
  gap: 5px;
  padding: 3px 8px;
  border-radius: 7px;
  background: var(--t-desc-bg);
  font-size: 11.5px;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

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

/* Buscador embebido en la cabecera de una tarjeta. */
.filtro { display: flex; gap: 8px; align-items: center; }

/* Excluye las casillas: esta regla se escribió para una caja de búsqueda, y
   como va después de `.check input` le ganaba la puja y convertía la casilla en
   una barra de 230 px. */
.filtro input:not([type="checkbox"]) {
  width: 230px;
  padding: 7px 12px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-btn);
  font: inherit;
  font-size: 13px;
  background: var(--card-bg);
  color: var(--text);
}

.filtro input:focus { outline: none; border-color: var(--gray-300); }

td.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; white-space: nowrap; }
td.name { font-weight: 600; }
td.muted { color: var(--text-muted); }
td.right { text-align: right; }
tr.inactiva td { opacity: .55; }

/* ─────────── Historial ─────────── */

.timeline { padding: 8px 20px 20px; display: flex; flex-direction: column; }

.ev {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 14px;
  padding: 14px 0 14px 18px;
  border-left: 2px solid var(--divider);
  position: relative;
}

.ev::before {
  content: "";
  position: absolute;
  left: -6px;
  top: 20px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--off-mark);
  box-shadow: 0 0 0 3px var(--card-bg);
}

.ev[data-kind="alta"]::before { background: var(--brand-mark); }
.ev[data-kind="consumo"]::before { background: var(--ok-mark); }
.ev[data-kind="anulado"]::before { background: var(--bad-mark); }
.ev[data-kind="excepcion"]::before { background: var(--warn-mark); }

.ev .when { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-size: 12px; color: var(--text-muted); white-space: nowrap; padding-top: 2px; }
.ev .title { font-size: 13.5px; font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ev .by { color: var(--text-muted); font-size: 12.5px; margin-top: 2px; }
.ev .by b { color: var(--text-slate); font-weight: 600; }
.ev[data-kind="anulado"] .title .txt { text-decoration: line-through; color: var(--text-muted); font-weight: 500; }

.reason {
  margin-top: 8px;
  padding: 9px 12px;
  border-radius: var(--r-row);
  background: var(--mist);
  border-left: 3px solid var(--card-border);
  font-size: 12.5px;
  color: var(--text-slate);
}

.ev[data-kind="excepcion"] .reason { background: var(--warn-bg); border-left-color: var(--warn-mark); color: var(--warn-fg); }
.ev[data-kind="anulado"] .reason { background: var(--bad-bg); border-left-color: var(--bad-mark); color: var(--bad-fg); }

/* ─────────── Login ─────────── */

.login-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  padding: 24px;
}

.login-card { width: min(390px, 100%); }
.login-card .titulo { text-align: center; padding: 30px 28px 6px; }
.login-card .titulo strong { font-size: 17.5px; font-weight: 700; color: var(--text); letter-spacing: -.01em; }
.login-card .titulo p { margin: 5px 0 0; color: #5F5F5F; font-size: 13px; }

/* Logotipo sobre la tarjeta de acceso. */
.logo-pie { height: 48px; width: auto; display: block; }

/* Crédito del desarrollador: se lee al final, no compite con nada. */
/* Sube contra el `gap` de 40px del contenedor: la firma pertenece a la
   tarjeta y debe quedar más cerca de ella que el logotipo.
   Usa el mismo tratamiento que las etiquetas del sistema —versalitas con
   letter-spacing— para que se lea como parte del diseño y no como un añadido. */
.firma { margin: -18px 0 0; font-size: 12px; color: #9A9A9A; }
.firma strong { font-weight: 600; color: #6E6E6E; }
.login-card .form-grid { grid-template-columns: 1fr; padding: 22px 28px 26px; }
.login-card .btn { width: 100%; text-align: center; }

/* ─────────── Modal ─────────── */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(0, 0, 0, .45);
  display: none;
  place-items: center;
  padding: 20px;
}

.backdrop.abierto { display: grid; }

.modal {
  width: min(460px, 100%);
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--card-bg);
  border-radius: 14px;
  box-shadow: var(--shadow-modal);
}

.modal-head { padding: 16px 20px; border-bottom: 1px solid var(--divider); }
.modal-head h3 { margin: 0 0 2px; font-size: 15.5px; font-weight: 700; }
.modal-head p { margin: 0; font-size: 12.5px; color: var(--text-muted); }
.modal .form-grid { padding: 18px 20px; gap: 14px; }
.modal-foot { display: flex; gap: 9px; justify-content: flex-end; padding: 14px 20px; border-top: 1px solid var(--divider); }

.nota {
  grid-column: 1 / -1;
  padding: 11px 14px;
  border-radius: var(--r-btn);
  background: var(--nota-bg);
  border: 1px solid var(--nota-line);
  color: var(--nota-fg);
  font-size: 12.5px;
  line-height: 1.5;
}

.nota b { font-family: var(--font-num); font-weight: 700; }

.excepcion-box {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px;
  border: 1px solid var(--warn-line);
  border-radius: var(--r-btn);
  background: var(--warn-bg);
}

.excepcion-box .titulo { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--warn-fg); }
.excepcion-box .texto { font-size: 12.5px; color: var(--warn-fg); }
.excepcion-box .par { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ─────────── Paginación ─────────── */

.paginacion { display: flex; gap: 8px; align-items: center; justify-content: center; padding: 14px; color: var(--text-muted); font-size: 12.5px; }

/* ─────────── Responsive ─────────── */

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .sacudir, .aviso-flotante, .modal { animation: none !important; }

  /* La transición del buscador se cancela, pero el rótulo tiene que seguir
     desapareciendo cuando hay resultados: sin la animación que lo colapsa,
     quedaría ocupando su espacio para siempre. */
  .buscador, .card.resultados, .titulo-buscador { animation: none !important; }
  .saliendo .buscador, .saliendo .card.resultados { animation: none !important; }
  .buscar-zona:not(.sola) .titulo-buscador { display: none !important; }
}

@media (max-width: 900px) {
  .stats { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  .topbar { padding: 0 16px; gap: 12px; }
  .topnav { display: none; }
  main { padding: 20px 16px 48px; }
  .form-grid { grid-template-columns: 1fr; }
  .excepcion-box .par { grid-template-columns: 1fr; }
  /* En pantalla angosta no caben cinco columnas de datos: caducidad y
     vencimiento pasan a un segundo renglón, pegadas a la izquierda. */
  .row { grid-template-columns: 3px 1fr auto auto; row-gap: 8px; }
  .row .celda { grid-row: 2; text-align: left; }
  .row .celda:first-of-type { grid-column: 2; padding-left: 7px; }
  .row .celda.tipo-col { display: none; }
  .row .cta { grid-column: 2 / -1; padding: 0 12px 12px; }
  .ev { grid-template-columns: 1fr; gap: 4px; }
}

@media (max-width: 560px) {
  .brand .bar, .brand .app { display: none; }
}

/* ─────────── Manual de uso ───────────

   El manual vive dentro del sistema y no en un PDF: un archivo que se descarga
   envejece el día que cambia una pantalla, y nadie sabe quién guardó cuál.

   El índice va al costado y se queda pegado al hacer scroll. No es decoración:
   el manual se consulta a saltos —«¿cómo era lo de la excepción?»— y bajar
   diez pantallas hasta encontrar la sección es justo lo que hace que nadie lo
   consulte una segunda vez. */

/* El salto desde el índice se acompaña en vez de teletransportar: sin la
   transición, quien pulsa «Consumos con excepción» aparece de golpe en otro
   punto del documento y pierde la referencia de dónde estaba.

   Va sobre el elemento raíz porque es el que desplaza, y se limita a esta
   pantalla con :has() para no cambiarle el comportamiento al resto del
   sistema. Donde :has() no exista, el salto sigue siendo instantáneo: se
   pierde el detalle, no la navegación. */
html:has(.manual) { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html:has(.manual) { scroll-behavior: auto; }
}

.manual {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

.manual-indice {
  position: sticky;
  top: 82px;
  max-height: calc(100vh - 108px);
  overflow-y: auto;
}

.manual-indice ol { list-style: none; margin: 0; padding: 0; }

.manual-indice a {
  display: flex;
  gap: 10px;
  padding: 7px 10px;
  border-radius: var(--r-btn);
  text-decoration: none;
  color: var(--text);
  line-height: 1.3;
}

.manual-indice a:hover { background: var(--mist); }

.manual-indice .n {
  font-family: var(--font-num);
  font-size: 11px;
  font-weight: 700;
  color: var(--brand);
  padding-top: 1px;
}

.manual-indice .t { font-size: 13px; font-weight: 600; }
.manual-indice small { display: block; font-weight: 400; font-size: 11.5px; color: var(--text-muted); }

.manual-cuerpo {
  padding: 30px 34px 36px;
  /* Un punto más que el resto del sistema. El texto ocupa todo el ancho de la
     tarjeta —igual que las tablas y las capturas, para que el borde derecho no
     quede desparejo— y con 14 px esa línea se hacía larga de seguir. */
  font-size: 15px;
  line-height: 1.6;
  color: var(--text);
  /* Tope para la disposición apilada: sin él, cuando el índice pasa arriba la
     tarjeta se estira a todo el ancho y la línea se vuelve ilegible. */
  max-width: 860px;
  counter-reset: seccion;
}

/* Corte entre secciones.

   Antes era una línea fina con el mismo aire arriba que abajo: el filete
   quedaba flotando sin pertenecer a ninguna de las dos secciones y el corte se
   leía como un renglón más. Ahora manda el espacio —46 px antes del filete y 38
   después—, de modo que el título queda más cerca de su propio texto (16 px)
   que del corte, que es lo que hace que se lean como bloques y no como una
   lista continua.

   El filete arranca con un tramo dorado del ancho de la pastilla del número, y
   justo encima de ella. Es la misma columna, y convierte una línea genérica en
   una marca de sección. */
.manual-cuerpo section + section {
  margin-top: 46px;
  padding-top: 38px;
  background-image: linear-gradient(to right, var(--brand) 0 46px, var(--divider) 46px);
  background-repeat: no-repeat;
  background-size: 100% 2px;
  background-position: top left;
}

/* El desplazamiento del índice deja el título pegado al borde superior; el
   margen negativo compensa la barra fija. */
.manual-cuerpo h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 16px;
  scroll-margin-top: 84px;
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -.01em;
  /* La cuenta va en el título y no en la sección: así el número del contenido y
     el del índice cuentan exactamente lo mismo —los títulos— y no pueden
     separarse el día que alguien agregue un bloque sin encabezado. */
  counter-increment: seccion;
  /* Cada sección reinicia la cuenta de sus apartados. */
  counter-reset: apartado;
}

/* El número va en pastilla y no como una cifra suelta en el margen.

   Colgando en el margen quedaba a la altura de una nota al pie: el título lo
   aplastaba y el número dejaba de leerse como el rótulo de la sección. La
   pastilla es además el mismo recurso que usan los pasos numerados y los
   estados del sistema, así que se reconoce sin explicación.

   Va en la línea del título —y no colgando— porque a este tamaño no cabe en el
   margen de la tarjeta. `flex: none` evita que se comprima cuando el título
   ocupa dos líneas. */
.manual-cuerpo h2::before {
  content: counter(seccion, decimal-leading-zero);
  flex: none;
  /* Ancho fijo aunque «01» y «11» no midan igual: así las pastillas de todas
     las secciones forman una columna y no un borde dentado. */
  min-width: 46px;
  padding: 6px 10px;
  border-radius: 9px;
  text-align: center;
  background: var(--brand-12);
  color: var(--brand);
  font-family: var(--font-num);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: .03em;
}

/* El apartado tiene que pesar más que el texto que introduce.

   Antes iba en versalitas doradas de 11,5 px, o sea más chico que el cuerpo de
   15: leído así no era un título sino un rótulo, y la sección entera se
   aplanaba. Ahora la escala baja de verdad —22 en la sección, 17 en el
   apartado, 15 en el texto— y el dorado se reserva para el número, que es lo
   que sí es una marca y no un encabezado.

   El espacio también ordena: mucho aire arriba, para despegarlo del bloque
   anterior, y poco abajo, para que se lea pegado a su propio párrafo. */
.manual-cuerpo h3 {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 34px 0 7px;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.005em;
  color: var(--text);
  counter-increment: apartado;
}

/* El número lleva delante el de su sección —01.1, 01.2— para que se pueda citar
   sin ambigüedad y para que se vea de qué sección depende al llegar por el
   medio del documento. */
.manual-cuerpo h3::before {
  content: counter(seccion, decimal-leading-zero) "." counter(apartado);
  flex: none;
  font-family: var(--font-num);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--brand);
}

.manual-cuerpo p { margin: 0 0 13px; }
.manual-cuerpo p:last-child { margin-bottom: 0; }

/* Apunte al margen: una precisión que conviene saber pero que no cambia lo que
   hay que hacer. Va sin recuadro —el de la nota se reserva para lo que sí
   afecta al procedimiento— y se distingue por el icono y el tono más suave. */
.manual-cuerpo .apunte {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 18px 0;
  color: var(--text-muted);
  font-size: 14px;
}

.manual-cuerpo .apunte svg {
  width: 17px;
  height: 17px;
  flex: none;
  /* Alinea el círculo con la primera línea, no con la caja del párrafo. */
  margin-top: 3px;
  color: var(--brand);
}

/* Justificado, y sin partir palabras: los guiones de corte se leen como parte
   del texto y en pantalla estorban más de lo que ayudan.

   Sin partición el justificado reparte el sobrante entre los espacios, así que
   se deja `text-wrap: pretty` para que el navegador elija los cortes de línea
   mirando el párrafo entero y no palabra por palabra. A este ancho —cerca de
   cien caracteres— cada línea lleva muchos espacios donde repartir, y el
   sobrante por hueco queda imperceptible.

   Solo va en la prosa: en una tabla o en un pie de foto, una línea corta
   justificada queda deshilachada. */
.manual-cuerpo p,
.manual-cuerpo .nota,
.manual-cuerpo .pasos > li {
  text-align: justify;
  text-wrap: pretty;
  hyphens: manual;
}
.manual-cuerpo a { color: var(--brand); }

.manual-cuerpo .nota {
  margin: 16px 0;
  padding: 12px 16px;
  border-left: 3px solid var(--brand);
}

/* En los formularios la negrita de una nota es casi siempre una cifra, y por
   eso va en la tipografía de números. Acá es el arranque de una frase. */
.manual-cuerpo .nota b { font-family: inherit; font-weight: 700; }

.manual-cuerpo .nota.malo {
  background: var(--bad-bg);
  border-color: var(--bad-mark);
  border-left-color: var(--bad-fg);
  color: var(--bad-fg);
}

.manual-cuerpo .pasos {
  counter-reset: paso;
  list-style: none;
  margin: 14px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.manual-cuerpo .pasos > li {
  counter-increment: paso;
  position: relative;
  padding-left: 34px;
}

.manual-cuerpo .pasos > li::before {
  content: counter(paso);
  position: absolute;
  left: 0;
  top: 1px;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--brand-12);
  color: var(--brand);
  font-family: var(--font-num);
  font-size: 11px;
  font-weight: 700;
}

.manual-cuerpo figure {
  /* Separación del texto de alrededor: el marco necesita despegarse del
     párrafo que lo introduce y del que sigue, o se lee como parte de ellos. */
  margin: 28px 0;
  padding: 14px;
  border: 1px solid var(--divider);
  border-radius: var(--r-card);
  background: var(--mist);
}

.manual-cuerpo figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
}

/* Los recortes de un cuadro de diálogo miden la mitad: estirarlos al ancho
   completo los deja borrosos y desproporcionados. Se encoge el marco entero y
   no solo la imagen, para que no quede flotando en un recuadro vacío. */
.manual-cuerpo figure.angosta { max-width: 452px; margin-left: auto; margin-right: auto; }

.manual-cuerpo figcaption {
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
  text-align: center;
}

/* Cuadrícula completa: en una tabla de referencia, donde se cruza una fila con
   una columna para leer un dato, las líneas verticales son las que sostienen la
   lectura. Un solo color para todo el enrejado —el marco exterior sale de las
   propias celdas al colapsarse los bordes— y la cabecera con doble grosor, que
   es lo único que necesita destacarse. */
.manual-tabla {
  width: 100%;
  border-collapse: collapse;
  margin: 14px 0;
  font-size: 13.5px;
}

.manual-tabla th,
.manual-tabla td { border: 1px solid var(--border-soft); }

.manual-tabla th {
  text-align: left;
  padding: 8px 12px;
  font-size: 10.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom-width: 2px;
}

.manual-tabla td { padding: 10px 12px; vertical-align: top; }
.manual-tabla td:first-child { white-space: nowrap; width: 1%; padding-right: 22px; }
.manual-tabla.estados td:first-child { padding-right: 16px; }

/* Reglas generales de tabla que acá estorban, y que hay que anular por su
   nombre porque ganan por especificidad:
   - el redondeo de las esquinas, tanto en la cabecera (`th:first-child`) como
     en las celdas del cuerpo; está pensado para filas que se seleccionan y en
     una cuadrícula rompe el marco;
   - el borde inferior suprimido en la última fila, que dejaba la tabla abierta
     por abajo. */
/* Los selectores van completos —no basta `.manual-tabla td`— porque
   `tbody tr td:first-child` pesa más y ganaba la puja de especificidad. */
.manual-tabla th,
.manual-tabla tbody tr td:first-child,
.manual-tabla tbody tr td:last-child { border-radius: 0; }

.manual-tabla tbody tr:last-child td { border-bottom: 1px solid var(--border-soft); }

.manual-cuerpo kbd {
  font-family: var(--font-num);
  font-size: 11.5px;
  padding: 1px 6px;
  border: 1px solid var(--border-soft);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--mist);
}

@media (max-width: 900px) {
  .manual { grid-template-columns: minmax(0, 1fr); }
  .manual-indice { position: static; max-height: none; }
  .manual-cuerpo { padding: 22px; }
}

/* Impreso sale como folleto: sin barra, sin índice lateral y sin la tarjeta.
   Una sección por hoja para que no se parta una captura por la mitad. */
@media print {
  .topbar, .manual-indice, .page-head .right, .avisos { display: none !important; }
  body { background: #FFFFFF; }
  main { padding: 0; }
  .manual { display: block; }
  .manual-cuerpo { border: 0; box-shadow: none; padding: 0; }
  .manual-cuerpo section { break-inside: auto; }
  /* En papel cada sección empieza en hoja nueva, así que el filete sobra. */
  .manual-cuerpo section + section { break-before: page; background-image: none; padding-top: 0; }
  .manual-cuerpo h2 { break-after: avoid; }
  .manual-cuerpo figure, .manual-cuerpo .nota, .manual-cuerpo .pasos { break-inside: avoid; }
}

/* ─────────── Filtro de un reporte ───────────

   En su propia franja bajo la cabecera. Compartiendo línea con el título, el
   desplegable se quedaba sin ancho y partía en dos el nombre del beneficio. */
.barra-filtro {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--divider);
}

/* El desplegable se viste como cualquier campo del sistema —mismo borde, mismo
   fondo, mismo redondeo y la misma reacción al foco—, no con el aspecto que le
   dé el navegador. Es el único control de esta barra y desentonaba justo en el
   sitio donde más se mira. */
.barra-filtro select {
  min-width: 300px;
  padding: 9px 12px;
  border: 1px solid var(--card-border);
  border-radius: var(--r-btn);
  background: var(--input-bg);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}

.barra-filtro select:hover { border-color: var(--input-line-fuerte); }
.barra-filtro select:focus { border-color: var(--input-focus); }

.barra-filtro .check { gap: 7px; white-space: nowrap; font-size: 12.5px; color: var(--text-slate); }
.barra-filtro .check input { width: 16px; height: 16px; }
.barra-filtro .btn { margin-left: auto; }

/* ─────────── Tarjetas de resumen de un reporte ───────────

   Van sobre la tabla y no al pie: son las cifras que se copian a un correo, y
   buscarlas al final obliga a recorrer una lista que puede tener doscientas
   filas.

   Cada una en su propia tarjeta. Sueltas en una fila no se sabía dónde
   terminaba una y empezaba la siguiente; el marco las separa sin necesidad de
   rayas ni de espaciados que hay que calibrar a ojo. */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--divider);
  background: var(--mist);
}

.kpi {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border: 1px solid var(--border-soft);
  border-radius: var(--r-btn);
  background: var(--card-bg);
}

.kpi b {
  font-family: var(--font-num);
  font-size: 24px;
  font-weight: 700;
  line-height: 1.05;
  color: var(--text);
}

.kpi span {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* El color entra solo cuando significa algo. La primera es la que contesta la
   pregunta; las otras dos se encienden únicamente si hay algo que atender, de
   modo que un cero no pinte una alarma que no existe. */
.kpi.principal { border-color: var(--brand-light); background: var(--brand-06); }
.kpi.principal b { color: var(--brand); }
.kpi.principal span { color: var(--brand); }

.kpi.warn { border-color: var(--warn-line); background: var(--warn-bg); }
.kpi.warn b, .kpi.warn span { color: var(--warn-fg); }

.kpi.bad { border-color: var(--bad-mark); background: var(--bad-bg); }
.kpi.bad b, .kpi.bad span { color: var(--bad-fg); }

/* El filtro del reporte lleva desplegable y casillas además del botón. La
   casilla en sí la dibuja `.check`, que ya existe; acá solo se ajusta el rótulo
   para que no pese más que el resto de la barra. */
.filtro .check { gap: 7px; white-space: nowrap; font-size: 12.5px; color: var(--text-slate); }
.filtro .check input { width: 16px; height: 16px; }

.filtro select { max-width: 260px; font-size: 13px; padding: 7px 10px; }

/* Los nombres no se parten: la columna de paciente se estrecha hasta dejar
   «Daniel Isaías Nunura Tovar» en cuatro renglones. */
.reporte td.name,
.reporte td.cifra { white-space: nowrap; }

/* La segunda línea de una celda —documento, paquete, quién vendió— es contexto,
   no dato: se lee si hace falta y no compite con lo de arriba. */
.reporte .bajo-nombre {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 3px;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--text-muted);
}

.reporte .bajo-nombre .sep { color: var(--gray-300); }
.reporte .bajo-nombre .num { font-family: var(--font-num); }

/* El saldo es la cifra que se mira. La porción contratada va al lado en
   pequeño: dice sobre cuánto es, sin pesar como si fuera otro número. */
.reporte td.saldo b { font-size: 16px; font-weight: 700; color: var(--text); }
.reporte td.saldo small { margin-left: 3px; font-size: 12px; color: var(--text-muted); }

/* Las columnas de fecha se alinean a la derecha entre sí, no cada una por su
   cuenta: es lo que deja las cifras comparables de un vistazo. */
.reporte td.cifra, .reporte th.cifra { text-align: right; }
.reporte td.estado, .reporte th.estado { text-align: left; }
