/* ---------------------------------------------------------------- Fuentes
 *
 * Self-hosted, not Google's CDN: a compliance portal should not leak a request
 * per visit to a third party (design system §1.8). Served from the binary with
 * go:embed.
 *
 * VARIABLE versions: one file per family covers every weight the spec uses
 * (Archivo 400-900, JetBrains Mono 400-500) instead of eight static ones.
 * 66 KB for both, latin subset.
 *
 * font-display: swap — text shows immediately in the fallback family and swaps
 * once loaded. On a compliance table, reading late is worse than reading in a
 * different typeface for a moment.
 */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url('fonts/archivo-latin.woff2') format('woff2-variations');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('fonts/jetbrains-mono-latin.woff2') format('woff2-variations');
}

/* Porticus — design system tokens.
 *
 * A literal transcription of docs/design/design_handoff_porticus_portal/design-system.md.
 * Values are never "eyeballed": if something does not fit a screen, the spec is
 * corrected with Pedro first and this file after, never the other way round.
 *
 * A single theme file: when the handoff changes, this changes and not the views.
 */

:root {
  /* --- Marca --- */
  --navy:        #0F2A54;
  --navy-700:    #16386B;
  --navy-600:    #1c4380;
  --navy-500:    #2A4574;
  --blue:        #1F63E3;
  --blue-400:    #4A8BF0;
  --blue-200:    #9FC0F7;
  --blue-100:    #E8EEF9;

  /* --- Neutros --- */
  --bg:                  #F4F6FA;
  --surface:             #FFFFFF;
  --border:              #E5E7EB;
  --border-soft:         #EEF1F6;
  --text:                #0F2A54;
  --text-muted:          #4B5563;
  --text-subtle:         #8b95a5;
  --text-disabled:       #9CA3AF;
  --text-on-navy:        #7f9cc9;
  --text-on-navy-strong: #C9DCFF;

  /* --- Compliance states: ALWAYS a background/border/text triple.
         Nunca el color como único portador de significado: cada chip lleva
         además su etiqueta textual. --- */
  --ok-bg:     #E6F2EC;  --ok-border:     #BEDDCE;  --ok-text:     #0F7A55;
  --pend-bg:   #FDF2E2;  --pend-border:   #F3DFBD;  --pend-text:   #B4690E;
  --riesgo-bg: #FBE9E7;  --riesgo-border: #F2CFC9;  --riesgo-text: #B3261E;
  --na-bg:     #F4F6FA;  --na-border:     #E5E7EB;  --na-text:     #9CA3AF;

  /* --- Status dots of the compliance table ---
     Son tokens PROPIOS y no los *-text de arriba: aquéllos están calculados
     para leerse como TEXTO sobre el fondo claro de un chip, así que son oscuros.
     Como relleno sólido de un punto chico eso se paga caro — el ámbar #B4690E se
     ve marrón y a 8px no se distingue del rojo.
     Los de acá son un tono más vivos, y aun así todos superan 3:1 contra el
     blanco, que es lo que WCAG pide para un elemento gráfico. */
  --dot-ok:     #0F7A55;  /* 5.3:1 */
  --dot-pend:   #F59E0B;  /* 2.2:1 — ver la nota de abajo */
  --dot-riesgo: #B3261E;  /* 6.5:1 — se deja OSCURO a propósito: el ámbar es
                             claro por naturaleza, y un rojo también claro los
                             volvería a acercar. La separación entre esos dos
                             puntos es de luminancia tanto como de tono. */
  --dot-na:     #9CA3AF;

  /* On the amber's 2.2:1. An orange ONLY reads as amber when it is light: at low
     luminance the eye calls it brown, and there it stops being distinguishable
     from the red — which is the mistake to avoid. Brightness is chosen over
     contrast, and it can be, because the dot is NOT the only carrier of state:
     every cell carries the state in words in its title and for screen readers,
     and the row has its GLOBAL chip with text. WCAG's 3:1 rule applies to
     graphics required to understand the content; here the text alternative
     exists. It is the same #F59E0B the backoffice uses, so the two portals also
     speak the same visual language. */

  /* --- Alert severity --- */
  --sev-critica:      #B3261E;  --sev-critica-on-navy: #F09A8E;
  --sev-alta:         #C2571A;  --sev-alta-on-navy:    #F0C070;
  --sev-media:        #B4690E;  --sev-media-on-navy:   #F0C070;
  --sev-baja:         #4A8BF0;  --sev-baja-on-navy:    #9FC0F7;

  /* --- Sidebar percentage indicators --- */
  /* Ambar de la estrella de fijar, sobre navy. Se llamaba --pct-medio y era el
     tono medio del porcentaje del sidebar; ese porcentaje salio el 2026-09-02 y
     el token se quedo con su unico uso real. */
  --star: #F0C070;

  /* --- Typography. Two families, no exceptions.
         Regla: si es un número que se compara o un código, va en mono. --- */
  --font-ui:   'Archivo', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* --- Radios --- */
  --radius-xs:   2px;
  --radius-sm:   5px;
  --radius-md:   7px;
  --radius-lg:   9px;
  --radius-xl:   10px;
  --radius-2xl:  12px;
  --radius-full: 999px;

  /* --- Medidas fijas --- */
  --sidebar-w: 288px;
  --drawer-w:  460px;
  --modal-w:   640px;
  --prose-max: 720px;

  /* --- Movimiento: discreto y funcional --- */
  --t: 120ms ease;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Visible focus on every interactive element. The handoff marks it as
   "a añadir en producción"; se añade desde el principio. */
:is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

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

.layout { display: flex; min-height: 100vh; }

/* El sidebar se queda quieto: position:sticky + 100vh de alto.
   Sin esto scrollea junto con la página y en una tabla de 24 empresas la
   navegación entera desaparece de la pantalla — que es lo contrario de para qué
   existe una barra de navegación.
   Sticky y no fixed: fixed lo saca del flujo y habría que reservarle el ancho a
   mano en .main. Así la columna la sigue reservando el flex.
   El overflow propio es la válvula para una ventana baja: antes de recortar el
   menú, que scrollee él solo. */
.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
  background: var(--navy);
  color: #fff;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 20px 14px;
}

.sidebar__section {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-on-navy);
  padding: 16px 10px 6px;
}

.sidebar__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-md);
  color: var(--text-on-navy-strong);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  transition: background var(--t), color var(--t);
}
.sidebar__item:hover            { background: var(--navy-700); color: #fff; }
.sidebar__item[aria-current]    { background: var(--blue);     color: #fff; }

.sidebar__divider { height: 1px; background: var(--navy-500); margin: 12px 10px; }

/* --- Collapsible menu groups ---
   Native <details>/<summary>: collapsing a menu needs no JavaScript, and the
   keyboard and screen reader already know what this is. */
.sidebar__group { }

.sidebar__summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-md);
  color: var(--text-on-navy-strong);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background var(--t), color var(--t);
  /* The default marker is removed in both engines: the chevron takes its
     place, which can be aligned and rotated. */
  list-style: none;
}
.sidebar__summary::-webkit-details-marker { display: none; }
.sidebar__summary:hover { background: var(--navy-700); color: #fff; }
/* Keyboard focus must be visible: the summary IS the control that expands. */
.sidebar__summary:focus-visible { outline: 2px solid var(--blue-200); outline-offset: -2px; }

.sidebar__chevron {
  margin-left: auto;
  display: flex;
  color: var(--text-on-navy);
  transition: transform var(--t);
}
.sidebar__group[open] .sidebar__chevron { transform: rotate(180deg); }

/* A group's items are indented to where the summary's TEXT starts (10 padding
   + 16 icon + 10 gap), so they read as children and not as another row at the
   same level. */
.sidebar__group .sidebar__item { padding-left: 36px; font-weight: 500; }

/* Inherits the text colour, so it works over the navy and over a light background. */
.icon { width: 16px; height: 16px; flex-shrink: 0; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 40px;
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}

.content { padding: 32px 40px 72px; display: flex; flex-direction: column; gap: 24px; }

/* ------------------------------------------------------------ Tipografía */

.page-title  { font-size: 29px; font-weight: 800; letter-spacing: -0.03em; line-height: 1.05; margin: 0; }
.card-title  { font-size: 18px; font-weight: 800; letter-spacing: -0.02em; margin: 0; }
.eyebrow {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.muted  { color: var(--text-muted); }
.prose  { max-width: var(--prose-max); text-wrap: pretty; }

/* Bajada de una tarjeta: la línea que explica en lenguaje llano lo que muestra
   la tabla de abajo.
   NO lleva el tope de medida de .prose. Dentro de una tarjeta que ocupa todo el
   ancho de la pantalla, un párrafo cortado en 720px deja media tarjeta vacía y
   se lee como un error de maquetación, no como una decisión tipográfica.
   text-wrap: pretty evita que la última línea quede con una sola palabra. */
/* La estrella del encabezado: el mismo control que la del sidebar, en el tamaño
   del título. Va a la DERECHA del nombre: a la izquierda desalineaba el título
   respecto de la bajada de arriba. */
.page-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.page-pin {
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  font-size: 22px;
  color: var(--text-subtle);
  transition: color 120ms ease;
}
.page-pin:hover { color: var(--blue); }
.page-pin--on   { color: var(--dot-pend); }
.page-pin:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }

.card__intro {
  margin: -8px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  text-wrap: pretty;
}
.mono   { font-family: var(--font-mono); }

/* ---------------------------------------------------------------- Piezas */

/* Flat interface: a 1px border, never a shadow. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 26px 28px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 16px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-family: var(--font-ui);
  font-size: 13.5px;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.btn--primary            { background: var(--blue); color: #fff; font-weight: 700; }

/* EL BOTON APAGADO. No existia ningun :disabled en el portal, asi que un boton
   muerto se veia identico a uno vivo: le hacias click, no pasaba nada, y eso se
   lee como "esto esta roto" — peor que un boton que se ve apagado (Pedro,
   2026-09-04). Aplica a TODOS, no solo a los formularios de soporte y consulta. */
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  filter: grayscale(0.35);
}
.btn:disabled:hover { background: var(--blue); border-color: transparent; }
.btn--secondary:disabled:hover { background: var(--surface); }

/* EL INDICADOR DE CARGA, dentro del boton.
   Lo enciende .htmx-request, que HTMX le pone al formulario mientras la peticion
   esta en vuelo — o sea sin una linea de JavaScript.

   visibility y no display en el rotulo: asi el boton conserva su ancho. Con
   display:none se encogeria al rotulo vacio y la fila de acciones saltaria justo
   cuando la persona esta esperando, que es cuando menos hay que moverle la
   pantalla. */
.btn__spinner { display: none; }
.htmx-request .btn__label { visibility: hidden; }
.htmx-request .btn__spinner {
  display: block;
  position: absolute;
  width: 15px;
  height: 15px;
  border: 2px solid currentColor;
  /* Un cuarto del anillo transparente: es lo que hace visible el giro. Un
     anillo completo girando se ve quieto. */
  border-top-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}
/* El boton pasa a ser el ancla del anillo, que va absoluto para quedar centrado
   sobre el rotulo escondido en vez de sumarse a su lado. */
.btn { position: relative; }

@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Quien pidio menos movimiento igual necesita saber que algo pasa: el anillo
   deja de girar y late. Nunca se queda sin senal. */
@media (prefers-reduced-motion: reduce) {
  .htmx-request .btn__spinner { animation: btn-pulse 1.2s ease-in-out infinite; }
  @keyframes btn-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
}

.btn--primary:hover      { background: var(--navy); }
.btn--secondary          { background: var(--surface); color: var(--text); border-color: var(--border); font-weight: 600; }
.btn--secondary:hover    { border-color: var(--blue-200); }

/* Status chip: colour + label. The label is NOT decorative — it is what
   hace legible el estado sin depender del color. */
/* LA ETIQUETA DE CLASIFICACION. Dice QUE es algo -- que productos tiene una
   sociedad --, no como va, asi que se queda FUERA de la paleta de estados: los
   colores verde, ambar y rojo son un idioma de cuatro valores y meter ahi algo
   que no tiene bueno ni malo obliga a leer la palabra para descartarlo.

   Sale del handoff, que ya distingue las dos piezas: es su «chip de tipo de
   documento» -- blue-100 sobre navy con borde blue-200 (design-system.md, tabla
   de estados). Comparte la tipografia del chip porque es la misma escala de
   cosa, y nada mas.

   Mas chico que un chip a proposito: van de a tres en una celda de tabla, y con
   el relleno del chip de estado la fila no alcanza. */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: var(--radius-full);
  border: 1px solid var(--blue-200);
  background: var(--blue-100);
  color: var(--navy);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  border: 1px solid;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.chip--ok     { background: var(--ok-bg);     border-color: var(--ok-border);     color: var(--ok-text); }
.chip--pend   { background: var(--pend-bg);   border-color: var(--pend-border);   color: var(--pend-text); }
.chip--riesgo { background: var(--riesgo-bg); border-color: var(--riesgo-border); color: var(--riesgo-text); }
.chip--na     { background: var(--na-bg);     border-color: var(--na-border);     color: var(--na-text); }
/* Sin permiso: mismo gris que NO APLICA pero HUECO, para que se distinga sin
   leer el título. Un relleno igual diría «nada que ver aquí» y no es eso. */
.chip--noaccess { background: transparent; border-style: dashed; border-color: var(--na-text); color: var(--na-text); }

/* --------------------------------------------------------------- Wordmark */

/* Wordmark según docs/design/Porticus Manual de Marca.dc.html. Los números no
   son de gusto: salen de las proporciones que el manual repite en sus cinco
   variantes (cuerpos 29, 32 y 53 px).

   - Cuerpo 22px porque el manual fija un MÍNIMO: "wordmark nunca por debajo de
     15 px de altura de mayúscula". La Archivo tiene un cap height de 0.686 em,
     así que 15 / 0.686 = 21.9. Con los 19px anteriores la mayúscula medía
     13.0px y estábamos bajo el mínimo.
   - Peso 800, no 900. El manual lo dice como regla aparte: "No cambiar el peso
     del wordmark: siempre 800". El 900 es solo para el monograma del tile.
   - Tracking -0.04em y interlineado 0.82, como las tres variantes claras.
   - Punto al 23% del cuerpo (5px) y separado un 18% (4px), alineado abajo con
     el mismo respiro de ~7% que usa el manual. */
.brand { display: inline-flex; align-items: flex-end; gap: 4px; text-decoration: none; }
.brand__name { font-size: 22px; font-weight: 800; letter-spacing: -0.04em; line-height: 0.82; color: #fff; }
/* El punto del wordmark es CUADRADO, no redondo: el manual de marca lo dice en
   la definición ("el wordmark Porticus con punto cuadrado") y en las cinco
   variantes que dibuja. Estuvo redondo hasta el 2026-09-02.
   El azul cambia con el fondo, también según el manual: #4A8BF0 sobre navy,
   #1F63E3 sobre claro. */
.brand__dot  { width: 5px; height: 5px; background: var(--blue-400); margin-bottom: 2px; }
.brand--on-light .brand__name { color: var(--navy); }
.brand--on-light .brand__dot  { background: var(--blue); }

/* Etiqueta de producto al lado del wordmark ("BPO"). Tres decisiones, y las
   tres salen del manual de marca, no del gusto:

   1. El margen izquierdo de 12 px es la ZONA DE RESPETO. El manual (§02) la
      define como la mitad de la altura del lockup y dice que ningún elemento
      entra en ella: con 22 px de wordmark, la mitad de la mayúscula es ~8 px,
      así que 12 px la respeta con holgura. El `gap: 4px` del .brand es para el
      punto, que SÍ es parte de la marca; por eso acá va un margen propio y no
      se toca el gap.
   2. Va en JetBrains Mono y no en Archivo. El manual reserva Archivo Black 900
      para "wordmark y monograma únicamente", así que escribir la etiqueta en la
      tipografía de la marca la haría parecer parte de ella. En mono se lee como
      lo que es: una anotación, del mismo modo que un RUT o un código.
   3. #4A8BF0 es el azul del manual SOBRE NAVY, el mismo del punto. No se usa el
      blanco del wordmark a propósito: con el mismo color y el mismo eje, el ojo
      lo leería como una palabra más del logotipo.

   Se alinea por la MAYÚSCULA y no por la línea base (.brand usa flex-end, que
   alinearía el pie de las dos): la etiqueta es más chica, así que colgarla del
   pie la dejaría flotando bajo el wordmark. */
.brand__tag {
  margin-left: 12px;
  align-self: center;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--blue-400);
}
.brand--on-light .brand__tag { color: var(--blue); }

/* ------------------------------------------------------------------ HTMX */

/* In-flight request indicator. Pattern inherited from Petrus (HTMX.md): without
   una acción lenta no da señal y el usuario vuelve a hacer clic. */
.htmx-indicator { opacity: 0; transition: opacity var(--t); }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }

/* ----------------------------------------------------------------- Login */

.login {
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: var(--navy);
  padding: 24px;
}
.login__card {
  background: var(--surface);
  border-radius: var(--radius-2xl);
  padding: 40px;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  text-align: center;
}

/* El icono del dominio junto al nombre de la fila. gap chico y alineado a la
   base del texto: el icono acompaña al nombre, no lo encabeza. */
/* El nombre de la fila y su bajada. Se llamaban .dt__name y .dt__sub, del
   prefijo de ObligationsTable, y quedaron huérfanas cuando esa tabla salió del
   portal (2026-09-02): ahora llevan el prefijo de quien las usa. */
.heatmap__title { font-size: 14px; font-weight: 700; letter-spacing: -0.01em; }
.heatmap__sub   { font-size: 12px; color: var(--text-subtle); }

/* --------------------------------------- Ficha de sociedad: dos columnas */

/* Izquierda quién ES la sociedad, derecha cómo VA. La derecha se lleva algo más
   de ancho porque el heatmap son doce celdas y una ficha de datos se apila sin
   sufrir.
   Cada columna es un CONTAINER: así el heatmap decide su tamaño de etiqueta por
   el ancho que realmente tiene y no por el de la ventana, que es lo que un
   media query no sabe distinguir. */
.company-split {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: 16px;
  align-items: start;
}
.company-split > * { min-width: 0; container-type: inline-size; }
/* Bajo 1200px el heatmap no cabe en media pantalla: vuelven a apilarse. */
@media (max-width: 1199px) {
  .company-split { grid-template-columns: 1fr; }
}
/* --------------------------------------------------------- Fichas (facts) */

/* Grilla que se acomoda a las tarjetas que haya. auto-fit + minmax deja que
   bajen de línea solas: estas tarjetas tienen altura variable —una identidad
   son cinco líneas y los socios pueden ser treinta— y forzarlas a una fila
   compartida las estiraría todas a la más alta. */
.fact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
  align-items: start;
}

.facts { margin: 0; display: flex; flex-direction: column; }
/* La línea separadora va ENTRE filas y no debajo de la última: un borde
   colgando bajo el último dato se lee como una fila vacía. */
.facts__row + .facts__row { border-top: 1px solid var(--border-soft); }
.facts__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
}
/* El bloque de la izquierda se lleva el ancho sobrante, para que quede UN solo
   canal de aire entre lo que se lee y el dato que cierra (regla de columnas,
   cabecera de styleguide.templ). */
.facts__head { min-width: 0; flex: 1 1 auto; }
.facts__label {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}
.facts__note {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
}
.facts__value {
  margin: 0;
  flex: 0 0 auto;
  text-align: right;
  font-size: 13px;
  color: var(--text-muted);
  white-space: nowrap;
}
.facts__value.mono { font-family: var(--font-mono); font-size: 12px; }

.facts__more { margin-top: 4px; border-top: 1px solid var(--border-soft); }
.facts__more > summary {
  cursor: pointer;
  padding: 9px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}
.facts__more > summary:hover { color: var(--blue); }

/* --------------------------------------------------------------- Errores */

/* Comparte .login__card: es la misma pieza —tarjeta blanca centrada sobre
   navy— y forkearla para cambiar tres textos es justo lo que el catálogo
   existe para evitar. Sólo se ensancha, porque acá hay dos frases y no un
   botón. */
.err { max-width: 520px; gap: 16px; }

/* El código va chico y arriba: es lo que sirve para reportar el problema, no
   lo que la persona necesita leer primero. El 404 gigante de otros sitios le
   da todo el peso visual justo a lo único sobre lo que no puede hacer nada. */
.err__code {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-subtle);
}
/* Archivo 800 con tracking −3 % e interlineado 1,05: el titular del manual de
   marca, sin inventarle una escala propia a esta pantalla. */
.err__title {
  margin: 0;
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: var(--text);
  text-wrap: balance;
}
/* La línea técnica es DATO: va en mono, para copiarla y pegarla en un mensaje.
   break-all porque una URL larga sin cortes desborda la tarjeta. */
.err__detail {
  margin: 0;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  word-break: break-all;
  text-align: left;
}
.err__actions { display: flex; flex-direction: column; gap: 10px; }

/* ------------------------------------------------------------------- KPI */

/* La fila de KPIs se reparte entre LAS TARJETAS QUE HAY, no entre cuatro
   columnas fijas. Era repeat(4, 1fr) y ninguna pantalla tenia cuatro: todas
   dejaban un hueco a la derecha que se leia como algo que no cargo (Pedro,
   2026-09-02). Con flex, tres tarjetas ocupan la fila completa y dos tambien.
   El basis de 240px es el que decide cuando bajan de linea, asi que no hace
   falta un media query. */
.kpi-grid { display: flex; flex-wrap: wrap; gap: 16px; }
.kpi-grid > * { flex: 1 1 240px; }

.kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.kpi__value { font-size: 32px; font-weight: 800; letter-spacing: -0.03em; line-height: 1; }
/* An amount needs less weight than a count; a text value, much less: at 32px
   un nombre de régimen ocupa tres líneas y desproporciona la fila entera. */
.kpi__value--amount { font-size: 27px; }
.kpi__value--text   { font-size: 19px; line-height: 1.2; letter-spacing: -0.02em; text-wrap: balance; }
.kpi__value--good   { color: var(--ok-text); }
.kpi__value--warn   { color: var(--pend-text); }
.kpi__value--bad    { color: var(--riesgo-text); }
.kpi__value--accent { color: var(--blue); }
.kpi__note { font-size: 12.5px; color: var(--text-muted); line-height: 1.4; text-wrap: pretty; }

/* --------------------------------------------------------------- Tablas */

/* Container with its own scroll: the page body never scrolls
   horizontal, la tabla sí (README del handoff, §Responsive). */
.table-scroll { overflow-x: auto; }

/* ------------------------------------------------------------- Leyenda */

/* La clave de los cinco estados. Vive al pie de ComplianceTable y de
   HistoryHeatmap, y el margen negativo la pega a lo que explica: dentro de
   .card el gap del flex son 18px, que la dejaba flotando como si fuera otra
   sección. */
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: -6px 0 0;
  padding: 0;
  list-style: none;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.legend__item { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }

/* La muestra copia la FORMA de lo que explica: punto redondo en la tabla,
   celda cuadrada en el heatmap. Ver la nota de la paleta más arriba — la forma
   codifica si el eje es continuo, así que una leyenda con la forma equivocada
   contradice justo eso. */
.legend__swatch--dot  { width: 8px;  height: 8px;  border-radius: 50%; }
.legend__swatch--cell { width: 12px; height: 12px; border-radius: var(--radius-sm); border: 1px solid; }

/* Con forma de punto la muestra es color sólido, como el punto de la tabla. */
.legend__swatch--dot.legend__swatch--ok       { background: var(--dot-ok); }
.legend__swatch--dot.legend__swatch--pend     { background: var(--dot-pend); }
.legend__swatch--dot.legend__swatch--riesgo   { background: var(--dot-riesgo); }
.legend__swatch--dot.legend__swatch--na       { background: var(--dot-na); }
.legend__swatch--dot.legend__swatch--noaccess { background: transparent; box-shadow: inset 0 0 0 1.5px var(--dot-na); }

/* Con forma de celda, relleno claro y borde saturado: idéntico al heatmap. */
.legend__swatch--cell.legend__swatch--ok       { background: var(--ok-bg);     border-color: var(--ok-border); }
.legend__swatch--cell.legend__swatch--pend     { background: var(--pend-bg);   border-color: var(--pend-border); }
.legend__swatch--cell.legend__swatch--riesgo   { background: var(--riesgo-bg); border-color: var(--riesgo-border); }
.legend__swatch--cell.legend__swatch--na       { background: var(--na-bg);     border-color: var(--na-border); }
.legend__swatch--cell.legend__swatch--noaccess { background: transparent; border-style: dashed; border-color: var(--na-text); }

/* -------------------------------------------------------------- Heatmap */

/* The heatmap and the compliance table share a PALETTE and differ in SHAPE.
   Shape encodes what the axis is: contiguous cells for a continuous axis —twelve
   months in a row, where what you read is the streak— and separate dots for
   indicators unrelated to each other, where suggesting continuity would lie.
   The colour, on the other hand, has to be the same in both or the user learns
   two languages for the same thing.

   The cells used to carry the chip-background pastels, and at that lightness the
   "on time" green and the "not applicable" grey looked nearly identical. */
/* The cells are elastic and take up ALL the available width. The minmax(0, 1fr)
   is what guarantees there is never a horizontal scrollbar: without that 0 the
   implicit minimum is the content, and a single month label is enough to
   overflow the grid. That is also why the heatmap is not wrapped in
   .table-scroll — having no scroll is a property of the layout, not something
   papered over with overflow. */
.heatmap { display: grid; grid-template-columns: 190px repeat(12, minmax(0, 1fr)); gap: 4px; align-items: center; }
.heatmap__corner {}
.heatmap__month { font-size: 9.5px; letter-spacing: 0.02em; color: var(--text-subtle); text-align: center; padding-bottom: 6px; overflow: hidden; }
.heatmap__label { padding: 6px 12px 6px 0; }
/* Light fill + SATURATED border. The border carries the state's identity —it is
   the same colour as the table's dot, so the palette stays one— and the fill
   stays quiet.
   Filling the whole cell with the saturated colour worked too, but at 26px × 12
   months a good year ended up shouting as loudly as a bad one, and green is
   precisely the news you do not need to deliver. */
.heatmap__cell  { height: 26px; border-radius: var(--radius-sm); border: 1px solid; }
.heatmap__cell--ok     { background: var(--ok-bg);     border-color: var(--dot-ok); }
.heatmap__cell--pend   { background: var(--pend-bg);   border-color: var(--dot-pend); }
.heatmap__cell--riesgo { background: var(--riesgo-bg); border-color: var(--dot-riesgo); }
/* "Not applicable" is the only state that is NOT news: it goes without a
   coloured border, like an empty slot. Its pale grey used to be nearly identical
   to the pale green of "on time" — the saturated border on the others is exactly
   what separates them now. */
.heatmap__cell--na     { background: var(--na-bg);     border-color: var(--na-border); }

/* On narrow screens the obligation label is what gives, not the cells: a name
   is still readable truncated, an 8px month is not readable at all. */
@media (max-width: 900px) {
  .heatmap { grid-template-columns: 120px repeat(12, minmax(0, 1fr)); gap: 3px; }
  .heatmap__label .heatmap__sub { display: none; }
}

/* La columna estrecha: la etiqueta cede, las celdas no. Un nombre truncado se
   sigue leyendo; un mes de 8px no. */
@container (max-width: 660px) {
  .heatmap { grid-template-columns: 120px repeat(12, minmax(0, 1fr)); gap: 3px; }
}
/* Y si ni con eso alcanza, lo que cede es la BAJADA de la fila, no las celdas:
   un nombre sin su detalle se sigue entendiendo; doce meses ilegibles, no. */
@container (max-width: 460px) {
  .heatmap { grid-template-columns: 96px repeat(12, minmax(0, 1fr)); gap: 2px; }
  .heatmap__label .heatmap__sub { display: none; }
}


/* --- Domain strip of a company's page ---
   It comes first on the screen because it answers the question you arrive with
   —"how is this company doing?"— before drilling into the month. Each block
   leads to its domain's table, with the rest of the companies alongside. */
/* Las tarjetas son de CONEXIONES, y sus nombres son largos y desparejos:
   "SII" al lado de "Dirección del Trabajo". El minmax de 190px las partía en
   dos líneas y dejaba la fecha cortada en "1 sep / 2026". A 240px el nombre
   más largo entra completo, y las que sobran bajan de fila solas. */
.domain-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}
.domain-strip__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--text);
  transition: border-color var(--t), background var(--t);
}
/* Ya no es un enlace: el hover que insinuaba que se podía entrar a alguna
   parte salió junto con el href. */
.domain-strip__head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
/* La fecha va DEBAJO del nombre y no al lado: es el dato secundario de la
   tarjeta, y en línea competiría con el chip por el mismo canal de aire. */
.domain-strip__note {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0;
  /* La fecha no se parte: "1 sep" arriba y "2026" abajo se lee como dos datos. */
  white-space: nowrap;
  color: var(--text-subtle);
}
.domain-strip__head .icon { color: var(--text-subtle); }
.domain-strip__item:hover .domain-strip__head .icon { color: var(--blue); }

/* ------------------------------------------- Multi-company compliance table */

/* One row per company and one column per obligation. With 24 companies and up
   to 12 indicators, two decisions carry all the legibility: the company stays
   frozen during horizontal scroll, and the rows are ordered by severity (that
   is SortComplianceRows' job, not the CSS's). */
.ct {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}

.ct thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--text-subtle);
  text-align: center;
  padding: 0 8px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

/* The company column stays put: without this, scrolling across to see
   Contribuciones leaves you not knowing whose row it is. */
.ct__company {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  text-align: left !important;
  font-weight: 400;
  min-width: 240px;
  padding: 10px 16px 10px 0;
  border-bottom: 1px solid var(--border);
}
.ct thead .ct__company { z-index: 3; }

.ct tbody tr:hover .ct__company,
.ct tbody tr:hover td { background: var(--bg); }
/* El periodo del detalle es un <th> y no lleva .ct__company, asi que quedaba
   fuera del hover y la banda empezaba en la segunda columna. */
.det tbody tr:hover th { background: var(--bg); }

.ct__link { display: block; text-decoration: none; color: inherit; }
.ct__name {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
.ct__link:hover .ct__name { color: var(--blue); }
.ct__meta { display: flex; gap: 8px; font-size: 10.5px; color: var(--text-subtle); margin-top: 2px; }

.ct__global { width: 96px; padding: 10px 8px; border-bottom: 1px solid var(--border); text-align: center; }
.ct__ind    { width: 58px; padding: 10px 8px; border-bottom: 1px solid var(--border); text-align: center; }

/* A dot instead of a chip: in a grid of up to 12 columns the label does not
   fit. What it does carry —and the backoffice does not— is the state in words,
   in the title and for screen readers: colour cannot be the only thing.
   8px, the same as the backoffice. 10px was tried to help tell the hue apart and
   came out worse: it fattens the row without fixing anything, because the
   problem was the colour and not the size. */
.ct__dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  vertical-align: middle;
}
.ct__dot--ok     { background: var(--dot-ok); }
.ct__dot--pend   { background: var(--dot-pend); }
.ct__dot--riesgo { background: var(--dot-riesgo); }
.ct__dot--na     { background: var(--dot-na); }
.ct__dot--noaccess { background: transparent; box-shadow: inset 0 0 0 1.5px var(--dot-na); }

/* El punto que abre el detalle. El area de click de 8px es inaceptable —y el
   minimo tactil son 24—, asi que el enlace se agranda con un pseudo-elemento
   transparente en vez de con padding: padding movería el punto dentro de la
   celda y desalinearia la columna. */
a.ct__dot--link { position: relative; cursor: pointer; }
a.ct__dot--link::after {
  content: "";
  position: absolute;
  inset: -8px;
}
a.ct__dot--link:hover  { box-shadow: 0 0 0 4px var(--blue-100); }
a.ct__dot--link:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

/* ------------------------------------------------------------ Modal

   El detalle de un indicador, encima de la tabla. <dialog open> pintado por el
   servidor: sin showModal() no está en el top layer, asi que el z-index y el
   scrim son nuestros. A cambio no hay una linea de JavaScript y el ✕ es un
   enlace, que funciona igual sin HTMX. */
/* Cerrado por el navegador (Escape o click afuera) solo se oculta el <dialog>:
   esta capa seguiría fija encima, oscureciendo y bloqueando la pagina. Con
   :has() desaparece junto con el. El ✕ es otro camino —vacia el hueco entero—
   y no necesita esta regla, pero tampoco le estorba. */
.modal:not(:has(dialog[open])) { display: none; }
.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
}
/* El scrim es SOLO el fondo oscuro, un <div> inerte. Cerrar al hacer click
   afuera lo pone el navegador con closedby="any" en el <dialog>: siendo un
   enlace hacia una peticion al servidor para cerrar algo que ya estaba en
   pantalla. */
.modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(15, 42, 84, 0.32);
  backdrop-filter: blur(2px);
}
.modal__box {
  position: relative;
  /* --modal-w (640px) es el ancho de un modal de FORMULARIO, que es para lo
     que el sistema lo definio. Este es un modal de TABLA: cuatro columnas y una
     de ellas con parrafos del SII de cinco lineas. A 960 se veia apretado; 1200
     deja el mensaje en tres lineas y sigue por debajo del limite de largo de
     linea legible. Mas ancho no: la prosa empieza a costar seguirla. */
  width: min(1200px, 100%);
  max-height: calc(100vh - 80px);
  overflow: auto;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-2xl);
  background: var(--surface);
  box-shadow: 0 24px 64px rgba(15, 42, 84, 0.18);
  color: inherit;
}
.modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 24px 28px 18px;
  border-bottom: 1px solid var(--border);
}
/* Un buscador que vive DIRECTO en el diálogo —fuera del formulario, porque
   SearchBox es un <form> y HTML no anida formularios— no hereda el respiro del
   .form, así que la caja llegaba de borde a borde mientras la lista de abajo
   respetaba los 28px. El mismo costado que el título y que el formulario; abajo
   nada, que ese espacio lo pone el padding superior del .form. */
.modal__box > .searchbox { padding: 18px 28px 0; }
.modal__title { font-size: 20px; font-weight: 800; letter-spacing: -0.025em; margin: 0; }
.modal__sub   { font-size: 12px; color: var(--text-muted); margin: 4px 0 0; }
.modal__scope { font-size: 12px; color: var(--text-subtle); margin: 6px 0 0; }
.modal__close {
  flex: none;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-md);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 14px;
}
.modal__close:hover { background: var(--bg); color: var(--text); }

/* El modal de FORMULARIO, que es para lo que --modal-w se definio: una columna
   de campos, no una tabla. El de tabla es el ancho por defecto de .modal__box
   por historia —fue el primero— y no al reves. */
.modal__box--form { width: min(var(--modal-w), 100%); }

/* --- Lista de sociedades desconectadas ------------------------------------
   Una lista y no una tabla: son pocas filas y solo hay dos datos por fila, asi
   que las lineas de una tabla serian ruido. La causa va a la derecha porque es
   lo que se compara entre filas; el nombre se lleva el ancho sobrante. */
/* Un bloque por organismo. El rotulo va arriba y no en cada fila porque el
   arreglo es POR ORGANISMO: "se cayo Previred" se resuelve de una vez para las
   tres sociedades, y repetirlo en cada fila haria leer el mismo problema tres
   veces. */
.conn-group { margin-top: 18px; }
.conn-group:first-of-type { margin-top: 10px; }
.conn-group__source {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.conn-list { margin: 4px 0 0; padding: 0; list-style: none; }
.conn-list__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0;
  border-top: 1px solid var(--border-soft);
}
.conn-list__name { display: flex; align-items: baseline; gap: 10px; font-weight: 600; color: var(--text); text-decoration: none; }
.conn-list__name:hover { color: var(--blue); }
.conn-list__id { font-size: 12px; color: var(--text-muted); font-weight: 400; }

/* --- Formulario de soporte ------------------------------------------------
   Una sola columna, porque son tres campos y ponerlos en dos hace que la vista
   tenga que decidir por donde entra. */
/* --- Formularios y pantallas de administracion (BPO) ----------------------

   Todo lo que sigue hasta la tabla de cumplimiento nacio con la pantalla de
   Empresas del backoffice, que es la primera del producto con mas formulario
   que lectura. Tres capas, de mas generica a mas concreta:

     .form .field .input .select      las primitivas de un formulario
     .dialog .rowlist                 un modal que lista algo y ademas lo edita
     .admin-block .admin-bar          la pantalla: buscador, acciones y tabla

   El prefijo .sup__ de mas arriba hace lo mismo para el formulario de soporte y
   NO es un alias: existe en produccion desde antes y se generaliza el dia que
   se toque esa pantalla, no hoy. Las medidas son las mismas a proposito, para
   que los dos se vean igual mientras conviven.
   ------------------------------------------------------------------------- */

/* FORMULARIOS — las primitivas genericas.
   Son nuevas y no un renombre de .sup__*: ese prefijo es del formulario de
   soporte, existe en produccion y se generaliza el dia que se toque, no hoy.
   Las medidas son las mismas a proposito, para que los dos se vean igual
   mientras conviven. */
.form { display: flex; flex-direction: column; gap: 18px; padding: 22px 28px 26px; margin: 0; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field__label { display: block; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); }
.field__optional { font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text-subtle); }
.field__hint { font-size: 12px; color: var(--text-muted); line-height: 1.5; }
/* El error de un campo va PEGADO al campo y no arriba del formulario: con seis
   campos, un mensaje en la cabecera obliga a buscar cual. */
.field__error { font-size: 12px; color: var(--riesgo-text); font-weight: 600; }
.input, .select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
}
.input:focus-visible, .select:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }
/* Un campo de VARIAS LINEAS, con la misma caja que el resto. La altura es fija
   y el resize esta apagado a proposito: el dialogo es una ventana de tamano
   conocido, y una caja que el usuario puede estirar empuja los botones fuera de
   la pantalla. Tres lineas de texto — lo que cabe en una descripcion util —, y
   lo que sobra se desplaza dentro de la caja. */
.input--area {
  height: 76px;
  resize: none;
  overflow-y: auto;
  scrollbar-width: thin;
}
.input[readonly] { background: var(--bg); color: var(--text-muted); }
.field--bad .input, .field--bad .select { border-color: var(--riesgo-border); }
.form__error {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--riesgo-border);
  border-radius: var(--radius-md);
  background: var(--riesgo-bg);
  color: var(--riesgo-text);
  font-size: 13px;
}
/* El AVISO no es el error: es ambar y no rojo, y deja seguir. Lo que no puede
   hacer es parecerse tanto a un error que la gente aprenda a cerrarlo sin
   leerlo, ni tan poco que pase de largo. */
.form__warn {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--pend-border);
  border-radius: var(--radius-md);
  background: var(--pend-bg);
  color: var(--pend-text);
}
.form__warn-lead { margin: 0; font-size: 13px; }
.form__warn-hint { margin: 4px 0 0; font-size: 12px; opacity: 0.9; line-height: 1.45; }

.form__done { margin: 0; font-size: 16px; font-weight: 700; }
.form__actions { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }

/* Un dialogo que lista algo y ademas lo edita: la lista arriba, el formulario
   abajo, separado por una linea. Con tres contactos el trabajo entero cabe en
   pantalla, y un formulario escondido tras un boton convierte el caso comun en
   dos pasos. */
.dialog { display: flex; flex-direction: column; }
/* El vacio de un dialogo necesita el MISMO margen lateral que la lista a la que
   reemplaza: ui.EmptyState es un <p> pelado a proposito —el hueco lo pone quien
   lo usa— y sin esto el texto queda pegado al borde del cuadro, en un cinturon
   sin aire entre la cabecera y el formulario. */
.dialog__empty { padding: 18px 28px; }
/* La nota al pie de un dialogo: UNA, con el mismo margen lateral que la lista.
   Tres parrafos sueltos con aire entre medio compiten con el contenido y se
   leen como tres avisos; lo que hacen es esconder el que importa. */
.dialog__note { margin: 0; padding: 0 28px 20px; font-size: 12px; color: var(--text-muted); line-height: 1.5; }
/* El registro de lo que ya paso. Va en gris y con su titulo chico porque es
   evidencia, no una segunda lista de cosas que hacer: lo que se opera esta
   arriba. */
.dialog__log { border-top: 1px solid var(--border); padding: 16px 28px 20px; background: var(--bg); }
.dialog__log-title { margin: 0 0 10px; font-family: var(--font-mono); font-size: 10px; font-weight: 500; letter-spacing: 0.1em; color: var(--text-subtle); }
.dialog__log-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.dialog__log-row { display: flex; align-items: baseline; gap: 10px; font-size: 12.5px; }
.dialog__log-name { font-weight: 600; color: var(--text); }
.dialog__log-when { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted); }

.rowlist { list-style: none; margin: 0; padding: 14px 28px; display: flex; flex-direction: column; gap: 2px; }
.rowlist__row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border-soft); }
.rowlist__row:first-child { border-top: 0; }
.rowlist__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rowlist__name { font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rowlist__note { font-size: 11.5px; color: var(--text-muted); }
.rowlist__row form { margin: 0; }
/* El display:flex de .rowlist__name es para el chip de estado que va al lado del
   nombre: sin el queda pegado a la ultima letra. */

/* LA ACCION DE UNA FILA: un control y su boton, en linea.
   .form a secas es una COLUMNA --los formularios de esta casa apilan campos-- y
   ahi el control quedaba encima del boton, duplicando el alto de cada fila.

   Los dos anchos son fijos y no de contenido, y ahi esta todo el asunto: con
   anchos automaticos cada fila arma su propia columna --"Activar" es mas corto
   que "Suspender", asi que su fecha se corre a la derecha-- y tres filas seguidas
   se leen como tres cosas distintas en vez de una lista. */
.rowact { display: flex; flex-direction: row; align-items: center; gap: 8px; flex: none; }
.rowact .btn { min-width: 6.75rem; justify-content: center; }
/* Lo que ocupa el lugar de la accion cuando no hay accion: la razon, en gris y
   alineada a la derecha como estaria el boton. */
.rowact__fixed { flex: none; max-width: 15rem; text-align: right; font-size: 12px; color: var(--text-muted); line-height: 1.4; }
/* El control de una fila va COMPACTO. El .input de la casa esta dimensionado
   para un formulario en columna (14px y 10px de relleno), y a esa altura una
   lista de tres filas ocupa la pantalla entera. */
.rowact .input {
  width: 8.75rem;
  padding: 6px 10px;
  font-size: 12.5px;
  font-family: var(--font-mono);
}
/* El formulario que sigue a una lista: misma columna, con la linea que separa
   "lo que hay" de "agregar otro". */
.form--inset { border-top: 1px solid var(--border); padding-top: 20px; }

/* La barra sobre la tabla: lo que se busca a la izquierda, lo que se crea a la
   derecha, y entre medio nada.

   align-items: flex-start y no center: si alguna vez vuelve a colgar una ayuda
   bajo el input, centrar la fila alinearia los botones contra el bloque ENTERO
   —input mas ayuda— y quedarian unos pixeles mas abajo que la caja con la que
   tienen que cuadrar. Lo que se alinea es siempre el primer renglon. */
.admin-bar { display: flex; align-items: flex-start; gap: 16px 24px; flex-wrap: wrap; }
/* El buscador se lleva todo el ancho que sobra hasta los botones. El aire entre
   los dos lo pone el gap de la barra y no un margen del input: uno solo, en un
   lugar, que es el mismo que separa las dos filas cuando la barra se parte. */
.admin-bar .searchbox { flex: 1 1 280px; }
/* margin-left: auto y no justify-content: space-between en el padre: con
   space-between, cuando la barra se parte en dos lineas el boton queda pegado a
   la IZQUIERDA de la segunda, debajo del buscador. Con margen automatico se va
   a la derecha en los dos casos. */
.admin-bar__actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* LA ALTURA DE LOS CONTROLES ES UNA SOLA. Medido el 2026-09-21: el input del
   buscador daba 34px y los botones 40px, los dos arrancando en la misma linea,
   asi que la fila terminaba 6px descuadrada — se ve como "desalineado" aunque
   cada pieza este bien puesta.
   Va acotado a .admin-bar y no a .searchbox__input: el buscador del RCV y el de
   cumplimiento no tienen un boton al lado, asi que ahi los 34px no descuadran
   nada y subirlos seria tocar dos pantallas en produccion por un problema que
   no tienen. */
.admin-bar .searchbox__input { min-height: 40px; padding: 10px 14px; font-size: 13.5px; }
.admin-bar__actions .btn { min-height: 40px; }

.sup { display: flex; flex-direction: column; gap: 20px; padding: 22px 28px 26px; margin: 0; }
.sup__label { display: block; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); }
.sup__optional { font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text-subtle); }
.sup__field { display: flex; flex-direction: column; gap: 8px; }
.sup__hint { font-size: 12px; color: var(--text-muted); line-height: 1.5; }
.sup__error {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--riesgo-border);
  border-radius: var(--radius-md);
  background: var(--riesgo-bg);
  color: var(--riesgo-text);
  font-size: 13px;
}
/* Los dos tipos son TARJETAS y no un <select>: con dos opciones un desplegable
   esconde la mitad de la pregunta detras de un click, y la ayuda de cada una
   —que es lo que evita que se elija mal— no cabria adentro. */
.sup__types { display: flex; flex-direction: column; gap: 8px; border: 0; padding: 0; margin: 0; }
.sup__types .sup__label { margin-bottom: 4px; padding: 0; }
.sup__type {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: border-color var(--t), background var(--t);
}
.sup__type:hover { border-color: var(--blue-200); }
/* :has() y no una clase que ponga el servidor: quien esta elegido lo sabe el
   input, y pintarlo desde Go obligaria a repintar el formulario en cada click. */
.sup__type:has(input:checked) { border-color: var(--blue); background: var(--blue-100); }
.sup__type input { margin-top: 2px; accent-color: var(--blue); }
.sup__type-name { display: block; font-size: 14px; font-weight: 600; }
.sup__type-hint { display: block; margin-top: 2px; font-size: 12px; color: var(--text-muted); }
/* VARIANTE COMPACTA de los tipos, para cuando son cuatro y no dos.
   Las tarjetas apiladas cuestan ~100px cada una: con dos opciones eso esta
   bien, pero con cuatro empujan el area de texto fuera de la pantalla, y el
   area de texto es donde de verdad se trabaja. Es un MODIFICADOR y no un
   componente nuevo: la tarjeta sigue siendo la misma, cambia como se
   distribuye.

   REJILLA FIJA de dos columnas, y NO un flex-wrap: con flex, un ancho que
   dependa del contenido hace que las pastillas cambien de fila al elegir otra,
   y las opciones saltan bajo el cursor. Dos columnas iguales no se mueven
   nunca.

   Y las cuatro ayudas se muestran SIEMPRE, no solo la elegida: mostrar solo
   una obliga a que la celda crezca al marcarla, que es el mismo salto por otra
   via. A dos columnas caben, y son justo lo que evita elegir mal. */
.sup__types--compact { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
/* La leyenda ocupa las dos columnas: es la pregunta, no una opcion mas. */
.sup__types--compact .sup__label { grid-column: 1 / -1; margin-bottom: 0; }
.sup__types--compact .sup__type { flex-direction: column; align-items: stretch; gap: 1px; padding: 9px 12px; }
.sup__types--compact .sup__type-name { font-size: 13px; }
.sup__types--compact .sup__type-hint { font-size: 11.5px; line-height: 1.4; margin-top: 0; }
/* El radio se esconde: la pastilla entera ES el control, y su estado se lee en
   el borde y el fondo. El input sigue en el DOM, asi que el teclado y los
   lectores de pantalla lo ven igual. */
.sup__types--compact .sup__type input { position: absolute; opacity: 0; pointer-events: none; }
.sup__types--compact .sup__type:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: 1px; }

.sup__text {
  width: 100%;
  min-height: 132px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  resize: vertical;
}
.sup__text:focus-visible, .sup__file:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }
.sup__file { font-size: 13px; color: var(--text-muted); }
.sup__actions { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
.sup__done { margin: 0; font-size: 16px; font-weight: 700; }

/* La tabla del detalle. Hereda de .ct el cuerpo y solo redefine anchos y
   alineacion: DETALLE se lleva el espacio porque es la unica columna con prosa.

   Se llama `det` y NO `dt`: `.dt` ya era la grilla de ObligationsTable
   (display: grid, mas arriba en este archivo). Reusar el nombre convirtio esta
   tabla en una grilla y le partio las columnas — cabecera y cuerpo cada una por
   su lado. Antes de inventar un prefijo, buscarlo acá. */
/* El aire lateral va en el contenedor con scroll, no en la <table>:
   padding sobre una tabla no lo respetan igual todos los motores. */
.modal__box .table-scroll { padding: 0 28px 24px; }
.modal__empty { padding: 24px 28px 28px; }
/* table-layout: fixed y anchos declarados. En automatico el navegador reparte
   segun el CONTENIDO, y los cinco indicadores tienen contenidos opuestos: el
   F22 trae parrafos del SII y las contribuciones una sola palabra ("VENCIDA").
   El resultado era que en contribuciones DETALLE se llevaba 800px vacios y la
   direccion se apilaba en cinco lineas en una columna de 110px. Con anchos
   fijos la tabla se ve igual en los cinco, que es de lo que se trata tener un
   componente y no cinco. */
.det { table-layout: fixed; }
.det thead th {
  text-align: left;
  padding: 14px 20px 10px 0;
  /* La cabecera comparte las clases de ancho con el cuerpo, pero NO su
     tipografia: manda el estilo de .ct thead th. */
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--text-subtle);
}

.det td,
.det tbody th {
  /* Arriba y no al medio: el estado tiene que quedar a la altura de la PRIMERA
     linea del mensaje. Centrado, en una fila de cinco lineas, el chip flota en
     el medio y deja de leerse como el estado de ese periodo. */
  vertical-align: top;
  padding: 16px 20px 16px 0;
  border-top: 1px solid var(--border);
}


.det__period {
  /* ANCHOS EN PORCENTAJE, no pixeles. Con table-layout fixed el sobrante se
     reparte proporcionalmente entre las columnas que declaran ancho, asi que en
     pixeles el aire quedaba esparcido por toda la fila. Acá hay UNA columna en
     `auto` —la ultima de la izquierda— que se lleva todo el sobrante, y el
     resultado es un solo canal de aire entre el grupo izquierdo y el derecho. */
  width: 26%;
  text-align: left;
  /* La identidad de la fila: es lo que se busca con la vista antes de leer. */
  font-size: 14px;
  font-weight: 700;
  color: var(--navy);
}
.det__state  { width: 13%; }
.det__date   { width: 14%; color: var(--text-muted); font-size: 12px; }
.det__detail { line-height: 1.5; }

/* --- Quien absorbe el sobrante: la ULTIMA columna de la izquierda que exista.
   Dárselo a la primera dejaba el chip a media fila de su propio concepto. --- */
.det--prose .det__detail { width: auto; }
.det--prose .det__period { width: 14%; }  /* con prosa, la identidad es un año */
.det--dated .det__date   { width: auto; }
.det:not(.det--prose):not(.det--dated) .det__state { width: auto; }

/* --- El grupo de la derecha. Números y fechas de cierre, alineados a la
   derecha para que los digitos cuadren y la tabla cierre contra el borde. --- */
.det__amount {
  width: 15%;
  text-align: right;
  /* El padding de .det td es a la izquierda; acá tiene que ir a la derecha o el
     numero queda pegado a la columna siguiente. */
  padding-right: 24px;
  font-size: 13px;
}
.det__updated {
  width: 15%;
  white-space: nowrap;
  text-align: right;
  padding-right: 0;
  color: var(--text-muted);
  font-size: 12px;
}
/* Las columnas de descarga: el icono centrado bajo su rotulo, y un canal a la
   IZQUIERDA para separarlas de ACTUALIZADO —que esta alineado a la derecha y
   sin el quedaba pegado a "CERTIFICADO" en la cabecera—. Van al final, asi que
   la ultima cierra contra el borde. */
.det__file { width: 9%; text-align: center; padding-right: 0; padding-left: 14px; }
/* La cabecera hereda la alineacion de su columna, NUNCA el tamaño de letra:
   .ct thead th la fija en 10px mono, y redefinirla dejaba un encabezado mas
   grande que los demas. */
.det thead .det__amount  { text-align: right; padding-right: 24px; }
.det thead .det__updated { text-align: right; padding-right: 0; }
.det thead .det__file    { text-align: center; padding-right: 0; padding-left: 14px; }

.det__dl {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-md);
  color: var(--text-muted);
}
.det__dl:hover { background: var(--bg); color: var(--blue); }
.det__dl:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
/* La celda sin dato. Ni "$0" ni en blanco: el guion dice que se miro y no habia,
   que no es lo mismo que una celda que no se pinto. */
.det__none { color: var(--text-disabled); }

/* --- Un hallazgo repetido: el mensaje una vez, los sujetos al desplegar. --- */
.det__finding + .det__finding { margin-top: 8px; }
.det__finding > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.det__finding > summary::-webkit-details-marker { display: none; }
/* El triangulo lo dibujamos nosotros para poder girarlo y alinearlo con la
   linea base del texto; el nativo cambia de forma entre navegadores. */
.det__finding > summary::before {
  content: "›";
  flex: none;
  color: var(--text-subtle);
  transition: transform var(--t);
}
.det__finding[open] > summary::before { transform: rotate(90deg); }
.det__count {
  flex: none;
  padding: 1px 7px;
  border-radius: var(--radius-full);
  background: var(--bg);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
}
/* Los RUT: monoespaciados para que se comparen y se copien, y con el sangrado
   del triangulo para que se lean colgando de su mensaje. */
.det__who {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.6;
}
.det__finding[open] > .det__who { padding: 6px 0 2px 18px; }

@media (max-width: 720px) {
  .modal { padding: 0; align-items: flex-end; }
  .modal__box { width: 100%; max-height: 88vh; border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; }
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------- SearchBox */

/* El buscador de una pantalla, sobre fondo claro. NO reusa .sidebar__search:
   ése vive sobre navy y sus colores son los del menú. Comparten la forma y
   nada más — un mismo control sobre dos fondos son dos controles. */
.searchbox { margin-bottom: 16px; }
/* El envoltorio de ComplianceTable: reproduce la columna de .card para que
   agrupar la tabla y su leyenda —necesario para que el swap de HTMX tenga una
   raíz— no cambie la separación entre las dos. Sin esto la leyenda se sube
   encima de la última fila, porque su margin-top negativo está calculado contra
   el gap de la tarjeta. */
.ct-block { display: flex; flex-direction: column; gap: 18px; }
.searchbox__form { position: relative; display: flex; }
.searchbox__input {
  flex: 1 1 280px;
  background: #fff;
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font-family: var(--font-ui);
  font-size: 13px;
  width: 100%;
}
.searchbox__input::placeholder { color: var(--text-muted); }
.searchbox__input:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
/* Mientras la búsqueda viaja se marca el borde y aparece "Buscando…" ENCIMA del
   input: va position:absolute para no reservar alto, porque un indicador que
   empuja la tabla cada 150 ms de tecleo se siente peor que no tener ninguno. */
.searchbox__form.htmx-request .searchbox__input { border-color: var(--blue); }
.searchbox__busy {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.searchbox__hint {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--text-muted);
}

/* ------------------------------------------------------- Sidebar v2 */

.sidebar__search {
  background: var(--navy-700);
  border: 1px solid var(--navy-500);
  color: #fff;
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font-family: var(--font-ui);
  font-size: 13px;
  width: 100%;
}
.sidebar__search::placeholder { color: var(--text-on-navy); }

/* The search box is Active Search: while the request is in flight the border is
   marked and "Buscando…" appears over the input. It is position:absolute so it
   reserves no height: an indicator that pushes the list down every 150 ms of
   typing feels worse than having no indicator at all. */
.sidebar__searchbox { position: relative; display: flex; }
.sidebar__searchbox.htmx-request .sidebar__search { border-color: var(--blue); }
.sidebar__searching {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--blue-200);
  pointer-events: none;
}

/* The company list is the fragment HTMX replaces —on search and on pin— so it
   needs to be its own element with an id. It repeats the sidebar's column layout
   because it is now one nesting level deeper. */
.sidebar__companies { display: flex; flex-direction: column; gap: 4px; }

/* The row carries the company and its star. The star sits outside the <a>
   because it is a different action: a button inside a link is not valid HTML and
   the click would be ambiguous. */
.sidebar__row { display: flex; align-items: center; gap: 2px; }
.sidebar__row > form { display: flex; }
.sidebar__row .sidebar__company { flex: 1; min-width: 0; }

.sidebar__pin {
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: var(--radius-md);
  font-size: 15px;
  line-height: 1;
  color: var(--navy-500);
  transition: color var(--t), background var(--t);
}
.sidebar__pin:hover     { color: var(--star); background: var(--navy-700); }
.sidebar__pin--on       { color: var(--star); }

.sidebar__company { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border-radius: var(--radius-md); color: var(--text-on-navy-strong); text-decoration: none; transition: background var(--t); }
.sidebar__company:hover { background: var(--navy-700); color: #fff; }
.sidebar__company[aria-current] { background: var(--blue); color: #fff; }
.sidebar__company-name { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar__company-meta { display: flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: 10px; color: var(--text-on-navy); }
.sidebar__company[aria-current] .sidebar__company-meta { color: var(--blue-200); }

/* The sidebar's empty state has to say something: a heading with nothing under
   lee como que la página no cargó. */
.sidebar__empty { padding: 4px 10px 8px; font-size: 12.5px; color: var(--text-on-navy); line-height: 1.4; }

/* --- Selector de año: el único control de período del portal ---
   Parece un <select> pero es un <details> con enlaces adentro: un select nativo
   necesitaría un botón de enviar o JavaScript, y así cada año sigue siendo una
   URL. Mismo idioma nativo que los grupos del menú y el menú de usuario. */
.yearsel { position: relative; }

.yearsel__current {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px 7px 12px;
  min-width: 84px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  list-style: none;
  transition: border-color var(--t);
}
.yearsel__current::-webkit-details-marker { display: none; }
.yearsel__current:hover { border-color: var(--blue-200); }
.yearsel__current:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.yearsel__current .icon { width: 14px; height: 14px; margin-left: auto; color: var(--text-subtle); transition: transform var(--t); }
.yearsel[open] .yearsel__current { border-color: var(--blue); }
.yearsel[open] .yearsel__current .icon { transform: rotate(180deg); }

/* El menú flota: si empujara el layout, abrirlo movería el título de la página. */
.yearsel__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  min-width: 100%;
  display: flex;
  flex-direction: column;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(16, 32, 64, 0.10);
}
.yearsel__item {
  padding: 7px 10px;
  border-radius: calc(var(--radius-md) - 3px);
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-muted);
  text-decoration: none;
  transition: background var(--t), color var(--t);
}
.yearsel__item:hover { background: var(--bg); color: var(--text); }
.yearsel__item[aria-current] { color: var(--blue); font-weight: 600; }

/* --- Menú de usuario, al pie del sidebar ---
   margin-top:auto lo empuja abajo sin importar cuántas empresas haya arriba. */
/* El pie: soporte y la cuenta, juntos y pegados abajo. El margin-top:auto está
   acá y NO en .usermenu — ahí dentro empujaba solo la cuenta, y soporte se
   quedaba arriba con un hueco de 300px en medio. */
.sidebar__foot { margin-top: auto; }
.usermenu { position: relative; padding-top: 4px; }

.usermenu__current {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  cursor: pointer;
  list-style: none;
  transition: background var(--t);
}
.usermenu__current::-webkit-details-marker { display: none; }
.usermenu__current:hover { background: var(--navy-700); }
.usermenu__current:focus-visible { outline: 2px solid var(--blue-200); outline-offset: -2px; }
.usermenu__current .icon { width: 14px; height: 14px; margin-left: auto; color: var(--text-on-navy); flex-shrink: 0; }
.usermenu[open] .usermenu__current { background: var(--navy-700); }

.usermenu__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--blue);
  color: #fff;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
}
.usermenu__email {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-on-navy-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.usermenu__email--dark { color: var(--text); }

/* Se abre hacia ARRIBA: el bloque ya está pegado al borde inferior. */
.usermenu__menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(16, 32, 64, 0.18);
  overflow: hidden;
}
.usermenu__head { display: flex; align-items: center; gap: 10px; padding: 12px; border-bottom: 1px solid var(--border); }
.usermenu__item {
  display: block;
  padding: 11px 12px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: background var(--t);
}
.usermenu__item:hover { background: var(--bg); }

/* Header breadcrumb */
.breadcrumb { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.12em; color: var(--text-subtle); text-transform: uppercase; }

/* Cabecera ordenable de la tabla de cumplimiento. Es un <a> con href: el orden
   es una URL que se puede compartir y el camino sin JavaScript sale gratis. */
.ct__sort {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: inherit;
  text-decoration: none;
  border-radius: 4px;
  padding: 2px 4px;
  margin: -2px -4px;
}
.ct__sort:hover { color: var(--blue); background: var(--bg); }
.ct__sort:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.ct__arrow { font-size: 9px; color: var(--blue); }
/* La columna ordenada se distingue sin depender solo de la flecha. Va como
   clase y no como selector sobre aria-sort del padre, porque la tabla de
   obligaciones es un grid de divs y ahí aria-sort no aplica. */
.ct__sort--on { color: var(--blue); }

/* La acción del header: consultar al contador.
   Vive acá y no al pie del menú junto a soporte técnico — para un cliente los
   dos nombres son sinónimos, y vecinos mandan la duda contable al equipo de
   desarrollo. Ver el comentario en shell.templ. */
.header__tools { display: flex; align-items: center; gap: 12px; }

.hdr-action {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  background: var(--blue);
  border: 1px solid var(--blue);
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--t), border-color var(--t);
}
.hdr-action:hover { background: var(--navy, #10214A); border-color: var(--navy, #10214A); }
.hdr-action:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.hdr-action .icon { width: 15px; height: 15px; }

/* El selector de sociedad del formulario de consulta. Mismo cuerpo que el
   textarea de al lado: los dos son campos del mismo formulario. */
.sup__select {
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
}
.sup__select:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }

/* --------------------------------------------- Tabs, Picker, DataTable, Pager
 *
 * Las cuatro piezas de una pantalla de documentos: el RCV (libro de compras y
 * ventas) es la primera que las usa. A diferencia de la tabla de cumplimiento,
 * acá no hay estados ni leyenda: hay plata, y lo que manda es que las columnas
 * de cifras se lean digito sobre digito.
 */

.tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 18px;
  overflow-x: auto;
}
.tabs__tab {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 14px;
  text-decoration: none;
  color: var(--text-muted);
  font-size: 13.5px;
  white-space: nowrap;
  /* El borde va SIEMPRE, transparente cuando no es la pestana activa: si
     apareciera solo en la activa, cambiar de pestana movería la fila 2px. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tabs__tab:hover { color: var(--text); background: var(--bg); }
.tabs__tab--on {
  color: var(--navy);
  font-weight: 600;
  border-bottom-color: var(--blue);
}
.tabs__tab:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.tabs__count { font-size: 10.5px; color: var(--text-subtle); }
.tabs__tab--on .tabs__count { color: var(--blue); }

/* Los selectores de sujeto —que empresa, que mes— arriba de la tabla. */
.pickers { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end; margin-bottom: 16px; }
.picker { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.picker__label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.picker__select {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 13px;
  padding: 9px 12px;
  max-width: 100%;
}
.picker__select:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.picker__go { margin-top: 6px; }
/* El selector de empresa es el sujeto de la pantalla: se lleva el ancho. */
.picker--wide { flex: 1 1 320px; min-width: 0; }
.picker--wide .picker, .picker--wide .chooser { width: 100%; }
/* Los dos selectores se alinean por ARRIBA cuando el de la izquierda es un
   buscador con lista: alinear por abajo dejaría el del período flotando al
   final de una lista de diez sociedades. */
.pickers { align-items: flex-start; }

/* La pantalla de documentos reproduce la columna de .card, igual que .ct-block:
   agrupar todo bajo una raiz —que el swap de HTMX necesita— no puede cambiar
   las separaciones que la tarjeta ya daba. */
/* La raiz de una pantalla de administracion: buscador, tabla y paginador en
   una columna. Misma forma que .rcv-block y nombre propio porque no son la
   misma pantalla: el dia que una de las dos cambie el ritmo, la otra no. */
.admin-block { display: flex; flex-direction: column; gap: 18px; }
.admin-block .searchbox { margin-bottom: 0; }

.rcv-block { display: flex; flex-direction: column; gap: 18px; }
/* Los controles y su tabla van juntos: el gap de la columna es para separar
   bloques, no para despegar un selector de lo que filtra. */
.rcv-block .pickers, .rcv-block .tabs, .rcv-block .searchbox { margin-bottom: 0; }

/* El envoltorio de DataTable, misma razon que .ct-block: el target del swap
   tiene que ser la raiz de lo que manda el servidor, y reproducir la columna de
   .card para que agrupar no cambie las separaciones. */
.dt-block { display: flex; flex-direction: column; gap: 18px; }

.dt {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}
.dt__h {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--text-subtle);
  text-align: left;
  padding: 0 12px 10px 0;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.dt__c {
  padding: 9px 12px 9px 0;
  border-bottom: 1px solid var(--border-soft);
  text-align: left;
  vertical-align: top;
}
/* Las cifras a la derecha y en tabular: sin esto los digitos de ancho variable
   desalinean una columna de montos aunque este alineada a la derecha. */
.dt__num { text-align: right; padding-right: 0; padding-left: 16px; }
/* LAS COLUMNAS OBEDECEN SU ANCHO. Sin esto la tabla ensancha la columna para que
   quepa el valor mas largo, asi que el recorte de .dt__c--clip no llega a
   pasar nunca. Se pide a proposito y no viene por defecto: para una tabla de
   cifras, que la columna crezca hasta el monto mas largo es lo correcto.

   EL min-width DEVUELVE EL SCROLL. Con table-layout fijo la tabla nunca es mas
   ancha que su contenedor: en una ventana angosta no aparece la barra, se
   aplastan las columnas -- y las que llevan un chip o una lista no pueden
   encogerse sin mentir. Con el minimo, por debajo de ese ancho vuelve a mandar
   el overflow-x de .table-scroll, que es lo correcto.

   820px son los medidos: a ese ancho las cinco columnas de la pantalla de
   empresas todavia no recortan nada que no sea un nombre. Mas alto que eso y la
   barra aparece en una tabla que cabe -- que es como quedo la primera version,
   con 880. */
.dt--fixed { table-layout: fixed; min-width: 820px; }
/* Un nombre que no cabe se CORTA, no se parte en dos lineas. En una lista de
   cincuenta filas lo que permite barrerla es que todas midan lo mismo, y una
   fila del doble de alto se lee como si fuera otra cosa. El valor completo vive
   en el title de la celda; el identificador, que es lo que no se puede leer a
   medias, va debajo y entero. */
.dt__c--clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Varias etiquetas en una celda, en UNA linea. Si no caben, la columna esta
   angosta y eso se arregla en el reparto de anchos, no dejando que una fila
   crezca al doble sin avisar. */
.dt__tags { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.dt__c--clip .dt__link { display: block; overflow: hidden; text-overflow: ellipsis; }
.dt__c.mono, .dt__f.mono, .dt__h.dt__num { font-variant-numeric: tabular-nums; }

/* EL AIRE DE LOS EXTREMOS. La banda de hover y la regla de cada fila cubren la
   celda entera, y las celdas de los bordes no tenian relleno: el resaltado
   nacia pegado a la primera letra y la linea moria pegada al ultimo caracter.

   El relleno va en las celdas y el margen negativo en el contenedor, no al
   reves: asi el TEXTO se queda donde estaba —alineado con el titulo y el
   buscador de la tarjeta, que es la regla de la casa— y lo unico que se
   ensancha es lo que se pinta. Se cuelga de .dt-block porque .table-scroll lo
   comparte con ComplianceTable, que no tiene banda de hover que despegar. */
.dt-block > .table-scroll { margin-inline: -10px; }
.dt__h:first-child, .dt__c:first-child, .dt__f:first-child { padding-left: 10px; }
.dt__h:last-child, .dt__c:last-child, .dt__f:last-child { padding-right: 10px; }
/* La segunda línea NO se parte: son el folio y el RUT, dos cosas que leídas en
   dos pedazos dejan de ser un identificador. Si no cabe, la columna crece. */
/* EL CUADRADITO DE AGRUPACION. Marca a ojo que dos filas son del mismo grupo
   —el mismo holding, en la pantalla de empresas— sin que haya que leer y
   comparar 50 nombres.

   CUADRADO y no circulo, y en frios: los estados de este sistema son verde,
   ambar y rojo, y son redondos (ver --dot-ok y compania). Una marca que tomara
   prestada cualquiera de las dos cosas se leeria como un estado, que es
   justamente lo que no es.

   Y NO identifica: con 45 holdings y 8 colores hay grupos que comparten uno, asi
   que color igual no prueba grupo igual — lo prueba el nombre que va al lado, y
   por eso el cuadradito solo se usa donde ese nombre esta siempre a la vista.
   Es la misma regla del chip: el color nunca va solo. */
.dt__swatch {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  margin-right: 8px;
  vertical-align: 1px;
  flex: none;
}
.dt__swatch--1 { background: #1F63E3; }
.dt__swatch--2 { background: #1E3A8A; }
.dt__swatch--3 { background: #4338CA; }
.dt__swatch--4 { background: #7C3AED; }
.dt__swatch--5 { background: #A21CAF; }
.dt__swatch--6 { background: #BE185D; }
.dt__swatch--7 { background: #0E7490; }
.dt__swatch--8 { background: #475569; }

/* Una celda que abre lo que cuenta. Hereda el color para que la tabla no se
   llene de azul: lo que dice que es un enlace es el subrayado al pasar y el
   cursor, no el color de 163 numeros. */
.dt__link { color: inherit; text-decoration: none; cursor: pointer; }
.dt__link:hover { text-decoration: underline; }
.dt__link:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }
.dt__note { display: block; font-size: 10.5px; color: var(--text-subtle); margin-top: 2px; white-space: nowrap; }
.dt tbody tr:hover .dt__c { background: var(--bg); }
/* Un documento anulado sigue en la lista y no puede leerse como vigente. */
.dt__c--muted { color: var(--text-disabled); }
.dt__c--muted .dt__note { color: var(--text-disabled); }

.dt__f {
  padding: 12px 12px 0 0;
  border-top: 1px solid var(--border);
  font-weight: 700;
  color: var(--navy);
  text-align: left;
  white-space: nowrap;
}
/* La fila de totales tiene que caer EXACTAMENTE bajo la columna que suma, y no
   caía: .dt__num pone padding-right:0 y .dt__f lo pisaba con sus 12px por venir
   después con la misma especificidad, así que cada total quedaba 12px a la
   izquierda de su columna. Se ve enseguida y no lo delata ninguna medida de las
   celdas —las cajas terminan en el mismo x, lo que se corre es el texto—. */
.dt__f.dt__num { padding-right: 0; padding-left: 16px; }

.pager {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
}
.pager__count { margin: 0; font-size: 12.5px; color: var(--text-muted); }
.pager__moves { display: flex; align-items: center; gap: 4px; }
.pager__move {
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text);
  font-size: 12.5px;
  text-decoration: none;
  white-space: nowrap;
}
.pager__move:hover { border-color: var(--blue); color: var(--blue); }
.pager__move:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
/* El extremo se pinta apagado y NO se esconde: quitar el control haria saltar
   al otro justo cuando se le esta haciendo click. Misma decision que .btn:disabled. */
.pager__move--off { color: var(--text-disabled); border-color: var(--border-soft); cursor: not-allowed; }
.pager__move--off:hover { color: var(--text-disabled); border-color: var(--border-soft); }
.pager__at { font-size: 11px; color: var(--text-subtle); padding: 0 8px; }

/* ------------------------------------------------------------------- Chooser
 *
 * Elegir UN sujeto entre muchos: qué sociedad, de 163. Es un AUTOCOMPLETADO y
 * no un paso previo: la caja vive en la misma pantalla que las pestañas y la
 * tabla, y los resultados caen ENCIMA en vez de empujarla. Se abre con
 * :focus-within, sin una línea de JavaScript.
 */
.chooser { position: relative; display: flex; flex-direction: column; gap: 6px; }
.chooser__row { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px; }
.chooser__search { flex: 1 1 240px; min-width: 200px; }
.chooser__search .searchbox { margin-bottom: 0; }
.chooser__name { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.chooser__note { font-size: 11px; color: var(--text-subtle); }

/* La lista flota: con position:static empujaba la tabla media pantalla hacia
   abajo en cuanto alguien escribía una letra. Sale del flujo y vuelve a
   cerrarse sola al salir del control. */
.chooser__pop {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 30;
  margin-top: 4px;
  padding: 4px 0 0;
  max-height: 340px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(15, 42, 84, 0.12);
}
.chooser:focus-within .chooser__pop,
.chooser--open .chooser__pop { display: block; }

.chooser__list { list-style: none; margin: 0; padding: 0; }
.chooser__list li + li { border-top: 1px solid var(--border-soft); }
.chooser__item {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 9px 12px;
  text-decoration: none;
}
.chooser__item:hover { background: var(--bg); }
.chooser__item:hover .chooser__name { color: var(--blue); }
.chooser__item:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.chooser__item .chooser__name { font-size: 13.5px; }
.chooser__more { margin: 0; padding: 8px 12px; font-size: 12px; color: var(--text-muted); border-top: 1px solid var(--border-soft); }
.chooser__pop .muted { padding: 10px 12px; }

/* El pie de la tabla: el paginador a la izquierda y la descarga a la derecha.
   Con una sola página el paginador no se pinta y el botón se va igual al borde
   derecho, que es donde estaba antes — no se mueve al cambiar de filtro. */
.rcv-foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.rcv-foot .pager { flex: 1 1 320px; }

/* ------------------------------------------------- ChipPicker (campo de uno) */

/* Un campo que elige uno entre muchos SIN desplegable: todas las opciones a la
   vista en pastillas, y una caja arriba que las angosta. Las pastillas estan
   desde que se abre; el buscador no las hace aparecer, las filtra.

   Las opciones son RADIOS de verdad. Elegir no cuesta una peticion, asi que
   nada de lo ya escrito en el formulario puede perderse en el camino — que es
   el error que tiene cualquier version de esto que pregunte al servidor. */
.chipick { display: flex; flex-direction: column; gap: 8px; border: 0; padding: 0; margin: 0; min-width: 0; }
.chipick > .field__label { padding: 0; }
.chipick__find { font-size: 14px; }

/* ALTURA FIJA, no maxima: la caja mide lo mismo con una pastilla que con
   cuarenta, y lo que sobra se desplaza. Con max-height la caja crecia y se
   encogia en CADA tecla —«a» daba tres filas, «al» una— y los botones del
   dialogo saltaban debajo del cursor (Pedro, 2026-09-21). Con la altura fija no
   se mueve NADA en la pantalla mientras se busca.

   align-content arriba: sin el, una sola fila se centra en la caja y la
   pastilla queda flotando en el medio. */
.chipick__opts {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 6px;
  /* TRES FILAS EXACTAS, medidas y no a ojo: 3 pastillas de 26,8px + 2 huecos de
     6 + 16 de relleno + 2 de borde = 110,4. Con 118 asomaba media cuarta fila y
     se leia como texto cortado, no como que hay mas. Lo que dice que hay mas es
     la nota de abajo, que nombra cuantas calzaron. */
  height: 111px;
  overflow-y: auto;
  scrollbar-width: thin;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg);
}
.chipick__chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color var(--t), background var(--t), color var(--t);
}
.chipick__chip:hover { border-color: var(--blue-200); }
/* :has() y no una clase que ponga el servidor, igual que en .sup__type: quien
   esta elegido lo sabe el input, y pintarlo desde Go obligaria a repintar el
   campo en cada click — que es justo el viaje que este control no hace. */
.chipick__chip:has(input:checked) { background: var(--navy); border-color: var(--navy); color: #fff; font-weight: 600; }
/* El radio esta oculto pero sigue recibiendo foco: el anillo lo pinta la
   pastilla, o navegar con el teclado seria invisible. */
.chipick__chip:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ------------------------------------------- Administracion: ficha y paneles */

/* La bajada de una pantalla de administracion. Existe porque una tabla de
   nombres y numeros no puede decir POR QUE importa: una cartera es lo unico
   que concede acceso en la oficina, y eso no se deduce de cuatro filas. */
.admin-intro {
  margin: 0 0 16px;
  max-width: 72ch;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* La ficha de una cartera. Es una PAGINA y no un dialogo: la cartera mas grande
   tiene 45 empresas y dos listas que se buscan y se editan. */
.ficha { display: flex; flex-direction: column; gap: 20px; }
.ficha__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.ficha__title { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ficha__back {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
}
.ficha__back:hover { color: var(--blue); }
.ficha__back::before { content: "← "; }
.ficha__name { margin: 0; font-size: 20px; font-weight: 700; color: var(--navy); }
.ficha__note { margin: 0; font-size: 13px; color: var(--text-muted); }
.ficha__actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* DOS COLUMNAS y no una: las dos listas contestan preguntas distintas —que
   tiene la cartera y quien la lee— y apiladas obligan a desplazar para cruzar
   justo lo que hay que cruzar antes de agregar una empresa. Debajo de 1100px
   se apilan, que es cuando dos columnas dejan de caber. */
.ficha__panels { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 1100px) { .ficha__panels { grid-template-columns: 1fr; } }

.panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-2xl);
  background: var(--surface);
}
.panel__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.panel__title { margin: 0; display: flex; align-items: baseline; gap: 8px; font-size: 14px; font-weight: 700; color: var(--navy); }
.panel__count { font-size: 12px; font-weight: 500; color: var(--text-muted); }
.panel .searchbox { margin-bottom: 0; }

/* El aviso de que la cartera es COMPARTIDA. Va sobre la lista y no dentro del
   dialogo de agregar, porque lo que advierte ya es cierto de lo que esta ahi:
   cada empresa de la lista la estan leyendo esas personas. */
.panel__warn {
  margin: 0;
  padding: 8px 12px;
  border-left: 3px solid var(--pend-border);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--pend-bg);
  color: var(--pend-text);
  font-size: 12.5px;
  line-height: 1.5;
}

.rowlist__tags { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }

/* Dos campos cortos en una fila: cargo y rol se eligen juntos y apilados
   parecerian dos decisiones separadas. */
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 560px) { .form__row { grid-template-columns: 1fr; } }

/* Multi-seleccion con casillas NATIVAS: elegir cuatro empresas es una sola
   pasada y un solo POST. La caja se desplaza y tiene altura fija por el mismo
   motivo que .chipick__opts: si creciera con los resultados, los botones del
   dialogo saltarian en cada tecla. */
/* El envoltorio de lo que repinta el buscador. Existe para que el swap tenga UN
   id, y hereda el ritmo del formulario: sin esto, la caja, los avisos y los
   botones quedan pegados, porque el gap era del .form y ahora son sus nietos. */
.checklist-block { display: flex; flex-direction: column; gap: 18px; }

/* LA MATRIZ DE ACCESO: una fila por materia, tres niveles por fila.
 *
 * Radios de verdad y no un <select> por materia: las tres respuestas caben en
 * la fila, se ven las tres a la vez —que es lo que deja comparar «ver» con
 * «administrar»— y elegir no cuesta una peticion. Un desplegable por linea
 * esconderia dos de cada tres opciones y obligaria a abrirlo para saber que hay.
 *
 * ES UNA SOLA GRILLA de cuatro columnas y no tres filas flex, con display:
 * contents en la fila y en el grupo de niveles. Con una grilla por fila, cada
 * una mide sus columnas por su propio contenido y las tres dejan de alinearse:
 * «Administrar» cae en un x distinto en cada linea y la matriz deja de leerse
 * como una tabla. Con columnas de ancho FIJO alineaba, pero el panel es angosto
 * y «Administrar» se cortaba contra el borde. */
.matrix {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.matrix__row, .matrix__levels { display: contents; }
.matrix__domain, .matrix__level {
  display: flex;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.matrix__row:last-child > .matrix__domain,
.matrix__row:last-child > .matrix__levels > .matrix__level { border-bottom: 0; }
.matrix__domain { min-width: 0; padding-left: 12px; font-size: 13px; color: var(--text); }
.matrix__level {
  gap: 6px;
  font-size: 12.5px;
  color: var(--text-muted);
  white-space: nowrap;
  cursor: pointer;
}
.matrix__level:hover { background: var(--bg); }
.matrix__level input { accent-color: var(--blue); }
/* El nivel elegido se marca con PESO y color del texto, no con un fondo: tres
   filas con tres fondos distintos se leen como tres estados de cumplimiento. */
.matrix__level:has(input:checked) { color: var(--text); font-weight: 600; }
.matrix__level:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: -2px; }
.checklist {
  display: flex;
  flex-direction: column;
  max-height: 260px;
  overflow-y: auto;
  scrollbar-width: thin;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg);
}
.checklist__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.checklist__row:last-child { border-bottom: 0; }
.checklist__row:hover { background: var(--surface); }
.checklist__row input { accent-color: var(--blue); }
.checklist__row:has(input:focus-visible) { outline: 2px solid var(--blue); outline-offset: -2px; }
.checklist__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.checklist__name { font-size: 13px; color: var(--text); }
.checklist__note { font-size: 11px; color: var(--text-muted); }

/* LA PANTALLA DE USUARIOS.
 *
 * Una nota sobre la lista: lo que quedó a medias. La invitación que escribe la
 * pertenencia y no logra mandar el correo no es un error —la persona está
 * adentro— ni un éxito, así que no puede robar ninguno de los dos estilos: va
 * en ámbar, que es el color de «te falta algo por hacer» en todo el sistema. */
.admin-note {
	margin: -8px 0 0;
	padding: 10px 14px;
	border-radius: var(--radius-md);
	background: var(--pend-bg);
	border: 1px solid var(--pend-border);
	font-size: 13px;
	color: var(--pend-text);
}

/* LA FICHA DE UNA PERSONA, dentro de un modal.
 *
 * El cuerpo lleva el MISMO respiro que .form (22/28/26) y no ninguno: sin esto
 * el texto y las lineas de .facts llegaban de borde a borde mientras el
 * encabezado, que si tiene su padding, quedaba metido hacia adentro — dos
 * margenes distintos en el mismo cuadro, que es lo que se ve como "sin margen".
 * Es el mismo bug que tuvo el buscador dentro del dialogo de agregar empresas. */
.person { display: flex; flex-direction: column; }
.person__body { display: flex; flex-direction: column; gap: 16px; padding: 22px 28px 24px; }
.person__block { display: flex; flex-direction: column; gap: 6px; }
.person__block > .eyebrow { margin: 0; }

/* EL PIE TIENE DOS PESOS Y NO CUATRO BOTONES IGUALES.
 *
 * Cuatro botones del mismo tamano obligan a leerlos todos para encontrar el que
 * se vino a apretar, y dejan "Desactivar cuenta" —que saca a alguien de la
 * plataforma entera— con el mismo aspecto que "Reenviar contrasena". El catalogo
 * dice que un tercer ButtonVariant casi siempre significa que la jerarquia esta
 * mal; aca lo estaba, y lo que faltaba no era un boton gris sino separar lo que
 * se hace seguido de lo que se hace una vez.
 *
 * A la derecha los botones; a la izquierda, como ENLACES, las dos bajas. */
.person__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding: 16px 24px;
  border-top: 1px solid var(--border);
  background: var(--bg);
  border-radius: 0 0 var(--radius-2xl) var(--radius-2xl);
}
.person__rare { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.person__main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* El formulario de reenviar es SOLO un boton: display:contents lo saca del
   flujo para que su boton se alinee con los demas del pie. */
.person__inline { display: contents; }

/* Las dos bajas: enlaces sobrios que se pintan de rojo al acercarse. No son
   botones porque no son el trabajo del dia, y no nacen rojos porque un pie con
   dos alarmas encendidas se lee como una pantalla en problemas. */
.person__danger {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--t), border-color var(--t);
}
.person__danger:hover, .person__danger:focus-visible { color: var(--riesgo-text); border-bottom-color: var(--riesgo-text); }

/* La explicacion del boton que no esta (desactivarse a uno mismo). Va bajo el
   pie porque habla de el. */
.person__note { margin: 0; padding: 0 28px 18px; font-size: 12px; color: var(--text-muted); line-height: 1.5; }

.person__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Tope de alto: sin el, quien esta en ocho carteras estira el dialogo hasta
     pasarse de la pantalla y el pie queda bajo el doblez — que es justo como
     sus botones se dieron por inexistentes. Misma regla que .checklist. */
  max-height: 168px;
  overflow-y: auto;
}
/* Una cartera y su cargo en la MISMA linea: el cargo califica a la cartera, y
   ponerlo debajo lo convierte en un segundo dato de la lista. */
.person__item { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.person__cartera, .person__link a {
  color: var(--blue);
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  border-bottom: 1px solid transparent;
}
.person__cartera:hover, .person__link a:hover { border-bottom-color: var(--blue); }
.person__link { margin: 0; }
/* El enlace dentro de una frase hereda su tamano, o se lee como otro nivel. */
.field__hint .person__cartera { font-size: inherit; }

@media (max-width: 560px) {
  .person__foot { flex-direction: column-reverse; align-items: stretch; }
  .person__main { justify-content: flex-end; }
}
/* La casilla del interruptor de admin, sin el borde de una lista de opciones:
   aca es un campo del formulario y no una fila de una seleccion multiple. */
.checklist__row--bare { border-bottom: 0; padding-left: 0; padding-right: 0; }
.checklist__row--bare:hover { background: transparent; }

/* El icono dentro de un boton: un punto mas chico que el texto y con el trazo
   mas fino, o compite con la etiqueta en vez de acompanarla. El .btn ya trae
   gap: 8px, asi que no hace falta margen. */
.btn .icon { width: 15px; height: 15px; stroke-width: 2.2; }
.btn--primary .icon { opacity: 0.95; }
