/* Nexus · primitivas de CONTROL — FUENTE ÚNICA
   Creado 2026-08-27 (sdd/staff-chrome-unification, fase C-quinquies).

   ── POR QUÉ EXISTE ─────────────────────────────────────────────────────────
   Directriz del usuario, 2026-08-27: «unificar el css para que no se creen más líneas en css,
   sino que siempre se usen las mismas que se suponen que ya forman parte de la estructura de
   cómo debería ser toda la interfaz, así de ahora en adelante todo se parece y evitamos
   situaciones como la de plan, que parece una plataforma distinta a todo lo demás».

   Ese es exactamente el modo de fallo que este archivo viene a cortar. Hasta ahora cada pantalla
   escribía sus propios estilos —inline en Costeo y Plan, en `main/src/styles.css` para `main`—,
   así que dos botones con la misma función acababan con paddings, radios y colores distintos sin
   que nada los reconciliara. La causa es estructural, la misma que ya se corrigió para los tokens
   (`tokens.css`), el marco (`chrome.css`) y los modales (`modals.css`): sin un lugar común, la
   deriva no es un descuido, es el resultado por defecto.

   ── CÓMO USARLO ────────────────────────────────────────────────────────────
   ANTES de escribir un estilo nuevo para un control, buscar aquí si ya existe la primitiva. Si
   existe, se usa. Si no existe pero el control se va a repetir, se AÑADE aquí, no en el módulo.
   Solo se justifica un estilo local cuando es genuinamente único de una pantalla.

   Se enlaza con `<link>` DESPUÉS de `tokens.css` (usa sus variables) y ANTES de la hoja del
   módulo, para que un módulo pueda sobrescribir si algún día lo necesita. `<link>` y no
   `@import` por la misma razón que los otros: Costeo y Plan no tienen hoja de estilos propia.

   ── ESTADO ─────────────────────────────────────────────────────────────────
   Los TRES módulos de staff lo consumen. Plan se incorporó en la fase J (2026-08-27): era el
   pendiente declarado aquí, y era justo el módulo que el usuario había señalado como «una
   plataforma distinta a todo lo demás». */

/* ─── Chip / píldora de acción ──────────────────────────────────────────────
   Un control compacto y redondeado con dos estados: normal y `is-active`. Hoy lo usan el filtro
   alfabético y el paginador de la lista de pacientes de Costeo; antes cada uno repetía ~10
   propiedades inline con ternarios por propiedad.

   El color de acento entra por `--nx-chip-accent`, que el consumidor fija (en Costeo es el color
   del rol, `ROLES_CONFIG[role].color`). Así el estado activo se expresa con UNA clase en vez de
   recalcular borde, fondo, color y peso en cada render. Si nadie la define, cae a `--brand-blue`,
   de modo que la primitiva funciona sin configuración. */
.nx-chip {
  --nx-chip-accent: var(--brand-blue);
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.875rem;
  border: 1px solid var(--border, var(--line));
  border-radius: 999px;
  background: #fff;
  /* fase J: era `--muted` (#9AA5B1), 2.38:1 sobre el blanco del propio chip -- por debajo del
     umbral en las 18 instancias que ya lo usaban en Costeo. `--ink-muted` es el mismo gris con la
     luminosidad bajada hasta 4.88:1 sobre blanco. */
  color: var(--ink-muted);
  font-family: 'Libre Franklin', sans-serif;
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.4;
  cursor: pointer;
  white-space: nowrap;
  /* Transición acotada a lo que de verdad cambia. `transition: all` (lo que había inline) obliga
     al navegador a vigilar cada propiedad animable del elemento. */
  transition: background 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease);
}
.nx-chip:hover:not(:disabled) { border-color: var(--nx-chip-accent); color: var(--charcoal); }
/* fase J: el chip es el control mas repetido del sistema (filtros, paginador, acciones de banda) y
   no tenia indicador de foco. Mismo anillo que el chrome, para que teclado se comporte igual en
   toda la aplicacion. */
.nx-chip:focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: 2px; }
.nx-chip:disabled { opacity: 0.45; cursor: not-allowed; }
.nx-chip.is-active {
  border-color: var(--nx-chip-accent);
  /* `color-mix` en vez de concatenar el hex con '22' (lo que hacía el inline): aquel truco solo
     funciona si el acento es un hex de 6 dígitos, y se rompe en silencio con `rgb()` o con una
     variable. Así la primitiva acepta cualquier formato de color. */
  background: color-mix(in srgb, var(--nx-chip-accent) 13%, #fff);
  color: var(--nx-chip-accent);
  font-weight: 700;
}
.nx-chip-count { opacity: 0.7; font-weight: 400; }
.nx-chip-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ─── Paginador ─────────────────────────────────────────────────────────────
   Estado ("Mostrando 1–25 de 66") a la izquierda y controles a la derecha. Los botones NO tienen
   estilo propio: son `.nx-chip`, para que un número de página y un filtro alfabético se lean como
   el mismo tipo de control, que es lo que son. */
.nx-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.25rem;
}
.nx-pager-status { font-size: 0.75rem; color: var(--ink-muted); font-family: 'Libre Franklin', sans-serif; } /* fase J: `--muted` daba 2.4:1 */
.nx-pager-status strong { color: var(--charcoal); font-weight: 600; }
.nx-pager-controls { display: flex; gap: 0.35rem; flex-wrap: wrap; }

@media (max-width: 560px) {
  /* En móvil el estado y los controles no caben en una fila sin apretarse: se apilan centrados,
     mismo criterio que ya usa `.brand-footer` en su breakpoint. */
  .nx-pager { flex-direction: column; align-items: stretch; text-align: center; }
  .nx-pager-controls { justify-content: center; }
}

/* ─── Pie embebido en una pantalla ──────────────────────────────────────────
   `.brand-footer` (en `chrome.css`) asume que es el pie del documento, hijo directo de
   `.brand-frame`. Cuando se monta DENTRO de una pantalla que ya tiene su propio ancho y padding
   —el caso de la lista de pacientes de Costeo, que no usa `BrandFrame`— necesita ocupar el ancho
   del contenedor y separarse del contenido. Modificador, no una copia del pie. */
.nx-inline-footer { width: 100%; margin-top: 2rem; }

/* ─── Etiqueta de estado (no interactiva) ───────────────────────────────────
   Creada en la fase J (2026-08-27) al alinear Plan. `.nx-chip` no servia para esto y la diferencia
   no es cosmetica: `.nx-chip` es un CONTROL -- tiene `cursor: pointer`, `:hover` que cambia el
   borde y `:disabled`. Aplicarlo a un `<span>` que solo informa ("Solo lectura", el nombre de la
   variante del PCP, el estado de aprobacion) promete al usuario algo que se puede pulsar y no se
   puede: es una afordancia inventada, de las que el registro de producto prohibe.

   `.nx-badge` dice lo mismo sin prometer nada. Variantes por modificador, no por estilo inline en
   cada punto de uso -- que es como Plan tenia siete versiones de la misma pildora.

   El tono `info` usa `--brand-blue-ink` y no `--brand-blue`: el azul de marca sobre blanco mide
   1.98:1 (ver `tokens.css`), y esto es texto de 0.7rem. */
.nx-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  border: 1px solid transparent;
  background: var(--tan-wash);
  color: var(--charcoal);
  font-family: 'Libre Franklin', sans-serif;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.5;
  white-space: nowrap;
}
/* `nx-badge-info` NO usa `--brand-blue-ink` tal cual: ese token esta calibrado contra la superficie
   crema, y aqui el texto se pinta sobre el TINTE azul del propio badge, mas oscuro. Compuesto sobre
   su fondo real el token daba 4.40:1; #567188 da 4.54:1. `nx-badge-warn` si usa el token, que tras
   el barrido en navegador se bajo a #846238 justamente por este motivo (ver `tokens.css`). */
.nx-badge-info    { background: rgba(145, 189, 228, 0.16); border-color: rgba(145, 189, 228, 0.5);  color: #567188; }
.nx-badge-warn    { background: rgba(220, 201, 166, 0.28); border-color: rgba(184, 137, 78, 0.45);  color: var(--warm-tan-ink); }
.nx-badge-ok      { background: #E6F5EE;                   border-color: rgba(46, 125, 91, 0.35);   color: #216B4C; }
.nx-badge-neutral { background: #fff;                      border-color: var(--line);               color: var(--ink-muted); }
/* `nx-badge-danger` para un estado adverso que NO es destructivo: el coral (`--coral`) esta
   reservado a lo irreversible (DESIGN.md, "The Coral Alarm Rule"), y un PCP rechazado se vuelve a
   enviar. #A33 sobre este lavado mide 5.4:1. */
.nx-badge-danger  { background: #FCEDEC;                   border-color: rgba(163, 51, 51, 0.38);   color: #A33; }
/* Cuando la etiqueta ES un control (la pildora de aprobacion del PCP lo es cuando quien mira puede
   aprobar), hereda el mismo foco y realce que el resto del sistema. Un `<span>` no dispara ninguna
   de las dos, asi que la misma clase sirve para los dos elementos. */
.nx-badge:is(button):hover { filter: brightness(0.97); }
.nx-badge:is(button):focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .nx-chip { transition: none; } }

/* ─── Botón ────────────────────────────────────────────────────────────────────────────────────
   Primitiva compartida por los cuatro módulos (sdd/staff-chrome-unification, fase Q, 2026-08-28).

   ── POR QUE EXISTE ──────────────────────────────────────────────────────────────────────────
   Habia TRES sistemas de boton conviviendo, y ninguno era el mismo control:

     main    171 botones repartidos en ~50 clases ad hoc (`.pm-btn-muted`, `.ops-btn-danger`,
             `.user-form-actions button`, `.tasks-create-btn`...). Distintas clases, pero un
             patron dominante y consistente: navy + blanco, o blanco + borde `--line`.
     plan     14 botones sobre `ss.btn`: #457C9E, radio 7, 9px 18px, 13px. Un azul acero que no
             existe en ningun otro modulo ni en la paleta de marca.
     costeo  146 botones con estilo inline y sin criterio comun: #1A2332, #2C3E50, #B8894E,
             #2E7D5B, #5BA3D0... el mismo gesto pintado de cinco colores segun la pantalla.

   Los valores de abajo NO se inventaron: se destilaron del patron dominante de `main`, que es lo
   que el staff ya tiene aprendido. Medidos todos los estados antes de fijarlos:

     blanco / --deep-navy .......... 10.98:1   primario
     blanco / #1A2632 .............. 15.36:1   primario en hover
     --charcoal / #fff ............. 8.86:1    secundario
     --charcoal / --warm-cream ..... 8.22:1    secundario en hover
     #A33 / #fff ................... 6.50:1    peligro
     #A33 / #FCEDEC ................ 5.72:1    peligro en hover

   ── DOS DIVERGENCIAS DECLARADAS FRENTE A `DESIGN.md` §Buttons ───────────────────────────────
   El documento pide radio 7-8px y `padding: 0.6rem 1rem` para el primario. El codigo real de
   `main` usa 6px y `0.4rem 0.9rem` en los ~8 grupos de botones de panel, y reserva la escala
   grande para el CTA de la pantalla de acceso. Se sigue el CODIGO, porque es la interfaz que el
   staff ya usa y el criterio pedido fue «exactamente como los del main». Queda anotado para que
   se decida si lo que se corrige es el documento o el codigo -- pero no los dos a la vez.

   `--coral` NO aparece aqui: por «The Coral Alarm Rule» (DESIGN.md) esta reservado a lo
   irreversible, y un boton de peligro no siempre lo es. El rojo de accion es #A33, el mismo que
   ya usan `.pm-btn-danger`, `.ops-btn-danger` y `.pe-danger-btn` en `main`. */
/* Los valores del canon se exponen como custom properties para que `main` los consuma sin
   repetirlos (fase Q.11, 2026-08-28). `main` pinta la mayoria de sus botones con selectores
   DESCENDIENTES -- `.user-form-actions button`, `.task-row-actions button`, `.ops-table-actions
   button`... --, no con una clase por boton, asi que no puede adoptar `.nx-btn` sin tocar los
   171 sitios del JSX. Consumiendo estas variables comparte la FUENTE de los valores, que es lo
   que §10.4 pide: al cambiar el canon aqui, cambia en los cuatro modulos a la vez.
   Mismo patron que `--nx-chip-accent` mas arriba. */
:root {
  --nx-btn-radius: 6px;
  --nx-btn-pad: 0.4rem 0.9rem;
  --nx-btn-size: 0.8rem;
  --nx-btn-weight: 600;
  /* Escala pequena, medida en `main`: filas de tabla y barras de accion densas. */
  --nx-btn-pad-sm: 0.3rem 0.7rem;
  --nx-btn-size-sm: 0.72rem;

  --nx-btn-bg: #fff;
  --nx-btn-fg: var(--charcoal);
  --nx-btn-border: var(--line);
  --nx-btn-bg-hover: var(--warm-cream);

  --nx-btn-primary-bg: var(--deep-navy);
  --nx-btn-primary-fg: #fff;
  --nx-btn-primary-bg-hover: #1A2632;

  --nx-btn-danger-fg: #A33;
  --nx-btn-danger-border: rgba(163, 51, 51, 0.4);
  --nx-btn-danger-bg-hover: #FCEDEC;
}

.nx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  font-family: inherit;
  font-size: var(--nx-btn-size);
  font-weight: var(--nx-btn-weight);
  line-height: 1.2;
  padding: var(--nx-btn-pad);
  border-radius: var(--nx-btn-radius);
  border: 1px solid var(--nx-btn-border);
  background: var(--nx-btn-bg);
  color: var(--nx-btn-fg);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.nx-btn:hover:not(:disabled) { background: var(--nx-btn-bg-hover); }
/* `outline`, nunca `box-shadow`: cualquier ancestro con `overflow: hidden` recorta la sombra, y
   las barras de acciones de los formularios lo tienen. Misma regla que el resto del sistema. */
.nx-btn:focus-visible { outline: 2px solid var(--focus-ring-color); outline-offset: 2px; }
.nx-btn:disabled { opacity: 0.55; cursor: not-allowed; }

.nx-btn-primary {
  background: var(--nx-btn-primary-bg);
  color: var(--nx-btn-primary-fg);
  border-color: var(--nx-btn-primary-bg);
}
.nx-btn-primary:hover:not(:disabled) {
  background: var(--nx-btn-primary-bg-hover);
  border-color: var(--nx-btn-primary-bg-hover);
}

.nx-btn-danger {
  background: transparent;
  border-color: var(--nx-btn-danger-border);
  color: var(--nx-btn-danger-fg);
}
.nx-btn-danger:hover:not(:disabled) { background: var(--nx-btn-danger-bg-hover); }

/* Escala densa: filas de tabla y barras de accion con muchos controles seguidos. */
.nx-btn-sm { padding: var(--nx-btn-pad-sm); font-size: var(--nx-btn-size-sm); }

/* Escala del CTA de la pantalla de acceso (`.btn-primary` de `main`). Es el unico sitio donde el
   boton es el elemento principal de la pantalla; en un panel se veria desproporcionado. */
.nx-btn-cta { padding: 0.85rem 1.5rem; border-radius: 8px; font-size: 0.88rem; letter-spacing: 0.04em; }
.nx-btn-block { width: 100%; }

/* Boton cuadrado de un solo glifo: los `+`/`-` de los contadores de Costeo y los iconos de accion
   de las filas. El minimo de 28px viene del area pulsable, no de la tipografia. */
.nx-btn-icon { padding: 0; width: 28px; height: 28px; font-size: 0.95rem; font-weight: 700; }

@media (prefers-reduced-motion: reduce) { .nx-btn { transition: none; } }

/* ─── Medidor de fortaleza de contraseña ────────────────────────────────────────────────────────
   `shared/ui/PasswordStrength.jsx`, consumido por `ChangePasswordModal` y `ResetPasswordGate`
   (`main`). No existe en el legacy -- funcionalidad nueva, no paridad. Mismo patron de acento por
   variable que `--nx-chip-accent` / los `--nx-btn-*`: el tono lo fija `data-tone` en el
   contenedor, no una clase de color por elemento. */
.nx-pwstrength { width: 100%; font-family: 'Libre Franklin', sans-serif; }
.nx-pwstrength[data-tone="none"]    { --nx-pws-accent: var(--line);           --nx-pws-text: var(--ink-muted); }
.nx-pwstrength[data-tone="danger"]  { --nx-pws-accent: #A33;                  --nx-pws-text: #A33; }
/* `--warm-tan-dark` (el oro de accion, #B8894E) daba 2.89:1 sobre `--warm-cream` como relleno de
   barra -- por debajo del 3:1 que este mismo archivo exige a un acento en `tokens.css`. Se usa
   `--warm-tan-ink` para las dos variables, igual que "danger"/"safe" ya usan un solo color para
   acento y texto: 5.14:1 sobre crema, medido y documentado en `tokens.css`. */
.nx-pwstrength[data-tone="caution"] { --nx-pws-accent: var(--warm-tan-ink);   --nx-pws-text: var(--warm-tan-ink); }
.nx-pwstrength[data-tone="safe"]    { --nx-pws-accent: #216B4C;               --nx-pws-text: #216B4C; }

.nx-pwstrength-meter { display: grid; gap: 0.375rem; }
.nx-pwstrength-cell { position: relative; height: 6px; overflow: hidden; border-radius: 2px; background: var(--line); }
.nx-pwstrength-fill {
  position: absolute; inset: 0; transform-origin: left; border-radius: 2px;
  background: var(--nx-pws-accent);
}

.nx-pwstrength-status { margin-top: 0.5rem; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; height: 1.25rem; }
.nx-pwstrength-label { display: inline-grid; font-size: 0.78rem; font-weight: 600; }
.nx-pwstrength-label-item { grid-column: 1; grid-row: 1; white-space: nowrap; color: var(--nx-pws-text); }
.nx-pwstrength-guessable { font-size: 0.72rem; color: var(--warm-tan-ink); white-space: nowrap; }

.nx-pwstrength-rules { margin: 0.75rem 0 0; padding: 0; list-style: none; display: grid; gap: 0.375rem; }
/* Cuando `guessable` es true el puntaje ya cayo a 1 por un patron comun o secuencial, sin
   importar cuantas reglas formales cumpla el valor -- la checklist deja de ser la senal
   principal y se atenua para no contradecir visualmente al medidor. Se atenua SOLO el icono
   de check (decorativo, ya respaldado por el span `sr-only` "met"/"not met" para lector de
   pantalla): atenuar el `<ul>` o el texto de la regla arrastraba el TEXTO tambien, y
   `--ink-muted`/`--charcoal` ya estan al limite de contraste (4.53:1 / 8.22:1 sobre
   `--warm-cream` a opacidad plena, ver `tokens.css`) -- a 0.5 de opacidad caian a 1.93:1 y
   2.42:1, por debajo del umbral WCAG AA de 4.5:1.

   La opacidad es 0.7, NO 0.5: el icono es un objeto grafico que comunica estado, asi que le
   aplica el minimo de 3:1 del criterio WCAG 1.4.11 (contraste de elementos no textuales).
   Calculado, no estimado, componiendo el relleno verde (#216B4C de
   `.nx-pwstrength-rule-check-fill`) sobre el fondo realmente pintado, `--warm-cream` (#F9F6F0),
   con la formula de luminancia relativa de WCAG: a 0.5 daba 2.19:1 (FALLA); el corte real esta
   entre 0.67 (3.01:1) y 0.66 (2.95:1), y 0.65 -- el multiplo de 0.05 inmediatamente inferior --
   se queda en 2.90:1, asi que sube un paso. A 0.7 el relleno da 3.20:1 sobre la crema y el
   glifo blanco del check da 3.37:1 sobre ese relleno compuesto (6.42:1 a opacidad plena), las
   dos por encima de 3:1. Bajar este numero exige recalcular, no estimar. */
.nx-pwstrength[data-guessable="true"] .nx-pwstrength-rule-check { opacity: 0.7; }
.nx-pwstrength-rule { display: flex; align-items: center; gap: 0.5rem; }
.nx-pwstrength-rule-check {
  position: relative; display: grid; place-items: center; flex-shrink: 0;
  width: 14px; height: 14px; border-radius: 4px; border: 1px solid var(--line); color: #fff;
  transition: opacity 150ms var(--ease);
}
.nx-pwstrength-rule-check-fill { position: absolute; inset: 0; border-radius: 3px; background: #216B4C; }
.nx-pwstrength-rule-icon { position: relative; width: 9px; height: 9px; }
.nx-pwstrength-rule-text { font-size: 0.78rem; color: var(--ink-muted); }
.nx-pwstrength-rule.is-met .nx-pwstrength-rule-text { color: var(--charcoal); }

@media (prefers-reduced-motion: reduce) {
  /* `.nx-pwstrength-fill`/`-label-item`/`-rule-text` no tenian transicion CSS alguna que apagar
     -- su movimiento es JS (`motion`), ya cortado por `useReducedMotion()` en el componente. La
     unica transicion CSS real de este bloque es la de `.nx-pwstrength-rule-check` (arriba), el
     salto de opacidad cuando `guessable` se activa. */
  .nx-pwstrength-rule-check { transition: none; }
}

/* ─── Texto solo para lector de pantalla ────────────────────────────────────────────────────────
   Primitiva generica de accesibilidad, no ligada al medidor de arriba -- cualquier control puede
   necesitarla. No existia en el repo (verificado, `CLAUDE.md` §10.4 anti-duplicacion). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
