/* Sistema visual nuevo (rediseño flat de Woker). Es la única capa de sistema: los legacy
   modern-ui.css y modern-forms.css se borraron al migrar la última pantalla que los cargaba. */

/* Tokens de superficie y texto (dark-mode.css los reasigna bajo html[data-theme="dark"]) */
:root {
  /* Fallback de marca (COLOR_MARCA_DEFAULT en utils/utils_colores.py). En todo request normal
     base.html pisa estos valores con la paleta de la organización. Este default es para el único
     render sin contexto que hace Django: la 500 vía template.render(), donde no hay
     coloresMarca — base.html omite su :root en ese caso justamente para que aplique. */
  --woker-violet: #7551E4;
  --woker-violet-rgb: 117, 81, 228;
  --woker-violet-hover: #6546c4;
  --woker-violet-soft: #e9e3fb;
  --woker-violet-soft-border: #cdc0f5;
  --woker-violet-tint: #f7f5fd;

  --woker-page-bg: #fbfbff;    /* fondo de TODA la pantalla (lo pinta solo el body) */
  --woker-surface: #fff;       /* cards */
  --woker-surface-2: #fbfbff;  /* cabeceras de tabla, hovers, franjas */
  --woker-ink: #18181b;        /* texto principal */
  --woker-muted: #52525b;      /* texto secundario (labels, celdas) */
  --woker-subtle: #a1a1aa;     /* texto terciario (hints, timestamps) */
  /* Terciario cuando es TEXTO de lectura, no un adorno. --woker-subtle está calibrado para
     hints y timestamps y como texto corrido no llega al 4,5:1 de WCAG AA (2,48:1 sobre el
     fondo de página). Este token es el mismo gris un paso más oscuro: 4,68:1 sobre el fondo
     y 4,83:1 sobre una card, sin igualarse a --woker-muted (7,49:1), que es el de los labels
     — el subtítulo tiene que seguir leyéndose por debajo del título. Se reasigna en
     dark-mode.css. Mismo criterio que --woker-ok-fg / --woker-danger-fg. */
  --woker-subtle-texto: #71717a;
  --woker-border: #e4e4e7;     /* bordes de cards, filas y separadores */
  /* Borde de un CONTROL (input, select, select2, input file). Va un paso por encima de
     --woker-border porque el rol es otro: una línea divisoria puede insinuarse, pero el
     límite de un campo tiene que leerse — con el token de card los campos casi desaparecían
     contra el blanco de un modal (1,18:1 con el #ececf1 que termina aplicando
     sidebar-moderna.css; 1,27:1 con el #e4e4e7 de acá). Token aparte y no un --woker-border
     más oscuro porque ese valor lo consumen ~190 usos estructurales (cards, tablas,
     timelines, sidebar) que no tienen por qué pesar más. */
  --woker-border-control: #e0e0e6;
  --woker-border-fuerte: #d1d5db;  /* borde en hover de un control */
  --woker-radius: 12px;        /* radio de cards */
  --woker-radius-control: 6px; /* radio de inputs y botones */
  --woker-card-shadow: 0 1px 3px rgba(0, 0, 0, .04), 0 4px 12px rgba(0, 0, 0, .03);
  /* Motion — ease-out sutil (out-quint); duraciones cortas, estado no decoración */
  --woker-ease: cubic-bezier(.22, 1, .36, 1);
  --woker-transicion: all .2s var(--woker-ease);
  --woker-dur-feedback: .12s;   /* press / color: casi instantáneo */

  /* Color semántico — separado del color de marca; un valor por rol. El ámbar va sólido a propósito */
  --woker-ok: #16a34a;       --woker-ok-bg: rgba(22, 163, 74, .1);
  --woker-warn: #b45309;     --woker-warn-bg: #fef6d9;
  /* El ámbar del rol está oscurecido para que un texto llegue a AA sobre fondo claro; como
     relleno sólido (una barra, un punto de estado) queda barroso. Para eso va este, que es el
     mismo ámbar sin la corrección de contraste. Nunca para texto. */
  --woker-warn-solido: #f59e0b;
  --woker-danger: #dc2626;   --woker-danger-bg: rgba(220, 38, 38, .1);
  /* Canales del rojo, para cuando hace falta el rol a otra opacidad (mismo criterio
     que --woker-violet-rgb): rgba(var(--woker-danger-rgb), .55). */
  --woker-danger-rgb: 220, 38, 38;
  /* Tinta para TEXTO CORRIDO sobre el tinte del rol (ej. el mensaje de un .alert). El rol pleno
     está calibrado para tags y chips; como párrafo sobre su propio -bg no llega a AA: el verde
     da 2,96:1 y el rojo 4,13:1. Solo se definen estos dos porque warn (4,64:1) e info (6,74:1)
     ya pasan con el rol pleno. */
  --woker-ok-fg: #0f6b32;    --woker-danger-fg: #b3261e;
  --woker-info: #4338ca;     --woker-info-bg: #e6edff;
  --woker-neutral: #52525b;  --woker-neutral-bg: #f1f1f4;   /* estado inactivo / cerrado */
}

/* Layout shell — común a toda pantalla del sistema nuevo; el fondo lo pinta solo el body */
body {
  background: var(--woker-page-bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Columna flex de min 100vh: ancla el footer abajo aunque el contenido sea corto */
.wrapper { display: flex; flex-direction: column; min-height: 100vh; }

.content-wrapper {
  flex: 1 0 auto;
  min-height: 0 !important;
  background: transparent;
}

.main-sidebar,
.main-sidebar .brand-link,
.main-header.navbar { background-color: transparent !important; }

/* position:relative como contexto de posicionamiento local del contenido */
.main-content {
  padding: 1.5rem 1.5rem;
  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  position: relative;
}

@media (max-width: 575.98px) {
  .main-content { padding: 1rem 1rem; }
}

/* Paginación (compartida — paginacion_moderna.html) */

.custom-pagination-wrapper {
  padding: 0.5rem 1.5rem;
  background: var(--woker-surface);
  border-top: 1px solid var(--woker-border);
}

/* Sin margen propio: la fila de botones queda centrada en el alto del wrapper (su padding
   es el único aire). El aire hacia la línea de "Mostrando X - Y" lo pone .custom-pagination-info,
   que es quien lo necesita — así el paginador solo, sin info, nunca queda arriba del centro. */
.custom-pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 0;
}

.custom-pagination .page-btn {
  border: none;
  background: none;
  color: var(--woker-muted);
  padding: 0.375rem;
  border-radius: 4px;
  font-size: 0.875rem;
  transition: var(--woker-transicion);
  cursor: pointer;
  min-width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  text-decoration: none;
}

.custom-pagination .page-btn:hover:not(.disabled):not(.active) {
  background-color: var(--woker-surface-2);
  color: var(--woker-violet);
  text-decoration: none;
}

/* Editor Summernote — tratamiento base, colgado de .note-editor-wrapper (el hook que emite
   partials/editor_summernote.html). Sin esto una pantalla que use el partial se queda con el
   Summernote crudo de Bootstrap. tickets.css tiene su propia copia scopeada a
   .ticket-datos-card, más específica, así que sigue ganando ahí. */
.note-editor-wrapper .note-editor.note-frame {
  border: 1px solid var(--woker-border);
  /* Radio de card y no de control: el editor es un bloque con barra propia, del tamaño
     de la caja de adjuntos. Es el valor que ya usaba tickets. */
  border-radius: var(--woker-radius);
  overflow: hidden;
  margin-bottom: 0;
}

.note-editor-wrapper .note-editor.note-frame.focus,
.note-editor-wrapper .note-editor.note-frame:focus-within {
  border-color: var(--woker-violet);
  box-shadow: 0 0 0 3px rgba(var(--woker-violet-rgb), .18);
}

.note-editor-wrapper .note-editor .note-toolbar {
  background: var(--woker-surface-2);
  border-bottom: 1px solid var(--woker-border);
  padding: 6px 8px;
  gap: 2px;
}

.note-editor-wrapper .note-editor .note-btn-group {
  margin-right: 6px;
}

.note-editor-wrapper .note-editor .note-btn {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 7px;
  color: var(--woker-muted);
  padding: 5px 9px;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}

.note-editor-wrapper .note-editor .note-btn:hover,
.note-editor-wrapper .note-editor .note-btn:focus,
.note-editor-wrapper .note-editor .note-btn.active,
.note-editor-wrapper .note-editor .note-btn:active {
  background: var(--woker-violet-soft);
  color: var(--woker-violet);
  border-color: transparent;
  box-shadow: none;
}

.note-editor-wrapper .note-editor .note-editable {
  padding: 14px 16px;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--woker-ink);
  min-height: 200px;
}

.note-editor-wrapper .note-editor .note-placeholder {
  padding: 14px 16px;
  color: var(--woker-subtle);
}

.note-editor-wrapper .note-editor .note-statusbar {
  background: var(--woker-surface-2);
  border-top: 1px solid var(--woker-border);
}

.note-editor-wrapper .note-editor .note-statusbar .note-resizebar {
  padding-top: 1px;
}

/* Editor Summernote en modo oscuro. Va colgado de .note-editor-wrapper — el hook que
   emite partials/editor_summernote.html — porque el editor lo comparten tickets y
   noticias: scopearlo a un módulo deja al otro con la toolbar clara sobre fondo oscuro.
   (tickets.css tiene el suyo scopeado a .ticket-datos-card, de antes de este partial.) */
html[data-theme="dark"] .note-editor-wrapper .note-editor .note-toolbar,
html[data-theme="dark"] .note-editor-wrapper .note-editor .note-statusbar {
  background: var(--woker-surface-2);
  border-color: var(--woker-border);
}

html[data-theme="dark"] .note-editor-wrapper .note-editor .note-btn {
  background: transparent;
  border-color: transparent;
  color: var(--woker-muted);
}

html[data-theme="dark"] .note-editor-wrapper .note-editor .note-btn:hover,
html[data-theme="dark"] .note-editor-wrapper .note-editor .note-btn:focus,
html[data-theme="dark"] .note-editor-wrapper .note-editor .note-btn.active {
  background: rgba(var(--woker-violet-rgb), 0.16);
  color: var(--woker-violet);
}

html[data-theme="dark"] .note-editor-wrapper .note-editor .note-editable {
  background: var(--woker-surface);
  color: var(--woker-ink);
}

/* Lo que se PEGA en el editor trae colores inline pensados para fondo claro (un
   `color: rgb(0, 0, 0)` copiado de una web queda negro sobre negro y el campo se lee
   vacío). En oscuro manda el token, igual que en la vista de lectura de la noticia
   (.vn-cuerpo en noticias.css): así el editor muestra lo mismo que va a ver el lector. */
html[data-theme="dark"] .note-editor-wrapper .note-editor .note-editable [style*="color"] {
  color: var(--woker-ink) !important;
}

/* Summernote inyecta por JS el link de su diálogo de ayuda (<p class="text-center"><a>),
   que se queda con el azul de link de Bootstrap. Lo ve cualquier pantalla que cargue el
   editor, así que la regla va acá y no en el CSS de una. */
.note-modal a,
.note-editor .text-center a {
  color: var(--woker-violet);
}

.note-modal a:hover,
.note-editor .text-center a:hover {
  color: var(--woker-violet-hover);
}

/* El :hover de arriba excluye .active, así que sin esta regla el botón de la página
   actual se queda con el a:hover azul de Bootstrap (#0056b3) al pasarle por encima. */
.custom-pagination .page-btn.active,
.custom-pagination .page-btn.active:hover {
  background-color: var(--woker-violet-soft);
  color: var(--woker-violet);
  border: none;
  font-weight: 600;
  text-decoration: none;
}

.custom-pagination .page-btn.disabled {
  color: var(--woker-subtle);
  cursor: not-allowed;
  pointer-events: none;
}

.custom-pagination .page-btn.disabled:hover {
  background: none;
  color: var(--woker-subtle);
}

.custom-pagination-page-numbers {
  display: flex;
  gap: 0.25rem;
  align-items: center;
}

.custom-pagination-info {
  margin-top: 0.75rem;
  text-align: center;
  color: var(--woker-muted);
  font-size: 0.8rem;
}

@media (max-width: 768px) {
  .custom-pagination-wrapper {
    padding: 0.75rem 1rem;
  }

  .custom-pagination .page-btn {
    min-width: 26px;
    height: 26px;
    font-size: 0.8rem;
  }

  .custom-pagination-info {
    font-size: 0.75rem;
  }
}

/* Componentes planos reutilizables */

/* Iconos outline (estilo Lucide) */
.ico { display:inline-block; width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; vertical-align:middle; flex-shrink:0; }
.ico-sm { width:14px; height:14px; }
.ico-xs { width:12px; height:12px; }
.ico.flip { transform:rotate(180deg); }

/* Botones planos */
.btn-flat { display:inline-flex; align-items:center; gap:.45rem; background:transparent; border:1px solid var(--woker-border); color:var(--woker-ink); font-size:.8rem; font-weight:600; padding:.4rem .85rem; border-radius:8px; cursor:pointer; text-decoration:none; white-space:nowrap; }
.btn-flat:hover { background:var(--woker-surface); border-color:var(--woker-border-fuerte); color:var(--woker-ink); text-decoration:none; }
.btn-flat .ico { color:var(--woker-ink); }

/* borde transparente (no `none`): iguala el alto con .btn-flat, que sí lo tiene */
.btn-purple { display:inline-flex; align-items:center; gap:.45rem; background:var(--woker-violet); border:1px solid transparent; color:#fff; font-size:.8rem; font-weight:600; padding:.4rem .9rem; border-radius:7px; cursor:pointer; text-decoration:none; white-space:nowrap; box-shadow:0 1px 2px rgba(var(--woker-violet-rgb),.3); }
.btn-purple:hover { background:var(--woker-violet-hover); color:#fff; text-decoration:none; }

/* Deshabilitado: mismo tratamiento para los tres botones del sistema */
.btn-flat:disabled,
.btn-purple:disabled,
.btn-minimal:disabled { opacity:.5; cursor:not-allowed; pointer-events:none; }

/* Foco de los dos botones: anillo de marca en vez del glow azul de Bootstrap */
.btn-flat:focus,
.btn-purple:focus { outline:0; box-shadow:0 0 0 .2rem rgba(var(--woker-violet-rgb),.25); }

/* Microinteracción: color suave al hover, hundido al presionar (el primario además se eleva) */
.btn-flat,
.btn-purple { transition:background-color .15s var(--woker-ease), border-color .15s var(--woker-ease), box-shadow .15s var(--woker-ease), transform var(--woker-dur-feedback) var(--woker-ease); }
.btn-purple:hover { box-shadow:0 2px 6px rgba(var(--woker-violet-rgb),.35); transform:translateY(-1px); }
.btn-flat:active,
.btn-purple:active { transform:translateY(1px); }

/* Botón partido: la acción principal + un disparador de opciones pegado a su derecha.
   Los dos halves comparten fondo, así que se elevan juntos o no se elevan. */
.btn-split { display:inline-flex; align-items:stretch; }
.btn-split > .btn-purple:first-child { border-top-right-radius:0; border-bottom-right-radius:0; }
.btn-split > .btn-purple:last-child {
  border-top-left-radius:0;
  border-bottom-left-radius:0;
  border-left:1px solid rgba(255,255,255,.35);
  padding-left:.5rem;
  padding-right:.5rem;
  box-shadow:none;
}
.btn-split > .btn-purple:hover { transform:none; box-shadow:0 1px 2px rgba(var(--woker-violet-rgb),.3); }
.btn-split > .btn-purple:last-child .ico { width:14px; height:14px; }

/* Card liviana */
.card-soft { background:var(--woker-surface); border:1px solid var(--woker-border); border-radius:var(--woker-radius); box-shadow:var(--woker-card-shadow); }

/* Header de pantalla: ícono + título + subtítulo a la izquierda, acciones a la derecha */
/* margin-bottom 1.5rem = el mismo que .filters-card y .form-card: el aire entre
   el header y lo que sigue tiene que ser igual al que hay entre bloque y bloque. */
.pantalla-header { display:flex; justify-content:space-between; align-items:flex-start; flex-wrap:wrap; gap:1rem; margin-bottom:1.5rem; }
/* flex-basis 0 (no `auto`): el flex resuelve el wrap ANTES de encoger, así que con
   basis auto el bloque del título entra a la línea con su ancho máximo — el subtítulo
   en un solo renglón — y empuja las acciones a una segunda fila aunque a simple vista
   entren al lado. Con basis 0 el título toma el espacio que sobra y es el subtítulo el
   que se parte en dos líneas. El min-width es el piso: por debajo de eso el subtítulo
   se partiría en cuatro renglones, y ahí conviene la segunda fila (el wrap del header
   vuelve solo). En <768px el header pasa a columna y esto se revierte. */
.pantalla-header-left { display:flex; align-items:center; gap:.8rem; flex:1 1 0; min-width:320px; }
.pantalla-header-left > * { min-width:0; }
.pantalla-header-icon { width:42px; height:42px; border-radius:11px; background:var(--woker-violet-soft); color:var(--woker-violet); display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; }
.pantalla-header-icon .ico { width:21px; height:21px; }
.pantalla-title { font-size:1.3rem; font-weight:700; color:var(--woker-ink); margin:0; }
.pantalla-subtitle { font-size:.8rem; color:var(--woker-subtle-texto); margin:.2rem 0 0; }
.pantalla-actions { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; }

/* Tabs de navegación por <a href> (no JS-toggle): estado de un listado (tickets) o rama de
   una pantalla (monitoreo de credenciales) — cualquier caso donde el tab es en realidad un
   link a otra URL/querystring. Nace en lista-tickets.css; sube acá al usarla un segundo
   módulo (usuarios), que no puede depender del CSS de tickets. */
.estado-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
  margin-bottom: 1rem;
}
.estado-tab {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .45rem .85rem;
  border-radius: 8px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--woker-muted);
  text-decoration: none;
  white-space: nowrap;
}
.estado-tab .ico { width: 16px; height: 16px; }
@media (max-width: 767.98px) {
  .estado-tabs { justify-content: center; }
}
.estado-tab:hover { background: var(--woker-surface-2); color: var(--woker-ink); text-decoration: none; }
.estado-tab.is-active {
  background: rgba(var(--woker-violet-rgb), .1);
  color: var(--woker-violet);
}

/* Tarjetas de resumen (métricas numéricas arriba de una tabla/sección) — compartidas por
   varios módulos (gestor: listado_importaciones/subimportaciones/comisiones; administracion:
   estado del sistema), por eso viven acá y no en el CSS de un módulo puntual. */
.resumen-metricas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.metrica-card {
  background: var(--woker-surface);
  border: 1px solid var(--woker-border);
  border-radius: var(--woker-radius);
  box-shadow: var(--woker-card-shadow);
  padding: 1.1rem 1.25rem;
  text-align: center;
  /* Item de grid: sin esto, un valor largo (ej. "$35.801.173,58" en comisiones) que no
     puede partir en espacios fuerza el track a su ancho de contenido y desborda la card
     aunque la columna sea 1fr — el mínimo implícito de un grid item es su min-content. */
  min-width: 0;
}

.metrica-valor {
  /* <p>: sin esto arrastra el margin-bottom de 1rem del reboot y deja un hueco muerto
     entre el número y su etiqueta. */
  margin: 0;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--woker-ink);
  line-height: 1.2;
  /* Los importes en pesos no tienen espacios donde cortar: sin esto, un valor largo
     desborda la card en vez de partirse a la línea siguiente. */
  overflow-wrap: anywhere;
}
.metrica-label { font-size: .8rem; color: var(--woker-muted); margin: .25rem 0 0; }
.metrica-sub { font-size: .72rem; color: var(--woker-subtle); line-height: 1.35; margin: .15rem 0 0; }
.metrica-card.es-warn .metrica-sub { color: var(--woker-warn); font-weight: 700; }

@media (max-width: 575.98px) {
  .resumen-metricas { grid-template-columns: repeat(2, 1fr); }
}

/* Tabla moderna (listados) — valores de la pantalla de referencia (listaUsuarios) */
.tabla-card { overflow:hidden; border:1px solid var(--woker-border); border-radius:var(--woker-radius); box-shadow:var(--woker-card-shadow); }
/* El menú de fila (los tres puntitos) es un dropdown de Bootstrap posicionado dentro de la
   tabla: mientras está abierto hay que soltar el recorte de la card y el del .table-responsive,
   si no el desplegable queda encerrado en el contenedor scrolleable y aparece una barra de
   scroll en vez del menú. */
.tabla-card:has(.dropdown-menu.show),
.tabla-card .table-responsive:has(.dropdown-menu.show) { overflow: visible; }
.tabla-moderna { width:100%; margin:0; border-collapse:collapse; --tabla-pad-x:16px; --tabla-pad-borde:20px; }
/* Alto fijo (como las filas del cuerpo) y no padding vertical: así la cabecera mide igual en
   toda pantalla, aunque una columna traiga un control embebido (ej. el botón "Agregar" de las
   tablas del asegurado, que con padding hacía la cabecera más alta que en los otros tabs).
   En una celda de tabla `height` es un mínimo, así que un contenido más alto sigue creciendo. */
.tabla-moderna thead th { text-transform:uppercase; font-size:12px; letter-spacing:.12em; font-weight:500; color:var(--woker-muted); height:42px; padding:0 var(--tabla-pad-x); background:var(--woker-surface-2); border-bottom:1px solid var(--woker-border); white-space:nowrap; text-align:left; vertical-align:middle; }
/* Filas de alto fijo: la tabla no "salta" entre páginas con distinto contenido */
.tabla-moderna tbody td { font-size:14px; font-weight:400; color:var(--woker-muted); height:56px; padding:0 var(--tabla-pad-x); border-bottom:1px solid var(--woker-border); vertical-align:middle; white-space:nowrap; }
.tabla-moderna tbody tr:last-child td { border-bottom:none; }
.tabla-moderna tbody tr { transition:background-color .15s var(--woker-ease); }
.tabla-moderna tbody tr:hover { background:var(--woker-surface-2); }
/* Links dentro de la tabla (ids, nombres): color suave al hover */
.tabla-moderna a { transition:color .12s var(--woker-ease); }
/* Primera y última columna con más aire contra el borde de la card */
.tabla-moderna thead th:first-child,
.tabla-moderna tbody td:first-child { padding-left:var(--tabla-pad-borde); }
.tabla-moderna thead th:last-child,
.tabla-moderna tbody td:last-child { padding-right:var(--tabla-pad-borde); }

/* Tabla dentro de una form-card (accesorios, cuotas): el marco de .tabla-card pero sin sombra,
   porque ya vive sobre una card. El position contiene al .sr-only del th de acciones, que es
   absolute y si no se ancla a .main-content y empuja la página en mobile. */
.tabla-embebida { position:relative; overflow:hidden; border:1px solid var(--woker-border); border-radius:var(--woker-radius); }
/* Fila de "no hay nada": el mismo tratamiento en toda tabla, con o sin filas de alto fijo */
/* Estado vacío: va como <td> adentro de una tabla o como bloque suelto adentro de una card
   (el "Sin activaciones pendientes" del perfil), así que el centrado y el gris viven en la
   clase base; la regla del <td> sólo pisa el alto y el padding fijos de .tabla-moderna. */
.tabla-vacia { text-align:center; color:var(--woker-subtle); }
.tabla-moderna tbody td.tabla-vacia { height:auto; padding:1.25rem var(--tabla-pad-x); color:var(--woker-subtle); }
/* Una tabla editable (inputs en las celdas) no marca hover: no hay nada que resaltar */
.tabla-embebida .tabla-moderna tbody tr:hover { background:transparent; }

/* Variantes de tabla — se combinan con .tabla-moderna en el `class` del <table> */
.tabla-moderna.tabla-compacta { --tabla-pad-x:11px; --tabla-pad-borde:16px; }   /* muchas columnas */
/* Encabezado largo en dos renglones: sin esto el nowrap del th fija el ancho mínimo de
   toda la columna y empuja el scroll horizontal de la tabla. Entra en el alto del thead. */
.tabla-moderna thead th.th-multilinea { white-space:normal; line-height:1.25; }
.tabla-moderna.tabla-centrada thead th,
.tabla-moderna.tabla-centrada tbody td { text-align:center; }

/* Footer del paginador dentro de la card de tabla */
.tabla-footer { padding:0; }
.tabla-footer .custom-pagination-wrapper { padding:.5rem 1.1rem; border-top:1px solid var(--woker-border); background:transparent; }
.tabla-footer .custom-pagination { gap:.25rem; }

/* Celda usuario / avatar (para listados) */
.user-cell { display:flex; align-items:center; gap:12px; }
.user-avatar { width:36px; height:36px; box-sizing:border-box; line-height:1; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:12px; font-weight:500; background:var(--woker-violet-soft); color:var(--woker-violet); text-transform:uppercase; flex-shrink:0; }

/* Link de tabla al detalle del objeto (nombre, id, número de póliza...). ÚNICA clase para esto en
   todo el sistema: color de marca + 600, sin subrayado. No crear variantes por módulo. */
.link-detalle { color:var(--woker-violet); font-weight:600; font-size:14px; text-decoration:none; }
.link-detalle:hover { color:var(--woker-violet-hover); text-decoration:none; }

/* Link de texto corrido dentro del contenido (una referencia en un párrafo, un mailto en una
   celda). Sin esta regla se queda con el #007bff de Bootstrap: el único azul que sobrevive a la
   migración, porque no hay componente que lo cubra. Acotada a `a:not([class])` a propósito —
   todo lo que ES un componente (botón, tab, .link-detalle, .link-sin-color, paginador) lleva
   clase y queda afuera. */
.main-content a:not([class]) { color:var(--woker-violet); }
.main-content a:not([class]):hover { color:var(--woker-violet-hover); }

/* Link que envuelve contenido rico (nombre + subtítulo) sin look de link — el área entera
   es clickeable pero el texto no se pinta de marca. Viene de modern-ui.css (legacy). */
/* El :hover también: sin esta línea Bootstrap le mete su #0056b3 al pasar el mouse y
   el link vuelve a ser azul justo cuando se lo mira. La afordancia va por subrayado. */
.link-sin-color,
.link-sin-color:hover,
.link-sin-color:focus { color: inherit; }
.link-sin-color:hover { text-decoration: underline; }

/* Acciones por fila (ver/editar/eliminar): íconos sin caja, sin relleno permanente.
   Compartido por varios módulos (gestor/grupos, usuarios/contactos) — por eso vive acá
   y no en el CSS de una pantalla puntual. */
.tabla-acciones { display: inline-flex; align-items: center; gap: .25rem; }

.btn-fila-icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    border-radius: 8px;
    color: var(--woker-muted);
    cursor: pointer;
    transition: var(--woker-transicion);
}
.btn-fila-icono:hover { background: var(--woker-surface-2); color: var(--woker-violet); }
.btn-fila-icono-danger:hover { background: var(--woker-danger-bg); color: var(--woker-danger); }
.btn-fila-icono:disabled { opacity: .35; cursor: not-allowed; }
.btn-fila-icono:disabled:hover { background: transparent; color: var(--woker-muted); }

/* Chips / tags de estado — el color sale de los tokens semánticos, nunca de un hex */
.tipo-chip { display:inline-block; padding:3px 8px; border-radius:999px; font-size:12px; font-weight:500; background:var(--woker-surface); color:var(--woker-muted); border:1px solid var(--woker-border); }
/* Renovación / refacturación: con los tres chips iguales hay que leer la palabra para saber
   cuál es cuál. La renovación es el caso accionable y la refacturación la rutina, así que
   cada una lleva su tinta. El teal no sale de un token porque no hay rol semántico para
   "accionable", y los que hay (ok/danger/warn) ya se los llevan la columna de estado y el
   porcentaje de aumento: repetirlos acá dejaba dos columnas del mismo color y ninguna se leía.
   "Sin definir" se queda con el .tipo-chip neutro: es un dato que falta, no un tercer caso.
   Compartido por listado_vencimientos y listado_indice_aumentos. */
.tipo-chip.tipo-chip-renovacion { color:#0f766e; background:#ccfbf1; border-color:transparent; }
.tipo-chip.tipo-chip-refacturacion { color:var(--woker-info); background:var(--woker-info-bg); border-color:transparent; }
.estado-tag { display:inline-flex; align-items:center; gap:.4rem; font-size:.76rem; font-weight:500; padding:3px 10px; border-radius:999px; }
.estado-tag::before { content:''; width:5px; height:5px; border-radius:50%; background:currentColor; }
.estado-alta { color:var(--woker-ok); background:var(--woker-ok-bg); }
.estado-baja { color:var(--woker-danger); background:var(--woker-danger-bg); }
.estado-visualizacion { color:var(--woker-warn); background:var(--woker-warn-bg); }

/* Form controls, labels y botones de formulario (versión sistema nuevo de modern-forms.css legacy) */

.form-control,
select.form-control {
  background-color: var(--woker-surface);
  border: 1px solid var(--woker-border-control);
  border-radius: var(--woker-radius-control);
  color: var(--woker-muted);
  font-size: .875rem;
  line-height: 1.5;
  padding: .5rem .75rem;
  transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
  box-shadow: none;
}

.form-control:focus,
select.form-control:focus {
  background-color: var(--woker-surface);
  border-color: var(--woker-violet);
  outline: 0;
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}

.form-control:hover:not(:focus),
select.form-control:hover:not(:focus) { border-color: var(--woker-border-fuerte); }

/* Un input number centrado no queda centrado: el navegador reserva a la derecha el ancho de las
   flechitas —aunque solo se dibujen al pasar el mouse— y el texto se corre a la izquierda. Donde
   se pidió centrar (celdas de tabla como el número de cuota) el spinner se saca: centrar y spinner
   no conviven. Los number sin .text-center lo conservan. */
input[type="number"].text-center {
  -moz-appearance: textfield;
  appearance: textfield;
}

input[type="number"].text-center::-webkit-outer-spin-button,
input[type="number"].text-center::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Un campo readonly NO es un campo apagado: acá son links para copiar, snippets de embed y
   disparadores de datepicker — contenido que hay que poder leer y seleccionar. Bootstrap los
   pinta con su gris fijo (#e9ecef), fuera del sistema de tokens y sin variante oscura, y se
   leen como deshabilitados. Se los deja en la superficie de un control habilitado: lo que
   comunica que no se escribe es el cursor y el contexto, no un fondo gris. La regla va ANTES
   de :disabled —misma especificidad (0,2,0)— para que un campo readonly Y deshabilitado siga
   saliendo apagado. */
.form-control[readonly] {
  background-color: var(--woker-surface);
  border-color: var(--woker-border-control);
  color: var(--woker-muted);
  opacity: 1;
}

/* El deshabilitado se queda en el borde de card, un paso POR DEBAJO del control habilitado:
   si los dos usaran --woker-border-control, un campo apagado pesaría lo mismo que uno en el
   que se puede escribir. */
.form-control:disabled,
select.form-control:disabled {
  background-color: var(--woker-surface-2);
  border-color: var(--woker-border);
  color: var(--woker-muted);
  opacity: 1;
}

.form-control::placeholder,
select.form-control option:first-child { color: var(--woker-subtle); opacity: 1; }

/* Feedback de validación del panel de filtros (filtros-card.js: campos [required]
   vacíos y validaciones propias de una pantalla, ej. un rango de fechas > N días).
   Bootstrap trae `.is-invalid`/`.invalid-feedback` en un rojo fijo (#dc3545); se
   tokeniza acá para que salga en los dos temas sin regla aparte en dark-mode.css.
   Se saca el ícono de fondo de Bootstrap: no encaja con los form controls flat
   del sistema. */
.form-control.is-invalid,
select.form-control.is-invalid {
  background-image: none;
  padding-right: .75rem;
  border-color: var(--woker-danger);
}
.form-control.is-invalid:focus,
select.form-control.is-invalid:focus {
  border-color: var(--woker-danger);
  box-shadow: 0 0 0 .2rem var(--woker-danger-bg);
}
.select2-container--default.is-invalid .select2-selection--single,
.select2-container--default.is-invalid .select2-selection--multiple {
  border-color: var(--woker-danger) !important;
}
.invalid-feedback {
  display: block;
  color: var(--woker-danger);
  font-size: .78rem;
  margin-top: .35rem;
}

/* Label de un checkbox dentro de un .input-group (emisor, cotizador, credenciales): el
   patrón la marca `.form-control` para que quede a la misma altura y con la misma caja que
   los campos de al lado. La caja se conserva; lo que se saca es el resaltado de hover/foco,
   que es feedback de "podés escribir acá" y una label no es editable. Vivía scopeado a
   `.emitir-stepper`; es de la capa sistema porque el patrón se repite en los tres módulos. */
label.form-control {
  display: flex;
  align-items: center;
  margin-bottom: 0;
  cursor: default;
}

label.form-control:hover:not(:focus),
label.form-control:focus {
  border-color: var(--woker-border-control);
  box-shadow: none;
}

/* Con `for` sí se puede clickear para marcar la casilla; sin él es solo texto. */
label.form-control[for] { cursor: pointer; }

/* Prefijo/sufijo de un input-group (ícono de lupa, "$", "https://"): Bootstrap lo pinta gris
   (#e9ecef) contra el input blanco y el control se ve partido en dos. Va con la misma caja que
   `.form-control` —misma superficie, mismo borde, mismo alto— así que la única costura entre
   ícono e input es el borde que ya comparten. El ícono queda en el gris del placeholder: es
   decoración del campo, no dato. */
.input-group-text {
  background-color: var(--woker-surface);
  border: 1px solid var(--woker-border-control);
  border-radius: var(--woker-radius-control);
  color: var(--woker-subtle);
  font-size: .875rem;
  line-height: 1.5;
  padding: .5rem .75rem;
}

/* Y el foco también es del grupo, no del input solo: el resaltado va alrededor de todo
   (por eso `:focus-within` y no `:focus`) y el input cede el suyo, así no queda una caja
   resaltada adentro de otra apagada. */
.input-group:focus-within {
  border-radius: var(--woker-radius-control);
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}

.input-group:focus-within .form-control:focus,
.input-group:focus-within select.form-control:focus { box-shadow: none; }

.input-group:focus-within > .input-group-prepend > .input-group-text,
.input-group:focus-within > .input-group-append > .input-group-text {
  border-color: var(--woker-violet);
  color: var(--woker-violet);
}

/* La otra mitad del patrón del checkbox: el pill que contiene la casilla. El `:has()` lo limita
   a ese caso — ahí sí se despega de la superficie del input, porque no es un campo editable. */
.input-group-prepend > .input-group-text:has(input[type="checkbox"]) {
  display: flex;
  align-items: center;
  min-height: 40px;
  background-color: var(--woker-surface-2);
  border-color: var(--woker-border-control);
  color: var(--woker-muted);
}

.input-group-text > input[type="checkbox"] { margin: 0; accent-color: var(--woker-violet); }

/* Que el pill y la label midan lo mismo */
.input-group > label.form-control { min-height: 40px; }

/* La celda del checkbox no tiene label propio —el texto ya lo pone la etiqueta del grupo—, así que
   cuando comparte fila con campos que sí lo tienen el `.form-row` la estira a lo alto de la fila y
   el pill quedaba arriba de todo, a la altura del label del vecino y no de su caja. Alineado al
   fondo cae a la altura del input, y si la fila es solo de checkboxes no hay nada que estirar: no
   aparece aire muerto arriba. Sirve para las dos formas sin que el template tenga que saber cuál le
   toca. Deja afuera las celdas que ya traen su propio espaciador (el endoso del gestor). */
.form-row > .form-group:not(:has(> .info-label)):has(> .input-group > .input-group-prepend > .input-group-text > input[type="checkbox"]) {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/* Input file (Bootstrap .custom-file + bs-custom-file-input): viene con su propia caja
   (radio .25rem, alto y tipografía distintos) y el botón "Buscar" en gris #e9ecef, así que
   al lado de los demás controles desentona. Se alinea al .form-control: misma altura, mismo
   radio, mismo borde y foco; el botón queda como una franja en la superficie secundaria. */
.custom-file,
.custom-file-input,
.custom-file-label { height: calc(1.5 * .875rem + 1rem + 2px); }

.custom-file-label {
  display: flex;
  align-items: center;
  background-color: var(--woker-surface);
  border: 1px solid var(--woker-border-control);
  border-radius: var(--woker-radius-control);
  color: var(--woker-muted);
  font-size: .875rem;
  line-height: 1.5;
  padding: .5rem .75rem;
  margin: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}

/* El pseudo-elemento es el botón "Buscar": Bootstrap lo posiciona absoluto contra los
   4 bordes, así que el alto sale solo y el texto se centra por flex. */
.custom-file-label::after {
  display: flex;
  align-items: center;
  background-color: var(--woker-surface-2);
  border-left: 1px solid var(--woker-border-control);
  border-radius: 0 var(--woker-radius-control) var(--woker-radius-control) 0;
  color: var(--woker-muted);
  font-size: .875rem;
  line-height: 1.5;
  padding: 0 .75rem;
}

.custom-file-input:hover:not(:focus) ~ .custom-file-label { border-color: var(--woker-border-fuerte); }

.custom-file-input:focus ~ .custom-file-label {
  border-color: var(--woker-violet);
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}

/* Select nativo: sin el chrome del navegador, con el chevron propio */
select.form-control {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
  background-position: right .5rem center;
  background-repeat: no-repeat;
  background-size: 1.5em 1.5em;
  padding-right: 2.5rem;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

/* Los controles miden .875rem en TODOS los anchos. Acá había un salto a 16px en mobile (iOS
   hace zoom al enfocar un campo que mida menos) que solo alcanzaba a `.form-control`: los
   nativos subían a 16px y el resto del formulario —select2, casillas, el nombre del archivo
   elegido— se quedaba en 14px, así que el tamaño del texto terminaba dependiendo de con qué
   widget estaba hecho el campo. Se saca: un solo tamaño, y el zoom de iOS se acepta. */

/* Labels de formulario */
.info-label {
  display: block;
  color: var(--woker-muted);
  font-weight: 500;
  font-size: .875rem;
  line-height: 1.3;
  margin-bottom: .5rem;
}
.info-label .text-danger { color: var(--woker-danger); font-weight: 700; }

/* Casillas y radios nativos: el navegador los pinta con SU azul (o el accent del SO), que
   ningún auditor de color detecta porque no es CSS de autor. Va acá, en la capa de sistema,
   para que cualquier casilla suelta —incluidas las de los modales compartidos— nazca en el
   color de marca sin que cada pantalla tenga que acordarse. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--woker-violet); }

/* Checkbox/switch "custom" de Bootstrap: la casilla real está oculta y lo que se ve es el
   `::before` del label, pintado con el azul de Bootstrap. `accent-color` no lo toca (no hay
   control nativo que pintar) y ningún auditor lo ve como azul de la pantalla, así que va acá,
   una sola vez, para todo el stack nuevo. */
.custom-control-input:checked ~ .custom-control-label::before {
  background-color: var(--woker-violet);
  border-color: var(--woker-violet);
}
.custom-control-input:focus ~ .custom-control-label::before {
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .25);
}
.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {
  border-color: var(--woker-violet);
}
.custom-control-input:not(:disabled):active ~ .custom-control-label::before {
  background-color: var(--woker-violet-soft);
  border-color: var(--woker-violet);
}

/* Switch (`.custom-control.custom-switch`): Bootstrap lo dibuja como un cuadradito redondeado
   con la perilla gris pegada al borde, que no es la forma del toggle nuevo (el de Modo oscuro
   del menú de usuario: riel pill, perilla blanca, violeta al encender). Se redefine acá, en la
   capa de sistema, para que cualquier switch nazca con la estética nueva sin tocar el markup
   ni los widgets del form. Solo cambia la forma: las medidas siguen siendo las de Bootstrap
   (riel 1.75rem × 1rem), que al lado de un label de formulario pesan menos que el toggle del
   menú de usuario. */
.custom-switch .custom-control-label::before {
  border: none;
  border-radius: 999px;
  background-color: var(--woker-border-fuerte);
  transition: background-color .15s var(--woker-ease);
}
.custom-switch .custom-control-label::after {
  border-radius: 50%;
  background-color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
  transition: transform .15s var(--woker-ease);
}
.custom-switch .custom-control-input:checked ~ .custom-control-label::after {
  background-color: #fff;
}

/* Bootstrap clava el riel a `top: .25rem` contando una etiqueta de 1rem: con cualquier otro
   tamaño de texto el toggle queda alto o bajo respecto de su etiqueta. Con el label como
   contenedor de referencia, el 50% es el de la línea de texto y el riel se centra siempre.
   El translateX del encendido se repisa porque en Bootstrap es un `transform` suelto que
   pisaría el centrado. */
.custom-switch .custom-control-label {
  position: relative;
}
.custom-switch .custom-control-label::before,
.custom-switch .custom-control-label::after {
  top: 50%;
  transform: translateY(-50%);
}
.custom-switch .custom-control-input:checked ~ .custom-control-label::after {
  transform: translate(.75rem, -50%);
}

/* Checkbox nativo (Bootstrap .form-check): accent de marca + texto acorde a los form controls */
.form-check-input { accent-color: var(--woker-violet); }
.form-check-label { color: var(--woker-muted); font-size: .875rem; }

/* Radio de un `.form-check`: el control nativo dibuja el punto interior en el color del lienzo,
   así que con `color-scheme: dark` el marcado sale violeta con el punto NEGRO —se lee como una
   dona— y el apagado, como un disco gris macizo. Se dibuja a mano (mismo criterio que la casilla
   de los modales) para que el punto sea siempre blanco y el apagado, un aro sobre la superficie:
   el radio queda igual en los dos temas. `appearance: none` obliga a fijar el tamaño, porque el
   que traía era el del control del SO. */
.form-check-input[type="radio"] {
  width: 15px;
  height: 15px;
  appearance: none;
  -webkit-appearance: none;
  border: 1.5px solid var(--woker-border-fuerte);
  border-radius: 50%;
  background-color: var(--woker-surface);
  cursor: pointer;
  transition: var(--woker-transicion);
}
.form-check-input[type="radio"]:checked {
  border-color: var(--woker-violet);
  background-color: var(--woker-violet);
  background-image: radial-gradient(circle at center, #fff 0 3px, transparent 3px);
}
/* El foco se ve solo cuando se llega por teclado, igual que en la casilla de los modales. */
.form-check-input[type="radio"]:focus-visible {
  outline: 0;
  border-color: var(--woker-violet);
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}
.form-check-input[type="radio"]:disabled { cursor: default; opacity: .6; }

/* Grupo de opciones (checkbox o radio) que se listan juntas: grilla que acomoda tantas columnas
   como entren según el largo de las etiquetas, en vez de col-* fijas que dejan huecos enormes
   cuando las etiquetas son cortas. Cada opción es un .form-check de Bootstrap.
   El min() del minmax es lo que evita que en mobile la columna quede más ancha que la pantalla. */
.opciones-check {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
  gap: .4rem 1rem;
}
.opciones-check .form-check { margin-bottom: 0; }
/* Una sola columna: opciones excluyentes cortas que se leen mejor apiladas. */
.opciones-check.opciones-check-apiladas { grid-template-columns: 1fr; }
/* Etiquetas largas (nombres de cobertura): columnas más anchas para que no corten. */
.opciones-check.opciones-check-anchas { grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }

/* Checkbox suelto en una celda, sin el .form-check que lo envuelve: Bootstrap lo saca de flujo
   (position:absolute + margin-left negativo) para armar ese layout, y en una celda queda corrido
   a la izquierda y por debajo del centro. Dentro de la tabla vuelve al flujo y se centra con
   la celda (que ya es vertical-align:middle). */
.tabla-moderna td > .form-check-input {
  position: static;
  margin: 0;
  vertical-align: middle;
}

/* Botones de formulario (los usan también los modales compartidos) */
.btn-minimal {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  border: none;
  padding: .5rem 1rem;
  border-radius: var(--woker-radius-control);
  font-size: .875rem;
  font-weight: 600;
  transition: var(--woker-transicion);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}
.btn-minimal:hover { text-decoration: none; }
.btn-minimal:active { transform: translateY(1px); }

/* background-color en longhand a propósito: con var() el shorthand no expande los longhands en el CSSOM */
.btn-minimal.btn-primary { background-color: var(--woker-violet); border-color: var(--woker-violet); color: #fff; }
.btn-minimal.btn-primary:hover { background-color: var(--woker-violet-hover); border-color: var(--woker-violet-hover); color: #fff; transform: translateY(-1px); }
.btn-minimal.btn-outline { background: var(--woker-surface); color: var(--woker-muted); border: 1px solid var(--woker-border); }
.btn-minimal.btn-outline:hover { background: var(--woker-surface-2); color: var(--woker-ink); border-color: var(--woker-border-fuerte); }
/* Ghost: "crear/agregar" dentro de una card, sin caja para no competir con el submit de la
   pantalla. Borde transparente: iguala el alto con .btn-outline, que sí lo tiene. */
.btn-minimal.btn-ghost { background: transparent; color: var(--woker-violet); border: 1px solid transparent; }
.btn-minimal.btn-ghost:hover { background: var(--woker-violet-tint); color: var(--woker-violet); }
.btn-minimal.btn-ghost:disabled { color: var(--woker-subtle); background: transparent; }
.btn-minimal.btn-success { background-color: var(--woker-ok); border-color: var(--woker-ok); color: #fff; }
.btn-minimal.btn-success:hover { background-color: #128a43; border-color: #128a43; color: #fff; transform: translateY(-1px); }
.btn-minimal.btn-danger { background-color: var(--woker-danger); border-color: var(--woker-danger); color: #fff; }
.btn-minimal.btn-danger:hover { background-color: #b91c1c; border-color: #b91c1c; color: #fff; transform: translateY(-1px); }

/* Estados :focus / :active. Bootstrap repinta .btn-primary/.btn-success/.btn-danger con SU
   paleta (el azul #0062cc al apretar) desde `.btn-primary:not(:disabled):not(.disabled):active`,
   que tiene más especificidad que las reglas de arriba. Se reafirma el color de cada variante
   y el anillo de foco pasa al color de marca, solo con teclado (:focus-visible). */
.btn-minimal:focus { outline: 0; box-shadow: none; }
.btn-minimal:focus-visible { outline: 0; box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .25); }
.btn-minimal.btn-primary:not(:disabled):not(.disabled):active,
.btn-minimal.btn-primary:not(:disabled):not(.disabled):active:focus { background-color: var(--woker-violet-hover); border-color: var(--woker-violet-hover); color: #fff; }
.btn-minimal.btn-success:not(:disabled):not(.disabled):active,
.btn-minimal.btn-success:not(:disabled):not(.disabled):active:focus { background-color: #128a43; border-color: #128a43; color: #fff; }
.btn-minimal.btn-danger:not(:disabled):not(.disabled):active,
.btn-minimal.btn-danger:not(:disabled):not(.disabled):active:focus { background-color: #b91c1c; border-color: #b91c1c; color: #fff; }
.btn-minimal:not(:disabled):not(.disabled):active:focus-visible { box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .25); }

/* Select2 — enhance de los <select>. Los !important ganan a select2.min.css */

.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
  font-size: .875rem !important;
  font-weight: 400 !important;
  line-height: 1.5 !important;
  color: var(--woker-muted) !important;
  border: 1px solid var(--woker-border-control) !important;
  /* El mismo radio que .form-control: un select y un input vecinos no pueden tener
     esquinas distintas (se ve en cualquier form con los dos al lado). */
  border-radius: var(--woker-radius-control) !important;
  background-color: var(--woker-surface) !important;
}

.select2-container--default .select2-selection--single {
  height: calc(1.5em + 1rem + 2px) !important;
  padding: 0 !important;
  display: flex !important;
  align-items: center !important;
}

.select2-container--default .select2-selection--single .select2-selection__rendered {
  display: block !important;
  box-sizing: border-box !important;
  height: calc(1.5em + 1rem + 2px) !important;
  /* line-height + padding-top centran el texto en altura */
  line-height: calc(1.5em + 1rem - 1px) !important;
  padding-top: 3px !important;
  padding-left: .75rem !important;
  padding-right: 2.5rem !important;
  color: var(--woker-muted) !important;
  width: 100% !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

.select2-container--default .select2-selection--single .select2-selection__arrow {
  height: calc(1.5em + 1rem + 2px) !important;
  right: .5rem !important;
  top: 0 !important;
}

/* Vacío tiene que medir lo mismo que un .form-control al lado (el padding de select2
   lo hacía 3px más alto); con opciones elegidas crece con las pastillas. */
.select2-container--default .select2-selection--multiple {
  min-height: calc(1.5em + 1rem + 2px) !important;
  padding: 0 .5rem !important;
  display: flex !important;
  align-items: center !important;
}

/* Select2 arma las pastillas con una <ul> inline-block y <li> flotadas: contra el
   min-height del contenedor quedaban pegadas ARRIBA y todo el aire sobrante abajo.
   En flex se centran solas y siguen envolviendo cuando son muchas. */
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
  display: flex !important;
  flex-wrap: wrap;
  align-items: center;
  width: 100%;
  margin: 0 !important;
  padding: 0 !important;
}

/* Foco en color de marca, igual que .form-control.
   outline:0 igual que en .form-control:focus — la selección de select2 es tabindex="0",
   así que sin esto Chrome pinta ENCIMA su anillo nativo azul (auto 1px rgb(0,95,204)) y
   tapa el violeta. El indicador de foco accesible lo sigue dando el box-shadow. */
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple {
  border-color: var(--woker-violet) !important;
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15) !important;
  outline: 0 !important;
}

/* Chips del multi-select en color de marca */
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  background-color: var(--woker-violet-soft) !important;
  border: 1px solid var(--woker-violet-soft-border) !important;
  color: var(--woker-violet) !important;
  font-size: .875rem !important;
  /* El margen de select2 es asimétrico (5px arriba, 0 abajo) para compensar el float:
     centradas en flex ese margen las bajaría media pastilla. */
  margin: 2px 5px 2px 0 !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove { color: var(--woker-violet) !important; }

/* La "×" de limpiar (allowClear) es el PRIMER hijo del rendered y select2 la manda a la
   derecha con float: right — que en el contenedor flex de acá arriba no hace nada, así que
   quedaba pegada al borde izquierdo, delante del primer valor. El orden y el margen
   automático la devuelven al extremo derecho. Va en la capa de sistema porque el flex del
   rendered también es de sistema: afecta a TODO select2 múltiple (filtros, modales, forms). */
.select2-container--default .select2-selection__clear { order: 1; margin-left: auto; }

/* Desplegable — neutro a propósito: las opciones NO se pintan con el color de marca.
   Lleva el borde de control, no el de card: cuelga pegado a la caja que lo abre y con dos
   grises distintos se ve el escalón entre una y otra. */
.select2-dropdown {
  border: 1px solid var(--woker-border-control) !important;
  border-radius: 8px !important;
  box-shadow: 0 10px 25px rgba(0, 0, 0, .08) !important;
  overflow: hidden;
  background: var(--woker-surface) !important;
}
/* Reveal del desplegable al abrir: fade + leve subida (se reproduce en cada apertura) */
.select2-dropdown { animation: woker-dropdown-in .16s var(--woker-ease); transform-origin: top; }
@keyframes woker-dropdown-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.select2-results__options { padding: 4px !important; }
.select2-results__option {
  padding: 8px 12px !important;
  font-size: .8125rem !important;
  color: var(--woker-muted) !important;
  border-radius: 6px !important;
  margin: 0 0 2px !important;
  transition: background-color .15s ease, color .15s ease !important;
}
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
  background-color: var(--woker-surface-2) !important;
  color: var(--woker-ink) !important;
}
.select2-container--default .select2-results__option[aria-selected="true"] {
  background-color: var(--woker-surface-2) !important;
  color: var(--woker-ink) !important;
  font-weight: normal !important;
}

/* Buscador del desplegable — solo el del popup, no el input inline del multi-select */
.select2-search--dropdown { padding: 10px 12px !important; }
.select2-container--default .select2-search--dropdown .select2-search__field {
  border: 1px solid var(--woker-border-control) !important;
  border-radius: 6px !important;
  padding: 8px 12px !important;
  font-size: .8125rem !important;
  color: var(--woker-muted) !important;
  background: var(--woker-surface-2) !important;
  outline: none !important;
}
.select2-container--default .select2-search--dropdown .select2-search__field:focus {
  border-color: var(--woker-border-fuerte) !important;
  background: var(--woker-surface) !important;
  box-shadow: 0 0 0 2px rgba(var(--woker-violet-rgb), .15) !important;
  outline: none !important;
}

/* Input inline del multi-select: sin borde propio (el foco lo muestra el contenedor,
   no este input) — si no, hereda el azul de AdminLTE al tipear */
.select2-container--default .select2-search--inline .select2-search__field,
.select2-container--default .select2-search--inline .select2-search__field:focus {
  border: none !important;
  box-shadow: none !important;
  outline: none !important;
}

/* Date picker (bootstrap-daterangepicker) — el plugin trae sus propios azules
   (#357ebd el día activo, #08c el rango elegido, #ebf4f8 el rango marcado) y el
   botón Aplicar hereda el .btn-primary de Bootstrap. Acá se pasan al color de
   marca de la organización. El dark lo termina de ajustar dark-mode.css, que
   carga después y gana por especificidad (html[data-theme="dark"] ...). */
.daterangepicker td.active,
.daterangepicker td.active:hover { background-color: var(--woker-violet); border-color: transparent; color: #fff; }
.daterangepicker td.in-range { background-color: var(--woker-violet-tint); color: var(--woker-ink); }
.daterangepicker .ranges li.active { background-color: var(--woker-violet); color: #fff; }
.daterangepicker .drp-buttons .btn.applyBtn,
.daterangepicker .drp-buttons .btn.applyBtn:hover,
.daterangepicker .drp-buttons .btn.applyBtn:focus {
  background-color: var(--woker-violet);
  border-color: var(--woker-violet);
  color: #fff;
  box-shadow: none;
}
.daterangepicker .drp-buttons .btn.applyBtn:hover { background-color: var(--woker-violet-hover); border-color: var(--woker-violet-hover); }

/* Card de filtros (listado_base.html) — el aspecto "renglón" de los campos vive en listado.css */
.filters-card { background:var(--woker-surface); border:1px solid var(--woker-border); border-radius:var(--woker-radius); box-shadow:var(--woker-card-shadow); overflow:hidden; margin-bottom:1.5rem; }
.filters-header { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:8px 20px; background:var(--woker-surface-2); }
.filters-header-left { display:flex; align-items:center; gap:.8rem; }
.filters-title { font-size:15px; font-weight:600; color:var(--woker-muted); margin:0; }
/* El separador aparece recién con el panel abierto */
.filters-card:has(#filters-container:not([style*="display: none"])) .filters-header { border-bottom:1px solid var(--woker-border); }

#filters-container { padding:1.5rem; padding-top:1.25rem; }

/* Acciones del panel: Limpiar + Buscar agrupados a la derecha.
   Sin border-top: un separador ocuparía solo una columna cuando las acciones van en
   línea en la última fila (parcial) y se vería como una línea suelta.
   align-items:flex-end: si las acciones comparten fila con campos, la columna se estira
   a la altura de la fila y los botones bajan al nivel del input; si caen en su propia
   fila, la columna mide lo que los botones y quedan ajustados (la separación la da el
   margin-bottom del último campo). Así se ve bien en ambos casos sin un hueco de más. */
.filters-actions { display:flex; justify-content:flex-end; align-items:flex-end; flex-wrap:wrap; gap:.75rem; }
.filters-actions .btn-minimal { padding:.55rem 1.15rem; border-radius:8px; }

/* Toggle del panel: texto "Mostrar/Ocultar filtros" + chevron, en color de marca */
.filters-header .btn-collapse { display:inline-flex; align-items:center; gap:6px; flex-shrink:0; width:auto; height:auto; padding:6px 8px; border:none; border-radius:8px; font-size:13px; font-weight:500; white-space:nowrap; color:var(--woker-violet); background:none; cursor:pointer; }
.filters-header .btn-collapse { transition:color .12s var(--woker-ease); }
.filters-header .btn-collapse:hover { background:transparent; color:var(--woker-violet-hover); }
.filters-header .btn-collapse .chevron { width:16px; height:16px; flex-shrink:0; transition:transform .2s ease; }
.filters-header .btn-collapse.is-open .chevron { transform:rotate(180deg); }

@media (max-width: 575.98px) {
  .filters-header { padding:8px 1rem; }
  #filters-container { padding:1rem; }
}

/* Responsive header de pantalla (<xl): título arriba, acciones en grilla abajo */
@media (max-width: 1499.98px) {
  .pantalla-actions > .btn-flat,
  .pantalla-actions > .btn-purple,
  .pantalla-actions > .btn-split > .btn-purple,
  .form-card-actions > .btn-flat,
  .form-card-actions > .btn-purple { font-size: .75rem; padding: .35rem .7rem; gap: .35rem; }
  .pantalla-actions > .btn-split > .btn-purple:last-child { padding-left: .45rem; padding-right: .45rem; }
}

/* Mientras haya ancho suficiente (≥768px) los mantenemos en UNA sola fila, sin envolver. */
@media (min-width: 768px) and (max-width: 1499.98px) {
  .pantalla-actions { flex-wrap: nowrap; gap: .4rem; }
}

/* Título arriba, acciones abajo a su ancho natural (no se estiran).
   Solo <768px: arriba de eso alcanza con el flex-wrap del header, que baja las
   acciones a una segunda línea únicamente si NO entran al lado del título. Con
   el corte en 1200px una pantalla de una sola acción (ej. estadísticas, un
   "Exportar Excel") la mandaba abajo con media pantalla libre al costado. */
@media (max-width: 767.98px) {
  .pantalla-header { flex-direction: column; align-items: stretch; }
  /* En columna el eje principal es el vertical: el basis 0 del header pasaría a ser
     una altura, no un ancho. Acá el bloque vuelve a medir lo que mide su contenido. */
  .pantalla-header-left { flex: 0 1 auto; min-width: 0; }
}

/* En pantallas muy chicas: acciones en grilla de 2 columnas parejas */
@media (max-width: 575.98px) {
  .pantalla-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem;
    width: 100%;
  }
  .pantalla-actions > .btn-flat,
  .pantalla-actions > .btn-purple,
  .pantalla-actions > .btn-split {
    width: 100%;
    justify-content: center;
    text-align: center;
    white-space: normal;
  }
  /* El botón partido reparte su ancho: la acción principal se estira, el caret queda fijo */
  .pantalla-actions > .btn-split > .btn-purple:first-child { flex: 1 1 auto; justify-content: center; }
  /* El pie reparte a lo ancho: con dos botones quedan parejos, con uno ocupa todo */
  .form-card-actions > .btn-flat,
  .form-card-actions > .btn-purple {
    flex: 1 1 0;
    justify-content: center;
    text-align: center;
    white-space: normal;
  }
}

@media (max-width: 767.98px) {
  .form-card-actions { padding-top: 1rem; }
  .form-card-actions--bleed { padding: 1rem 1.1rem; }
}

/* Modales (genérico) */

/* Botones primary en color de marca dentro de cualquier modal (Bootstrap usa azul literal) */
.modal .btn-primary { background-color: var(--woker-violet) !important; border-color: var(--woker-violet) !important; }
.modal .btn-primary:hover { background-color: var(--woker-violet-hover) !important; border-color: var(--woker-violet-hover) !important; }

/* Footer de modales apilado en mobile (<sm) */
@media (max-width: 575.98px) {
    .modal-footer { justify-content: center !important; }
    .modal-footer .btn { width: 100%; margin: .2rem 0; }
}

/* Modal de importación — diseño pasos, timeline vertical (modalImportacion.html) */

.modal-woker {
    /* Tamaño del número de paso; el conector se posiciona respecto de él */
    --import-num-size: 36px;
}

/* El centrado del diálogo (vertical y horizontal) y el ancho del envoltorio cuando hay un
   `<form>` en el medio los resuelve `modales.css` para TODOS los modales del sistema. */

.modal-woker .modal-content {
    border-radius: var(--woker-radius);
    overflow: hidden;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .06), 0 8px 24px rgba(0, 0, 0, .10), 0 24px 64px rgba(0, 0, 0, .10);
}

/* Header: chip + título con subtítulo, y X de cierre en botón cuadrado.
   Sin divisor y sin franja propia: las tres secciones comparten superficie y el
   ritmo vertical lo marca un único valor de padding (1.25rem). */
.modal-woker .modal-header {
    align-items: center;
    gap: 1rem;
    padding: 1.25rem 1.5rem 0 !important;
    border-bottom: 0;
    /* La franja gris de header/footer la ponen tanto modern-modals.css como el CSS de varias
       pantallas (gestor.css) con un `.modal-header` suelto: se anula acá para
       que la superficie única del modal valga en claro igual que en oscuro (dark-mode.css §Modales). */
    background: transparent !important;
}

.modal-woker .modal-title {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 1.125rem !important;
    font-weight: 700 !important;
    line-height: 1.3 !important;
}

.modal-title-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 8px;
    background: rgba(var(--woker-violet-rgb), .06);
    border: 1px solid var(--woker-violet-soft);
    line-height: 0;
    color: var(--woker-violet);
}

.modal-title-icon svg {
    display: block;
    width: 19px;
    height: 19px;
}

/* Variantes de rol del chip del header. El default es el violeta de marca (acciones
   normales); estas cuatro son para modales que comunican un estado — confirmaciones de
   borrado, avisos, errores de validación, resultados. Salen de los tokens de rol, así que
   dark-mode.css no necesita una regla propia. */
/* El borde sale del propio color con color-mix y no de un rgba fijo: --woker-warn y
   --woker-info se reasignan en oscuro, y con el rgba del valor claro el borde quedaba de otro
   tono que el ícono. Para is-danger el resultado es idéntico al rgba(220,38,38,.35) que tenía. */
.modal-title-icon.is-danger,
.modal-title-icon.is-warn,
.modal-title-icon.is-info,
.modal-title-icon.is-ok {
    border-color: color-mix(in srgb, currentColor 35%, transparent);
}

.modal-title-icon.is-danger { background: var(--woker-danger-bg); color: var(--woker-danger); }
.modal-title-icon.is-warn   { background: var(--woker-warn-bg);   color: var(--woker-warn); }
.modal-title-icon.is-info   { background: var(--woker-info-bg);   color: var(--woker-info); }
.modal-title-icon.is-ok     { background: var(--woker-ok-bg);     color: var(--woker-ok); }

.modal-title-text {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}

.modal-title-main {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--woker-ink);
    line-height: 1.3;
}

.modal-title-sub {
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--woker-muted);
    line-height: 1.4;
}

/* X de cierre en botón cuadrado con hover violeta suave; área de toque ampliada a 48px */
.modal-woker .modal-header .close {
    position: relative;
    flex-shrink: 0;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 32px !important;
    height: 32px !important;
    min-width: 0 !important;
    min-height: 0 !important;
    padding: 0 !important;
    border: none !important;
    border-radius: 8px !important;
    background: transparent !important;
    color: var(--woker-muted) !important;
    opacity: 1 !important;
    transition: var(--woker-transicion);
}

.modal-woker .modal-header .close::before {
    content: '';
    position: absolute;
    inset: -8px;
}

.modal-woker .modal-header .close:hover {
    background-color: var(--woker-violet-soft) !important;
    color: var(--woker-violet) !important;
}

.modal-woker .modal-body {
    padding: 1.5rem !important;
}

/* Booleanos de un formulario: los del cuerpo de un modal (`.form-group.form-check`) y los de una
   `.form-card` de pantalla (`.campo-check`). Bootstrap los deja como una casilla nativa de 13px
   con el texto al lado y sin caja, así que al lado de los campos —que sí son cajas de borde
   completo— se leen como texto suelto en el medio del formulario. Cada opción pasa a ser una fila
   con la misma caja que un `.form-control` y la casilla dibujada en el color de marca, con el
   mismo tilde que el chip `.vc-toggle` del cotizador. Va en la capa sistema porque es el booleano
   de todo el stack nuevo (editar cotización, importar cartera, registrar usuario), no el de una
   pantalla.
   Quedan afuera las opciones de una grilla `.opciones-check` (selector de permisos, widget):
   ahí cada `.form-check` es un ítem de una lista de decenas, no un booleano suelto, y la caja
   por opción las agranda tanto que la lista deja de leerse. */
.modal-woker .modal-body .form-check:not(.opciones-check *),
.campo-check {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .625rem;
  min-height: 40px;
  padding: .5rem .75rem;
  border: 1px solid var(--woker-border-control);
  border-radius: var(--woker-radius-control);
  background-color: var(--woker-surface);
  transition: var(--woker-transicion);
}

/* En un modal el booleano es una línea suelta del cuerpo y se separa solo; en una `.form-card`
   la separación ya la pone el `.form-group` que lo envuelve. */
.modal-woker .modal-body .form-check:not(.opciones-check *) { margin-bottom: .5rem; }

.modal-woker .modal-body .form-check:not(.opciones-check *):hover,
.campo-check:hover { border-color: var(--woker-border-fuerte); }

/* Bootstrap saca la casilla del flujo (absolute + margin-left negativo) para armar su layout de
   dos columnas; acá la fila es flex y la casilla vuelve a ser un item más. Se dibuja a mano
   (`appearance: none`) porque el control nativo trae el tamaño y el borde del SO.
   `.campo-check` matchea por elemento y no por clase: adentro caen los `{{ field }}` de forms
   que se arman solos (credenciales, emisor) y que no necesariamente traen `form-check-input`. */
.modal-woker .modal-body .form-check:not(.opciones-check *) .form-check-input[type="checkbox"],
.campo-check input[type="checkbox"] {
  position: static;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 0;
  appearance: none;
  -webkit-appearance: none;
  border: 1.5px solid var(--woker-border-fuerte);
  border-radius: 5px;
  background: center / 11px no-repeat;
  cursor: pointer;
  transition: var(--woker-transicion);
}

.modal-woker .modal-body .form-check:not(.opciones-check *) .form-check-input[type="checkbox"]:checked,
.campo-check input[type="checkbox"]:checked {
  background-color: var(--woker-violet);
  border-color: var(--woker-violet);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.2 5 8.5 9.5 3.5'/%3E%3C/svg%3E");
}

/* El foco se ve solo cuando se llega por teclado: con el mouse el estado ya lo cuenta el tilde. */
.modal-woker .modal-body .form-check:not(.opciones-check *) .form-check-input[type="checkbox"]:focus-visible,
.campo-check input[type="checkbox"]:focus-visible {
  outline: 0;
  border-color: var(--woker-violet);
  box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}

/* Deshabilitada (ej. cotización vencida: el form llega con todos los campos apagados) */
.modal-woker .modal-body .form-check:not(.opciones-check *):has(.form-check-input:disabled),
.campo-check:has(input:disabled) { background-color: var(--woker-surface-2); }
.modal-woker .modal-body .form-check:not(.opciones-check *) .form-check-input:disabled,
.campo-check input:disabled,
.modal-woker .modal-body .form-check:not(.opciones-check *):has(.form-check-input:disabled) .form-check-label,
.campo-check:has(input:disabled) > label {
  cursor: default;
  opacity: .6;
}

/* La etiqueta ocupa el resto de la fila para que se pueda clickear en cualquier parte, y va en
   el color del texto (no en el gris de ayuda): acá es el nombre de la opción, no un apoyo. */
.modal-woker .modal-body .form-check:not(.opciones-check *) .form-check-label,
.campo-check > label {
  flex: 1;
  min-width: 0;
  margin: 0;
  cursor: pointer;
  color: var(--woker-ink);
}

/* El error del campo se renderiza dentro de la misma fila: va abajo, a lo ancho. */
.modal-woker .modal-body .form-check:not(.opciones-check *) > .errorlist,
.campo-check > .errorlist { flex: 0 0 100%; margin: 0; }

/* Un booleano no lleva label arriba, así que en una fila donde los demás campos sí lo llevan
   arrancaba pegado al techo y quedaba a la altura de los labels en vez de la de los campos
   (ej. Conexión SSL/TLS al lado de Host y Puerto). La columna ya se estira al alto de la fila
   —`.form-row` es flex—, así que apoyando su contenido abajo la caja cierra pareja con los
   `.form-control` de al lado. */
.form-row > .form-group:has(> .campo-check),
.row > [class*="col"] > .form-group:has(> .campo-check) {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/* Variante `.row > .col > .form-group` (los steps del emisor): ahí la que se estira al alto de
   la línea es la columna, así que el grupo tiene que crecer dentro de ella para poder apoyar
   la caja abajo. Si la columna no es flex, `flex-grow` no hace nada y el grupo queda como está. */
.row > [class*="col"] > .form-group:has(> .campo-check) { flex: 1 1 auto; }

/* El último bloque del cuerpo (form-group, párrafo) trae su propio margin-bottom, que se
   sumaba al padding y dejaba el aire contra los botones más grande que el de arriba
   (20px arriba vs 36px abajo). Anulándolo, el padding del body manda solo y el cuerpo
   queda centrado entre el header y el footer.
   La segunda regla es para los cuerpos que terminan en un contenedor de errores vacío
   (ej. #form-grupo-errores): ahí el margen que sobra es el del último bloque con contenido. */
.modal-woker .modal-body > :last-child,
.modal-woker .modal-body > :nth-last-child(2):has(+ :empty:last-child) { margin-bottom: 0; }
/* Si el último bloque es un booleano, su propia regla (más específica por el :not) le devolvía
   el .5rem y el aire contra los botones quedaba más grande que el que rodea al footer. */
.modal-woker .modal-body > .form-check:not(.opciones-check *):last-child,
.modal-woker .modal-body > .form-check:not(.opciones-check *):nth-last-child(2):has(+ :empty:last-child) { margin-bottom: 0; }
/* Y el propio contenedor vacío tampoco debe aportar aire mientras no tenga contenido. Lleva
   !important porque algún módulo le da su margen con un selector con id (ej. gestor.css:
   `#modalFusionarAsegurados .errores-fusion`), que si no gana por especificidad. En cuanto el
   contenedor recibe el mensaje de error deja de ser :empty y recupera su separación. */
.modal-woker .modal-body > :empty:last-child { margin-top: 0 !important; }

/* Los dos casos que esa regla no alcanza, porque el margen que sobra no está en el hijo
   directo del cuerpo sino un nivel más adentro:
   - la última línea es una fila (.form-row, ej. Altura/Piso/Departamento del modal de
     domicilio): el margen lo traen sus .form-group. Se absorbe con -1rem en la fila y no con
     0 en los campos para que, si la fila envuelve en mobile, las líneas sigan separadas.
   - la última línea vive en un bloque de campos condicionales (.modal-campos-condicionales,
     ej. tarjeta/CBU del modal de forma de pago, que se muestran según el tipo elegido). */
.modal-woker .modal-body > .form-row:last-child,
.modal-woker .modal-body > .form-row:nth-last-child(2):has(+ :empty:last-child),
.modal-woker .modal-body .modal-campos-condicionales > .form-row:last-child { margin-bottom: -1rem; }
.modal-woker .modal-body .modal-campos-condicionales > .form-group:last-child { margin-bottom: 0; }

/* Y mientras no haya ningún bloque condicional visible (el tipo todavía sin elegir), el
   último bloque con alto es el campo que los precede. Los bloques se muestran/ocultan con
   display inline (jQuery show/hide), así que el estado se lee del atributo style. */
.modal-woker .modal-body:not(:has(.modal-campos-condicionales:not([style*="display: none"]))) > .form-group:has(+ .modal-campos-condicionales) { margin-bottom: 0; }

/* Campos de un modal en dos columnas (`.modal-campos-grid`). Es para los cuerpos con muchos
   campos —el de editar cotización llega a quince, porque cada compañía suma los suyos a los de
   la base—: apilados el cuerpo queda más alto que la ventana y scrollea, mientras a los costados
   del formulario sobra ancho.
   Las dos columnas arrancan en `lg`, que es donde Bootstrap le da al diálogo `.modal-lg` sus
   800px; abajo el diálogo mide 500px y una sola columna es la que entra. La grilla vale también
   en una columna para que el aire entre campos lo dé el `gap` y no el margen de cada uno, que
   entre un campo y un booleano no es el mismo y dejaría el ritmo desparejo. */
.modal-woker .modal-body .modal-campos-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem 1.25rem;
    align-items: start;
}
.modal-woker .modal-body .modal-campos-grid > .form-group { margin-bottom: 0; }

/* Misma idea que en el `.form-row` de los modales de credencial: el booleano no tiene label arriba,
   así que cuando le toca compartir fila con un campo que sí lo tiene quedaba pegado al techo de la
   fila —a la altura del label del vecino— en vez de a la de su caja. Al fondo cae a la altura del
   input, y en las filas que son solo booleanos la fila mide lo que ellos: no aparece aire muerto. */
.modal-woker .modal-body .modal-campos-grid > .form-check { align-self: end; }

@media (min-width: 992px) {
    .modal-woker .modal-body .modal-campos-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* Los de selección múltiple (select2 de adicionales, descuentos, promociones) crecen en alto
       con cada opción elegida: van a lo ancho de la fila para no estirar a su vecino. */
    .modal-woker .modal-body .modal-campos-grid > .form-group:has(select[multiple]) { grid-column: 1 / -1; }
}

/* Estado de carga de un modal: velo sobre el propio cuerpo en vez de un spinner
   insertado en el flujo, que empujaba el formulario y cambiaba el alto del modal.
   El :has() evita tocar el posicionamiento de los cuerpos que no lo usan. */
.modal-body:has(> .modal-cargando) { position: relative; }

/* Mientras el velo está visible el cuerpo no scrollea: el velo cubre el área visible del
   cuerpo, así que scrollear dejaría el formulario a la vista por debajo. El estado se lee
   del atributo style porque se muestra/oculta con jQuery show/hide. */
.modal-body:has(> .modal-cargando:not([style*="display: none"])) { overflow: hidden; }

.modal-cargando {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    padding: 1rem;
    text-align: center;
    background: color-mix(in srgb, var(--woker-surface) 84%, transparent);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

/* Misma espera, pero a nivel de PANTALLA: el contenido de un modal que se trae por AJAX
   (abrirModal) todavía no tiene cuerpo donde apoyar el velo, así que se cubre todo.
   z-index por debajo del backdrop de Bootstrap (1040) a propósito: si la carga falla y el
   velo queda colgado, el modal sigue siendo usable en vez de quedar tapado. */
.pantalla-cargando {
    position: fixed;
    inset: 0;
    z-index: 1031;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    padding: 1rem;
    text-align: center;
    background: color-mix(in srgb, var(--woker-page-bg) 82%, transparent);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.modal-cargando-ring,
.pantalla-cargando-ring {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 3px solid rgba(var(--woker-violet-rgb), .22);
    border-top-color: var(--woker-violet);
    animation: modalCargandoGiro .8s linear infinite;
}

@keyframes modalCargandoGiro { to { transform: rotate(360deg); } }

.modal-cargando-titulo,
.pantalla-cargando-titulo { font-size: .95rem; font-weight: 600; color: var(--woker-ink); }
.modal-cargando-sub,
.pantalla-cargando-sub { font-size: .8rem; color: var(--woker-muted); max-width: 34ch; line-height: 1.4; }

@media (prefers-reduced-motion: reduce) {
    .modal-cargando-ring,
    .pantalla-cargando-ring { animation: none; }
}

/* Los cierres quedan deshabilitados mientras se espera la respuesta */
.modal-woker .modal-header .close:disabled { opacity: .45 !important; cursor: not-allowed; }
.modal-woker .modal-header .close:disabled:hover { background: transparent !important; color: var(--woker-muted) !important; }

/* Los errores de formulario (.errorlist, .campo-error, .modal-aviso-error) viven en
   avisos.css, que base.html carga para todas las pantallas — también las que todavía
   no migraron a este archivo. */

/* Cuerpo de las confirmaciones: texto + el ítem afectado en una caja tenue */
.modal-confirm-texto {
    margin: 0 0 .75rem;
    font-size: .875rem;
    color: var(--woker-muted);
}

.modal-confirm-archivo {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .625rem .875rem;
    border: 1px solid var(--woker-border);
    border-radius: var(--woker-radius-control);
    background: var(--woker-surface-2);
}

.modal-confirm-archivo-ico {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--woker-icon);
    line-height: 0;
}

.modal-confirm-archivo-nombre {
    font-size: .875rem;
    font-weight: 600;
    color: var(--woker-ink);
    word-break: break-all;
}

/* Pasos separados por divisores horizontales; número en círculo relleno */
.import-steps {
    display: flex;
    flex-direction: column;
}

.import-step {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 0.875rem 0;
    border-bottom: 1px solid var(--woker-border);
}

.import-step:first-child {
    padding-top: 0;
}

.import-step:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.import-step-num {
    flex-shrink: 0;
    width: var(--import-num-size);
    height: var(--import-num-size);
    border-radius: 50%;
    background: var(--woker-violet-soft);
    color: var(--woker-violet);
    font-size: 0.9375rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.import-step-body {
    flex: 1;
    min-width: 0;
    /* nudge chico: el dígito del número queda a la altura del título */
    padding-top: 0.25rem;
}

.import-step-title {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--woker-ink);
    line-height: 1.3;
    margin-bottom: 0.25rem;
}

.import-step-desc {
    font-size: 0.875rem;
    color: var(--woker-muted);
    line-height: 1.55;
    margin-bottom: 0.75rem;
}

.import-step-desc:last-child {
    margin-bottom: 0;
}

/* Link Descargar — pill suave violeta (mismo botón-chico que Elegir archivo) */
.import-step-action {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 36px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--woker-violet);
    text-decoration: none;
    padding: 0.5rem 0.75rem;
    border: 1.5px solid var(--woker-violet-soft);
    border-radius: var(--woker-radius-control);
    background: rgba(var(--woker-violet-rgb), .06);
    transition: var(--woker-transicion);
}

.import-step-action:hover {
    background: var(--woker-violet-soft);
    border-color: rgba(var(--woker-violet-rgb), .4);
    color: var(--woker-violet);
    text-decoration: none;
}

/* Selector de archivo: botón "Seleccionar archivo" + hint (muestra el nombre al elegir) */
.import-file-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 40px;
    padding: 0.5rem 1rem;
    border: 1.5px solid var(--woker-border);
    border-radius: var(--woker-radius-control);
    background: var(--woker-surface);
    color: var(--woker-muted);
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: var(--woker-transicion);
}

.import-file-btn:hover,
.import-file-btn--selected {
    border-color: var(--woker-violet);
    background: rgba(var(--woker-violet-rgb), .06);
    color: var(--woker-violet);
}

.import-upload-hint {
    font-size: 0.75rem;
    color: var(--woker-muted);
    margin: 0.5rem 0 0;
}

/* Editor de logo: la imagen adentro de un marco de otro color que la superficie que lo
   rodea, para que se distinga dónde termina el fondo del logo y empieza el de la card.
   Lo usan los logos de la organización (parámetros) y el logo del usuario (perfil). */
.logo-editor { display: flex; flex-direction: column; gap: .75rem; }
.logo-editor-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem;
    background: var(--woker-surface-2);
    border: 1px solid var(--woker-border);
    border-radius: 11px;
}
/* La columna de la izquierda mide siempre lo mismo (asi los textos de la derecha arrancan
   en la misma linea) pero el marco de adentro respeta la forma real de cada logo: el
   isologo va en cuadrado, igual que en el login, y el imagologo apaisado porque es mas grande. */
.logo-editor-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 150px;
    flex-shrink: 0;
}
.logo-editor-marco {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 84px;
    padding: .5rem;
    background: var(--woker-surface);
    border: 1px solid var(--woker-border);
    border-radius: 10px;
}
.logo-editor-marco-cuadrado { width: 84px; }
.logo-editor-marco-ancho { width: 150px; }
.logo-editor-marco img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-editor-datos { display: flex; flex-direction: column; align-items: flex-start; gap: .15rem; min-width: 0; }
.logo-editor-nombre { font-size: .9rem; font-weight: 600; color: var(--woker-ink); margin: 0; }
.logo-editor-desc { font-size: .78rem; color: var(--woker-muted); margin: 0 0 .5rem; }
.logo-editor-datos .import-upload-hint { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ajustado: el ancho del marco lo define el logo, no al revés. Los logos de la organización
   sí van con ancho fijo (`-cuadrado` / `-ancho`) porque son dos filas y la columna de la
   izquierda tiene que medir igual en las dos; donde hay una sola fila no hay con qué alinear
   y un ancho fijo lo único que hace es sumarle aire al costado a un logo angosto. */
.logo-editor-marco.es-ajustado { width: auto; max-width: 100%; }

/* Sin logo cargado no hay imagen que le dé el ancho al marco: se planta a lo ancho de su
   columna (va después de `es-ajustado`, que es el que le saca el ancho fijo). Punteado y sin
   fondo para que se lea como un lugar a llenar y no como una caja rota; con el ícono alcanza,
   el texto va en los datos de al lado. */
.logo-editor-marco.es-vacio {
    width: 100%;
    background: transparent;
    border-style: dashed;
    color: var(--woker-subtle);
}
.logo-editor-marco.es-vacio .ico { width: 22px; height: 22px; }

/* Apilado: en una columna angosta (la ficha lateral del perfil) el marco y los datos no
   entran uno al lado del otro. Mismo acomodo que hace el item en mobile. */
.logo-editor-item.es-apilado { flex-direction: column; align-items: stretch; }
.logo-editor-item.es-apilado .logo-editor-preview { width: 100%; }

/* El display:flex le gana al [hidden] del user-agent (la previa del modal se esconde
   mientras estás acomodando la imagen nueva). */
.logo-editor-item[hidden] { display: none; }

@media (max-width: 575.98px) {
    .logo-editor-item { flex-direction: column; align-items: flex-start; }
    .logo-editor-preview { width: 100%; justify-content: flex-start; }
    .logo-editor-marco-ancho { width: 100%; max-width: 220px; }
}

/* Footer: misma superficie que el resto del modal, Cancelar a izquierda, Importar a derecha */
.modal-woker .modal-footer {
    padding: 0 1.5rem 1.25rem !important;
    border-top: 0;
    /* Mismo motivo que el header: el fondo gris de modern-modals.css viene con !important. */
    background: transparent !important;
}

.import-modal-footer {
    display: flex !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 0.75rem;
}

/* El 1.25rem de abajo del footer genérico cuenta con los .25rem que Bootstrap le da a cada hijo
   del footer (`.modal-footer > *`); acá esos márgenes se anulan (ver abajo), así que el padding
   tiene que valer el 1.5rem completo o el aire de abajo queda más chico que el de los costados.
   Va con `.modal-woker` adelante para empatarle la especificidad al footer genérico. */
.modal-woker .import-modal-footer {
    padding-bottom: 1.5rem !important;
}

.import-modal-footer .btn-minimal {
    width: auto !important;
    margin-bottom: 0 !important;
}

/* ── Patrón: modal de importación con divisores ───────────────────────────────
   Excepción deliberada al modal genérico, que va sin líneas y con una sola
   superficie continua. Acá el cuerpo es un instructivo por pasos —una unidad
   que se lee sola—, así que las líneas lo encuadran y separan el "qué tengo que
   hacer" del título y de las acciones.

   Se aplica por `.modal-importacion`, clase que pone modals/modalImportacion.html:
   todo "Importar X" que use ese include (usuarios, contactos, compañías por
   usuario, los que vengan) queda con el mismo formato sin tocar nada más.

   El ritmo vertical es un único valor (1.25rem) a ambos lados de cada línea, por
   eso el cuerpo pisa acá su padding vertical: con el 1.5rem del genérico la línea
   quedaba más pegada al header que a los pasos. */
.modal-importacion .modal-header {
    padding-bottom: 1.25rem !important;
    border-bottom: 1px solid var(--woker-border);
}

.modal-importacion .modal-body {
    padding: 1.25rem 1.5rem !important;
}

.modal-importacion .modal-footer {
    padding-top: 1.25rem !important;
    border-top: 1px solid var(--woker-border);
}

.modal-woker .btn-minimal.btn-primary {
    background: var(--woker-violet) !important;
    color: #fff;
}

.modal-woker .btn-minimal.btn-primary:hover {
    background: var(--woker-violet-hover) !important;
    box-shadow: 0 4px 10px rgba(var(--woker-violet-rgb), 0.35);
}

/* Foco por teclado — anillo violeta del sistema (igual que .btn-purple:focus) */
.modal-woker .modal-header .close:focus-visible,
.import-step-action:focus-visible,
.modal-woker .btn-minimal:focus-visible {
    outline: none;
    box-shadow: 0 0 0 0.2rem rgba(var(--woker-violet-rgb), .25);
}

/* Input de archivo oculto pero focusable; el foco por teclado se refleja en el botón */
.import-file-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.import-file-input:focus-visible + .import-file-btn {
    border-color: var(--woker-violet);
    box-shadow: 0 0 0 0.2rem rgba(var(--woker-violet-rgb), .25);
}

/* Feedback de pulsado */
.import-step-action:active,
.modal-woker .btn-minimal:active {
    transform: translateY(1px);
}

/* Importar: deshabilitado hasta elegir archivo, y estado cargando durante la subida */
.btn-minimal-import[disabled],
.btn-minimal-import.is-loading {
    opacity: .55;
    pointer-events: none;
}

.btn-minimal-import.is-loading {
    position: relative;
    color: transparent !important;
}

.btn-minimal-import.is-loading::after {
    content: '';
    position: absolute;
    top: calc(50% - 8px);
    left: calc(50% - 8px);
    width: 16px;
    height: 16px;
    border: 2px solid rgba(255, 255, 255, .5);
    border-top-color: #fff;
    border-radius: 50%;
    animation: import-spin .6s linear infinite;
}

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

/* Accesibilidad: sin movimiento para quien lo pide — corta toda transición/animación del sistema */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
    .btn-flat:active, .btn-purple:active, .btn-purple:hover,
    .btn-minimal:active, .btn-minimal.btn-primary:hover { transform: none !important; }
}

@media (prefers-reduced-motion: reduce) {
    .modal-woker .btn-minimal:hover,
    .import-step-action:active,
    .import-file-btn:active,
    .modal-woker .btn-minimal:active {
        transform: none !important;
    }
    .btn-minimal-import.is-loading::after {
        animation: none;
    }
}

/* Form card — grupo de formulario en card propia (genérico, reutilizable) */

.form-card {
    background: var(--woker-surface);
    border: 1px solid var(--woker-border);
    border-radius: var(--woker-radius);
    box-shadow: var(--woker-card-shadow);
    margin-bottom: 1.5rem;
}

/* La última card no suma su margen: el contenedor ya trae padding abajo, y sumados dejaban
   el doble de aire al final de la pantalla que entre card y card. Vale también cuando las cards
   cuelgan de un <form> o de un panel de tabs en vez de colgar directo de .main-content.
   Quedan afuera las que cierran una COLUMNA de la grilla: ahí abajo sigue habiendo pantalla
   (otra fila, la barra de acciones) y el margen es la separación con eso. */
.main-content .form-card:last-child:not([class*="col-"] *) { margin-bottom: 0; }

/* Grilla de form-cards: secciones cuadradas lado a lado en vez de apiladas (ej. crear/editar
   cliente). data-cols fija columnas en desktop; colapsa a 2 (<xl) y 1 (<md). */
.form-card-grid {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
    margin-bottom: 1.5rem;
}
.form-card-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.form-card-grid[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Dentro de la grilla el aire entre cards lo da el gap, no el margin de cada una. */
.form-card-grid > .form-card { margin-bottom: 0; }
.main-content > .form-card-grid:last-child { margin-bottom: 0; }

/* Header contenido dentro de la grilla (ícono/título chicos, sin subtítulo); apiladas quedan igual. */
.form-card-grid .form-card-head { padding: 0.7rem 0.85rem; }
.form-card-grid .form-card-icon { width: 32px; height: 32px; border-radius: 9px; }
.form-card-grid .form-card-icon .ico { width: 16px; height: 16px; }
.form-card-grid .form-card-title { font-size: 0.9rem; font-weight: 600; }
.form-card-grid .form-card-sub { display: none; }

@media (max-width: 1199.98px) {
    .form-card-grid[data-cols] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767.98px) {
    .form-card-grid[data-cols] { grid-template-columns: 1fr; }
}

.form-card-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    /* padding uniforme: el ícono queda equidistante del ángulo (esquinas concéntricas con la card) */
    padding: 1rem;
    border-bottom: 1px solid var(--woker-border);
}

.form-card-head-left {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.form-card-icon {
    width: 42px;
    height: 42px;
    flex-shrink: 0;
    border-radius: 12px;
    background: var(--woker-violet-tint);
    color: var(--woker-violet);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.form-card-icon .ico {
    width: 20px;
    height: 20px;
}

.form-card-title {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--woker-ink);
    margin: 0;
    line-height: 1.3;
}

/* Orden de una card dentro de un flujo secuencial (ej. crear endoso: 1 Póliza → 2 Cliente → …).
   Va dentro del título porque es parte del nombre de la sección, no una acción; y en neutro
   para no competir con el ícono violeta de la card. */

/* El título pasa a flex solo cuando lleva número: alineado por baseline, la pastilla (inline-flex)
   apoya su borde inferior en la línea de base y queda montada abajo respecto del texto. */
.form-card-title:has(.form-card-paso) {
    display: flex;
    align-items: center;
}

.form-card-paso {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.35rem;
    height: 1.35rem;
    flex-shrink: 0;
    margin-right: 0.5rem;
    border-radius: 50%;
    background: var(--woker-surface-2);
    border: 1px solid var(--woker-border);
    color: var(--woker-subtle);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
}

/* Header apilado: título sobre subtítulo, al lado del ícono (reutilizable). */
.form-card-heading {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.form-card-sub {
    font-size: 0.8rem;
    color: var(--woker-subtle-texto);
    line-height: 1.35;
}

.form-card-body {
    padding: 1rem;
}

/* El aire de arriba lo pone el padding de la superficie: un margen propio del primer bloque
   (Bootstrap le da margin-top a .form-text, por ejemplo) se le suma y deja el borde superior
   más separado que los otros tres. */
.form-card-body > :first-child { margin-top: 0; }

/* Bootstrap le da margin-bottom:1rem a cada .form-group. El de la última línea de
   campos se suma al padding-bottom de la card y rompe la simetría arriba/abajo.
   Se absorbe con un margen negativo en el último bloque de campos: cancela sólo esa
   última línea, así que una fila que envuelve conserva la separación entre líneas.
   El :has() deja afuera los bloques finales que no son campos (resúmenes, tablas,
   dropzones), que no arrastran ese margen.
   La compensación vale para toda superficie con padding propio (.form-card-body, .riesgo-panel)
   y para los grupos que sólo juntan campos y se muestran/ocultan (.grupo-campos): esos no aportan
   espacio, así que su último bloque también tiene que soltar el margen; si no, la superficie que
   los contiene termina con el doble de aire abajo que arriba según qué grupo esté visible.
   El :has(+ oculto) cubre al hermano que el JS dejó en display:none y que si no se quedaría con
   el rol de "último" sin ocupar lugar.
   El :not(:has(~ :not(script))) cubre lo mismo para los <script> que varios partials dejan
   pegados al campo (el del editor Summernote, por ejemplo): no ocupan lugar pero se llevan el
   rol de :last-child y el campo anterior se queda con su margen. */
:is(.form-card-body, .riesgo-panel, .grupo-campos) > :is(.form-row, .row):has(.form-group):is(
    :last-child,
    :not(:has(~ :not(script))),
    :has(+ [style*="display: none"]:last-child),
    :has(+ [style*="display:none"]:last-child)
) {
    margin-bottom: -1rem;
}

:is(.form-card-body, .riesgo-panel, .grupo-campos) > .form-group:is(
    :last-child,
    :not(:has(~ :not(script))),
    :has(+ [style*="display: none"]:last-child),
    :has(+ [style*="display:none"]:last-child)
) {
    margin-bottom: 0;
}

/* Selector de modo: opciones excluyentes que definen QUÉ se va a cargar y se eligen antes de
   empezar (ej. endoso sobre póliza existente / póliza nueva / renovación). Son radios de verdad
   —el estado lo lleva el input— con la caja como superficie clickeable. */
.opciones-modo {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

/* El margen sólo separa de lo que viene abajo. Si el selector es lo último de la superficie, se
   suma al padding del contenedor y deja el doble de aire abajo que arriba (misma compensación
   que la de los .form-row de campos). */
.opciones-modo:last-child { margin-bottom: 0; }

.opcion-modo { margin: 0; cursor: pointer; }

/* El radio no se ve pero sigue en el DOM: es lo que da foco, teclado y a11y. */
.opcion-modo input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.opcion-modo-caja {
    display: flex;
    flex-direction: column;
    gap: 2px;
    height: 100%;
    padding: 0.7rem 0.85rem;
    border: 1px solid var(--woker-border-control);
    border-radius: var(--woker-radius-control);
    background: var(--woker-surface);
    transition: border-color .15s ease, background-color .15s ease;
}

.opcion-modo:hover .opcion-modo-caja { border-color: var(--woker-border-fuerte); }

.opcion-modo input:checked ~ .opcion-modo-caja {
    border-color: var(--woker-violet);
    background: var(--woker-violet-tint);
}

.opcion-modo input:focus-visible ~ .opcion-modo-caja {
    box-shadow: 0 0 0 .2rem rgba(var(--woker-violet-rgb), .15);
}

.opcion-modo-titulo {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--woker-ink);
}

.opcion-modo input:checked ~ .opcion-modo-caja .opcion-modo-titulo { color: var(--woker-violet); }

.opcion-modo-sub {
    font-size: 0.775rem;
    color: var(--woker-subtle);
    line-height: 1.3;
}

/* Card bloqueada: la sección depende de un paso anterior que todavía no se resolvió (ej. sin
   póliza no hay rama para los riesgos ni tomador para las formas de pago). Se apaga el contenido
   y las acciones, nunca el encabezado: hay que poder leer qué sección es y por qué no se puede
   usar. Acá va lo visual y el mouse; el foco y el teclado los saca el JS con `inert` (los campos
   NO se marcan disabled: un input deshabilitado no viaja en el POST). */
.form-card-bloqueada .form-card-head > :not(.form-card-head-left),
.form-card-bloqueada .form-card-body > :not(.form-card-bloqueo) {
    opacity: 0.4;
    pointer-events: none;
}

/* El aviso solo existe mientras la card está bloqueada. */
.form-card-bloqueo { display: none; }

.form-card-bloqueada .form-card-bloqueo {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 1rem;
    font-size: 0.85rem;
    color: var(--woker-subtle);
}

.form-card-bloqueo .ico {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Pie de acciones de la card: divisor + botones a la derecha (--bleed = divisor full-width) */
.form-card-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--woker-border);
}

.form-card-actions--bleed {
    margin-top: 0;
    padding: 1.1rem 1.5rem;
}

/* Labels: mismo gris que los labels de los filtros (ambos leen --woker-muted) */
.form-card .form-group .info-label {
    font-weight: 600;
    color: var(--woker-muted);
    /* Distancia label→campo (8px). Se reafirma acá porque gestor.css redefine
       `.info-label { margin-bottom:0 }` y pisaba los labels de form/modal del gestor. */
    margin-bottom: 0.5rem;
}

/* Misma distancia label→campo dentro de los modales (form-group > .info-label): los modales del
   asegurado viven en pantallas que cargan gestor.css y sin esto quedaban con el label pegado. */
.modal .form-group .info-label { margin-bottom: 0.5rem; }

/* Tap target mínimo de los controles dentro de la card */
.form-card .form-control {
    min-height: 40px;
}

/* Badge circular del dropzone (ícono cloud-upload) */
.form-card-dropzone-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--woker-violet-tint);
    color: var(--woker-violet);
    margin-bottom: 0.85rem;
}

.form-card-dropzone-icon .ico {
    width: 26px;
    height: 26px;
}

@media (max-width: 767.98px) {
    /* Apilado: lo que en desktop va a la derecha (switch, badge, link) cae debajo del
       encabezado, así que necesita más aire que el 0.35rem que separa título y subtítulo. */
    .form-card-head {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.75rem;
        padding: 1rem;
    }
    /* Excepción: el chevron de colapso es icon-only (30px) y entra a la derecha del
       encabezado a cualquier ancho — apilarlo debajo sólo agrega alto y lo despega
       de la esquina. */
    .form-card-head:has(> .form-card-collapse-toggle) {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
    }
    .form-card-body {
        padding: 1rem;
    }
}

/* Botón chevron para colapsar/expandir una form-card (icon-only, vive en el form-card-head).
   Genérico y reutilizable: cualquier pantalla de detalle con secciones colapsables. */
.form-card-collapse-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 8px;
    color: var(--woker-subtle);
    cursor: pointer;
    transition: var(--woker-transicion);
}
.form-card-collapse-toggle:hover { background: var(--woker-surface-2); color: var(--woker-ink); }
.form-card-collapse-toggle .ico { width: 18px; height: 18px; transition: transform .18s ease; }
.form-card-collapse-toggle[aria-expanded="false"] .ico { transform: rotate(-90deg); }

/* Layout de DETALLE: contenido principal + sidebar sticky (Información/Acciones).
   Genérico y reutilizable para cualquier pantalla de detalle (ver-ticket, ver-cotizacion, ...). */
.detalle-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 1.25rem;
    align-items: start;
}
.detalle-main { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.detalle-aside { display: flex; flex-direction: column; gap: 1.25rem; position: sticky; top: 1rem; }
.detalle-main > .form-card,
.detalle-aside > .form-card { margin-bottom: 0; }

@media (max-width: 991.98px) {
    .detalle-layout { display: flex; flex-direction: column; align-items: stretch; gap: 1.25rem; }
    .detalle-main, .detalle-aside { display: contents; }
}

/* Sidebar de detalle: título de card + filas de acción (icono + texto). Genérico,
   usado por cualquier pantalla de detalle con sidebar (ver-ticket usa su propia copia
   .vt-aside-title/.vt-accion en ver-ticket.css; esta es la versión de sistema para el resto). */
.detalle-aside-title { font-size: 1rem; font-weight: 700; color: var(--woker-ink); margin: 0 0 1.1rem; }

.detalle-acciones { display: flex; flex-direction: column; gap: .15rem; }
.detalle-accion {
    display: flex;
    align-items: center;
    gap: .65rem;
    width: 100%;
    padding: .6rem .7rem;
    background: transparent;
    border: none;
    border-radius: 9px;
    font-size: .88rem;
    font-weight: 500;
    color: var(--woker-muted);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}
.detalle-accion .ico { width: 17px; height: 17px; flex-shrink: 0; color: var(--woker-subtle); }
.detalle-accion:hover { background: var(--woker-surface-2); color: var(--woker-ink); text-decoration: none; }
.detalle-accion:hover .ico { color: var(--woker-muted); }
/* Variantes con texto/icono de color fijo, sin relleno; el fondo tenue aparece recién en hover */
.detalle-accion-danger,
.detalle-accion-danger .ico { color: var(--woker-danger); }
.detalle-accion-danger:hover { background: var(--woker-danger-bg); color: var(--woker-danger); }
.detalle-accion-danger:hover .ico { color: var(--woker-danger); }
.detalle-accion-success,
.detalle-accion-success .ico { color: var(--woker-ok); }
.detalle-accion-success:hover { background: var(--woker-ok-bg); color: var(--woker-ok); }
.detalle-accion-success:hover .ico { color: var(--woker-ok); }
.detalle-accion-warning,
.detalle-accion-warning .ico { color: var(--woker-warn); }
.detalle-accion-warning:hover { background: var(--woker-warn-bg); color: var(--woker-warn); }
.detalle-accion-warning:hover .ico { color: var(--woker-warn); }

/* Sidebar de detalle: pares label/valor apilados para la card "Información". Genérico
   (grupos.css tiene su propia copia .grupo-info-* pre-existente; esta es la versión de
   sistema para el resto de las pantallas de detalle). */
.detalle-info-item { display: flex; flex-direction: column; gap: .3rem; }
.detalle-info-item + .detalle-info-item { margin-top: 1rem; }
.detalle-info-label { text-transform: uppercase; letter-spacing: .05em; font-size: .7rem; font-weight: 600; color: var(--woker-subtle); }
.detalle-info-value { font-size: .9rem; font-weight: 500; color: var(--woker-ink); word-break: break-word; }
.detalle-info-value.is-empty { color: var(--woker-subtle); font-weight: 400; }
/* Valor que linkea a otra pantalla (el usuario → su perfil). El color lo trae el propio link
   (`usuarios/tagUsuario.html` lo fija inline en `inherit`), así que la afordancia va por el
   subrayado en hover: una declaración de color acá no le ganaría al style inline. */
.detalle-info-value a:hover { text-decoration: underline; }

/* Hilo de conversación / historial — riel de timeline que une los avatares.
   Componente de sistema reutilizable (verTicket, panel de seguimiento de cotizaciones). */
.ver-conversacion { position: relative; display: flex; flex-direction: column; gap: 1.4rem; }
.ver-conversacion::before {
  content: '';
  position: absolute;
  left: 13px;
  top: 14px;
  bottom: 14px;
  width: 2px;
  background: #eef0f4;
}
.ce-item { display: flex; gap: .55rem; }
/* Aire entre mensajes consecutivos del mismo tipo */
.ce-author + .ce-author,
.ce-team + .ce-team,
.ce-system + .ce-system { margin-top: .35rem; }
.ce-avatar {
  position: relative;   /* por encima del riel */
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .66rem;
  font-weight: 600;
  text-transform: uppercase;
}
/* Mensajes: avatar con iniciales sobre tinte suave (violeta autor / gris equipo) */
.ce-author .ce-avatar { background: var(--woker-violet-soft); color: var(--woker-violet); }
.ce-team   .ce-avatar { background: #eef0f4; color: #64748b; }
/* Eventos de sistema: avatar gris con ícono */
.ce-system .ce-avatar { background: #eef0f4; color: #98a2b3; }
.ce-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* Hilo de un solo lado: todo a la izquierda; el rol se distingue por el color de la burbuja */
.ce-author .ce-content,
.ce-team   .ce-content,
.ce-system .ce-content { align-items: flex-start; }
/* min-height = alto del avatar: el nombre queda centrado respecto del icono */
.ce-head { display: flex; align-items: center; min-height: 28px; gap: .5rem; flex-wrap: wrap; }
.ce-who { font-size: .82rem; font-weight: 600; color: #27272a; }
.ce-system .ce-who { font-weight: 500; color: #667085; }
.ce-time { font-size: .7rem; color: #a1a1aa; white-space: nowrap; }
.ce-bubble {
  margin-top: .2rem;
  max-width: 80%;
  padding: .4rem .65rem;
  background: #f8f8fc;
  border: 1px solid #eef0f4;
  border-radius: 10px;
  border-top-left-radius: 4px;
  font-size: .86rem;
  line-height: 1.45;
  color: #344054;
  overflow-wrap: anywhere;
  overflow-x: auto;
}
.ce-bubble p:last-child { margin-bottom: 0; }
.ce-bubble table, .ce-bubble img { max-width: 100%; }
/* Color por rol (mismo lado): PAS/autor violeta, organizador/equipo gris neutro */
.ce-author .ce-bubble { background: var(--woker-violet-soft); border-color: transparent; }
.ce-team   .ce-bubble { background: #f3f4f7; border-color: #e5e7ec; }

/* ===== Avisos en banda (.alert) =====
   Los `django.contrib.messages` que las pantallas pintan como `.alert alert-{{ message.tags }}`
   se quedaban con la paleta sólida de Bootstrap (el verde #28a745 a todo lo ancho, con el ×
   negro al 50% de opacidad encima). Como es un componente compartido, la regla va acá y no en
   el CSS de una pantalla: hoy lo usan crearSugerencia, editarCliente y
   solicitar_cotizacion_publica, y lo hereda cualquiera que se migre después.
   Mismo criterio que .estado-tag / .si-aviso: tinte de fondo + texto del rol, sin borde ni
   gradiente. Al salir de tokens, el oscuro no necesita reglas propias salvo el verde
   (--woker-ok es el único rol que dark-mode.css no reasigna).
   `alert-error` existe porque el tag de Django para errores es `error`, no `danger`. */
.alert {
  border: none;
  border-radius: var(--woker-radius);
  padding: .85rem 1.1rem;
  margin-bottom: 1.5rem;
  font-size: .875rem;
  box-shadow: none;
}

.alert-success { background: var(--woker-ok-bg); color: var(--woker-ok-fg); }
.alert-error,
.alert-danger { background: var(--woker-danger-bg); color: var(--woker-danger-fg); }
.alert-warning { background: var(--woker-warn-bg); color: var(--woker-warn); }
.alert-info,
.alert-debug { background: var(--woker-info-bg); color: var(--woker-info); }
.alert-secondary,
.alert-light { background: var(--woker-neutral-bg); color: var(--woker-neutral); }
.alert-primary { background: var(--woker-violet-soft); color: var(--woker-violet); }

/* El × de Bootstrap va en negro con opacidad; acá hereda el color del rol. */
.alert .close {
  color: inherit;
  opacity: .55;
  text-shadow: none;
  padding: .85rem 1.1rem;
}
.alert .close:hover { color: inherit; opacity: 1; }

/* ===== SweetAlert2 =====
   No hay reglas acá a propósito: el popup lo crea el JS en runtime, así que no lo alcanza el
   CSS de ninguna pantalla, y esta hoja sólo la linkean las pantallas migradas. Como el mismo
   diálogo aparece en las 20 que cargan el theme —migradas o no—, el tratamiento completo
   (geometría, botones, ícono, campos) vive en `avisos.css`, que `base.html` carga siempre y
   después del `{% block stylesheets %}` donde entra el theme. */

/* Tabs de sección (el lenguaje visual de ver-poliza y ver-asegurado, promovido a la capa
   sistema): pill chato sin caja contenedora, activo con tinte de marca al 10%.
   Markup: <ul class="nav tabs-modernas"><li class="nav-item">
             <a class="nav-link tab-moderna active" href="#id" data-toggle="tab"> */
.tabs-modernas { display: flex; flex-wrap: wrap; gap: .25rem; list-style: none; margin: 0 0 1.25rem; padding: 0; }
.tab-moderna {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem .9rem;
  border-radius: 8px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--woker-muted);
  text-decoration: none;
  white-space: nowrap;
}
.tab-moderna .ico { width: 16px; height: 16px; }
.tab-moderna:hover { background: var(--woker-surface-2); color: var(--woker-ink); text-decoration: none; }
.tab-moderna.active { background: rgba(var(--woker-violet-rgb), .1); color: var(--woker-violet); }

/* Sub-tabs (un segundo nivel dentro de un tab-pane): más chicas y sin ícono. */
.subtabs-modernas { margin-bottom: 1.1rem; }
.subtabs-modernas .tab-moderna { padding: .4rem .8rem; font-size: .8rem; }

/* En mobile las tabs wrapean en varias filas: centradas quedan equilibradas en vez de
   dejar la última fila colgando a la izquierda. */
@media (max-width: 767.98px) {
  .tabs-modernas { justify-content: center; }
}

/* Nav pills (tabs tipo pill): promovido desde modern-ui.css (legacy azul) a la capa sistema,
   tokenizado a marca. Lo usan varias pantallas (perfil, verSiniestro, _endosoForm). */
.nav-pills-custom {
  background: var(--woker-surface);
  border-radius: var(--woker-radius);
  padding: .375rem;
  margin-bottom: 2rem;
  box-shadow: var(--woker-card-shadow);
  border: 1px solid var(--woker-border);
}
.nav-pills-custom .nav-link {
  border-radius: 6px;
  color: var(--woker-muted);
  font-weight: 500;
  padding: .5rem 1rem;
  margin: 0 .125rem;
  transition: var(--woker-transicion);
  font-size: .875rem;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  cursor: pointer;
}
.nav-pills-custom .nav-link.active { background-color: var(--woker-violet); color: #fff; }
.nav-pills-custom .nav-link:hover:not(.active) { background-color: var(--woker-surface-2); color: var(--woker-ink); }

@media (max-width: 575.98px) {
  .nav-pills-custom { text-align: center; }
  .nav-pills-custom .nav { justify-content: center; flex-wrap: wrap; }
  .nav-pills-custom .nav-link { padding: .375rem .75rem; font-size: .8rem; margin: .125rem; }
}

/* El popover de ayuda lo inserta el JS en el body: no cuelga del modal. */
.help-icon {
  padding: 0 0 0 6px;
  border: none;
  color: var(--woker-subtle);
  background: none;
  font-size: 15px;
  line-height: 1;
  vertical-align: middle;
  cursor: pointer;
}

.help-icon:hover,
.help-icon:focus {
  outline: none;
  color: var(--woker-violet);
}

.help-popover {
  position: absolute;
  z-index: 10000;
  max-width: 320px;
  padding: 12px 14px;
  border: 1px solid var(--woker-border);
  border-radius: 10px;
  color: var(--woker-ink);
  background: var(--woker-surface);
  box-shadow: var(--woker-card-shadow-hover, 0 8px 24px rgba(0, 0, 0, .18));
  font-size: 13px;
  line-height: 1.5;
}

.help-popover::before {
  content: '';
  position: absolute;
  top: 14px;
  left: -7px;
  width: 12px;
  height: 12px;
  border-left: 1px solid var(--woker-border);
  border-bottom: 1px solid var(--woker-border);
  background: var(--woker-surface);
  transform: rotate(45deg);
}
