/* ============================================================
   LuxSOP · Tema de Bootstrap 5.3
   Reapunta las variables de Bootstrap al azul marino y los neutros de LuxSop.

   CONTRATO: este archivo SOLO declara custom properties (--…).
   Una declaración normal necesita un comentario justificándola arriba.
   Lo cuida tests/test_bootstrap_andamio.py.

   Tematizar   →  .btn-primary { --bs-btn-bg: #162566; }
   Reconstruir →  .btn-primary { padding: 8px 18px; }   ← prohibido

   Guardrail: ~80 líneas. Es señal, no dogma: si 82 son lo correcto, van 82;
   lo que no se vale es hacer trucos para quedar debajo del número.
   ============================================================ */

/* ── LA FUENTE ── Inter, auto-hospedada (2026-09-15).

   Venía de Google Fonts, y la enlazaba SOLO `base.html`. Eso dejaba a las **11 pantallas
   sueltas** —login, los dos visores, seleccionar_planta, todo el recorrido de la operaria y
   los dos editores del día— cayendo en `system-ui`, porque no extienden `base.html` y nadie
   les cargaba la fuente. Lo vio el usuario: «¿por qué no usas el mismo tipo de letra que las
   otras pantallas?». Llevaban así desde siempre.

   Se resuelve aquí, en `tema.css`, y no en `luxsop.css`, porque `tema.css` lo cargan LAS
   DOCE: `plan_trabajo/cotizacion` no carga `luxsop.css` a propósito.

   Y de paso sale del CDN, como las otras cinco librerías (spec §3): sin internet, la planta
   se quedaba sin Inter incluso en las pantallas que sí extienden `base.html`.

   Son DOS archivos y no ocho: Inter es una fuente VARIABLE, así que los cuatro pesos que
   pedía Google (400/500/600/700) devolvían el mismo `.woff2`. Por eso `font-weight` declara
   el rango `100 900` en vez de cuatro bloques repetidos — 130 KB en lugar de 521.

   `swap` mantiene el texto visible mientras la fuente carga. OJO: eso significa que la
   página se pinta primero con la de reserva y luego cambia, y cualquier JS que MIDA
   píxeles tiene que repetir la medición en `document.fonts.ready` (ya mordió en `kits`). */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../vendor/inter/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* El segundo trozo: el alfabeto latino básico, que es el que se usa el 99 % del tiempo.
   Va SEGUNDO a propósito, igual que lo sirve Google: el navegador solo descarga el que
   necesita según el `unicode-range`, así que una pantalla en español normal se trae
   47 KB y no los 130. (Este comentario, además, es lo que permite que la prueba del
   contrato acepte el bloque: `tema.css` solo admite declaraciones planas justificadas.) */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../vendor/inter/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Marca */
  --bs-primary:     #162566;
  --bs-primary-rgb: 22, 37, 102;

  /* Texto. Los neutros NO son grises puros: llevan un sesgo hacia el navy.
     Un #6b7280 junto a un #162566 se lee como dos paletas pegadas con cinta. */
  --bs-body-color:      #2E3444;
  --bs-body-color-rgb:  46, 52, 68;
  --bs-secondary-color: rgba(100, 108, 128, .85);
  --bs-heading-color:   #162566;

  /* Bootstrap pinta `<code>` de ROSA (#d63384) por omisión, pensando en documentación.

     LA REGLA DE VERDAD ES OTRA, y está antes que esta variable: **el ID de un renglón no
     es `<code>`**. `HE-AT-001` es un dato de la tabla y se escribe como los demás, en la
     misma letra y la misma tinta que la columna de al lado — `<code>` lo sacaba en
     monoespaciada Y en rosa, y las dos cosas lo despegaban del renglón. Decidido con el
     usuario el 2026-09-14 viendo /catalogos/herramientas.

     La variable se queda como RED, no como solución: `elementos.js`, `fracciones.js` y
     `kits.js` todavía envuelven su ID en `<code>` y aún no se convierten. Al convertirlas
     hay que QUITARLES la etiqueta, igual que a herramientas; si alguna se escapa, al menos
     no sale rosa. */
  --bs-code-color: #2E3444;

  /* Superficies */
  --bs-body-bg:     #F5F7FF;
  --bs-tertiary-bg: #F1F3F9;

  /* Líneas */
  --bs-border-color:             #E3E6EF;
  --bs-border-color-translucent: rgba(22, 37, 102, .12);

  /* Tipografía. Inter se auto-hospeda arriba, en este mismo archivo. */
  --bs-body-font-family: "Inter", system-ui, -apple-system, sans-serif;
  --bs-body-font-size:   .92rem;

  /* Enlaces */
  --bs-link-color:           #162566;
  --bs-link-color-rgb:       22, 37, 102;
  --bs-link-hover-color:     #1f3488;
  --bs-link-hover-color-rgb: 31, 52, 136;
}

/* Encabezados en negritas.
   Bootstrap los fija en `font-weight:500` (medio) y NO lo expone como variable
   —no existe `--bs-headings-font-weight`—, así que aquí no alcanza con una
   custom property. Es el caso para el que existe la válvula del contrato.
   LuxSop los quiere en 700, como los tenía el sistema anterior. Al ponerlo aquí
   y no en cada plantilla, lo heredan las 75 pantallas sin repetir `fw-bold`. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 { font-weight: 700; }

/* Forma del botón: compacto y en semibold.
   El default de Bootstrap (1rem, peso 400, radio 6px) se lee como un bloque plano
   al lado de los títulos en negritas y de la tabla-tarjeta. */
.btn {
  --bs-btn-font-size:     .82rem;
  --bs-btn-font-weight:   600;
  --bs-btn-padding-y:     6px;
  --bs-btn-padding-x:     14px;
  --bs-btn-border-radius: 7px;
}

/* Los tamaños van DESPUÉS de `.btn` y NO son opcionales.
   `.btn-sm` y `.btn` tienen la misma especificidad (0,1,0): como esta hoja carga
   después de Bootstrap, la regla `.btn` de arriba le gana a la de `.btn-sm` y un
   botón pequeño saldría del tamaño normal. Redefinirlos aquí lo devuelve. */
.btn-sm {
  --bs-btn-font-size:     .76rem;
  --bs-btn-padding-y:     4px;
  --bs-btn-padding-x:     10px;
  --bs-btn-border-radius: 6px;
}
.btn-lg {
  --bs-btn-font-size:     .95rem;
  --bs-btn-padding-y:     9px;
  --bs-btn-padding-x:     20px;
  --bs-btn-border-radius: 8px;
}

/* Botón primario.
   OJO: en Bootstrap 5.3 sobrescribir --bs-primary NO recolorea .btn-primary.
   Los botones leen sus PROPIAS variables. Tocar este selector para fijarlas
   es tematizar correctamente, no reconstruir Bootstrap. Ver el spec §6. */
.btn-primary {
  --bs-btn-bg:                    #162566;
  --bs-btn-border-color:          #162566;
  --bs-btn-hover-bg:              #1f3488;
  --bs-btn-hover-border-color:    #1f3488;
  --bs-btn-active-bg:             #101c4d;
  --bs-btn-active-border-color:   #101c4d;
  --bs-btn-disabled-bg:           #162566;
  --bs-btn-disabled-border-color: #162566;
}

/* Mismo caso para el botón de contorno. */
.btn-outline-primary {
  --bs-btn-color:               #162566;
  --bs-btn-border-color:        #162566;
  --bs-btn-hover-bg:            #162566;
  --bs-btn-hover-border-color:  #162566;
  --bs-btn-active-bg:           #162566;
  --bs-btn-active-border-color: #162566;
}

/* EL AMARILLO (2026-09-15). El usuario eligió el #ffc107 de Bootstrap, así que el TONO no
   se toca: lo que se arregla aquí es solo la LEGIBILIDAD, que es lo que estaba roto.

   Hizo falta llegar hasta aquí para verlo. El usuario rechazó tres amarillos seguidos en dos
   pantallas distintas, y el problema no era el tono —al final se quedó con el de siempre—
   sino DÓNDE se usaba: Bootstrap emplea el mismo #ffc107 para rellenar y para escribir, y
   como texto sobre el papel blanco da 1.63:1, cuando el mínimo legible son 4.5:1. El texto
   de un `btn-outline-warning` en reposo casi no se leía.

   Por eso aquí NO hay bloque `.btn-warning`: el de Bootstrap ya es lo que se quiere
   (#ffc107 con texto NEGRO, y sus tres estados dan 12.88, 14.04 y 9.77:1). Tocarlo sería
   reescribir lo que ya está bien.

   Solo se oscurece el tono de ESCRITURA, de #997404 a #7f620a:

   | dónde                                   | Bootstrap | aquí |
   | texto del botón de contorno, sobre papel|  1.63:1   | 5.75:1 |
   | texto de píldora, sobre su fondo suave  |  3.90:1   | 5.19:1 |

   Los fondos suaves y los bordes se quedan como vienen: ya eran correctos. */
:root {
  --bs-warning-text-emphasis: #7f620a;
}

/* Mismo caso que `.btn-primary`: el botón lee sus PROPIAS variables, así que la de arriba no
   le llega. En reposo el texto tiene que leerse, y por eso usa el tono de escritura y no el
   color base. Al pasar el ratón sí se rellena con el amarillo entero y el texto pasa a
   negro, que es el estado que el usuario aprobó viéndolo. */
.btn-outline-warning {
  --bs-btn-color:               #7f620a;
  --bs-btn-border-color:        #ffe69c;
  --bs-btn-hover-bg:            #ffc107;
  --bs-btn-hover-border-color:  #ffc107;
  --bs-btn-hover-color:         #000;
  --bs-btn-active-bg:           #ffc107;
  --bs-btn-active-border-color: #ffc107;
  --bs-btn-active-color:        #000;
  --bs-btn-disabled-color:      #7f620a;
}

.form-control, .form-select, .form-check-input {
  --bs-border-color: #CDD2E0;
}

/* Los campos, BLANCOS. Cuarta aparición de la misma trampa (van tabla, tarjeta, modal y
   ahora esto): Bootstrap 5.3 escribe `background-color: var(--bs-body-bg)` en
   `.form-control` y `.form-select`, así que con el fondo azulado de LuxSop el buscador
   se confundía con la página y no se veía dónde empezaba el campo.
   Aquí NO alcanza una custom property —Bootstrap no expone variable para este fondo, lo
   pone como declaración normal— y por eso va como declaración justificada, que es la
   válvula del contrato de este archivo. */
.form-control,
.form-select {
  background-color: #fff;
}

/* El NOMBRE del campo, en negro (2026-09-02). Es la única excepción al gris con tinte navy
   de `--bs-body-color`: la etiqueta tiene que ganarle a lo que se escribe dentro del campo
   y a la ayuda de abajo, y a #2E3444 las tres cosas pesaban casi igual.

   Se toca `.form-label` y NO `--bs-body-color`: esa variable pinta TODO el texto de las
   pantallas convertidas —tablas, tarjetas, párrafos—, y aquí lo que se pidió fue el título
   del campo, no la app entera.

   Va como declaración justificada porque Bootstrap no le pone color a `.form-label` (solo
   `margin-bottom`): hereda del cuerpo, así que no hay variable a la que reapuntar. Las
   ayudas `.form-text` y los placeholders siguen en gris a propósito: son pistas, no
   contenido. */
.form-label {
  color: #000;
}

/* Popover. Es la confirmación de borrado desde el 2026-09-05: una burbuja pegada al botón
   que se picó, en lugar del modal —que el usuario rechazó con «parece un modal, no una
   alerta»—. Se eligió sobre otras tres formas (fila, barra de alerta y aviso al pie) en un
   mockup comparativo que ya se borró; el registro queda en la bitácora de la migración.

   `--bs-popover-bg` es la QUINTA aparición de la misma trampa (van tabla, tarjeta, modal y
   campos de formulario): Bootstrap 5.3 lo apunta a `--bs-body-bg`, que aquí es el azulado
   del papel, así que la burbuja salía del mismo tono que la página y no se despegaba.

   La sombra va como DECLARACIÓN y no como custom property: esta compilación de Bootstrap
   trae `$enable-shadows: false`, así que declara `--bs-popover-box-shadow` pero NUNCA la
   lee. Fijar la variable no pinta nada. Es la válvula documentada de este archivo. */
.popover {
  --bs-popover-bg:            #fff;
  --bs-popover-border-color:  #E3E6EF;
  --bs-popover-border-radius: 12px;
  --bs-popover-max-width:     290px;

  box-shadow: 0 8px 28px rgba(22, 37, 102, .18);
}

/* Modal. El default de Bootstrap parte la ventana en tres bandas con una línea
   bajo el encabezado y otra sobre el pie; se lee como formulario de sistema y no
   como tarjeta. Aquí se quita la de arriba y se conserva la de abajo, que sí hace
   falta para despegar los botones del formulario. */
.modal {
  --bs-modal-border-radius:      14px;
  --bs-modal-border-width:       0;
  --bs-modal-padding:            1.5rem;
  --bs-modal-header-padding:     1.5rem 1.5rem 0;
  --bs-modal-header-border-width: 0;
}

/* EL MODAL SCROLLEABLE CON UN <form> ADENTRO (2026-09-08).
   Reportado en «Editar empleado»: el modal se salía por abajo, no se podía bajar y los
   botones de Guardar/Cancelar quedaban fuera de la pantalla.

   No era de esa pantalla: su marcado es el correcto y ya traía `modal-dialog-scrollable`.
   Es la cadena de flex la que se rompe. Bootstrap resuelve el scroll así:

       .modal-dialog-scrollable .modal-content { max-height:100%; overflow:hidden }
       .modal-dialog-scrollable .modal-body    { overflow-y:auto }

   y eso funciona porque `.modal-content` es `display:flex; flex-direction:column` y el
   `.modal-body` es hijo suyo: como el contenedor está acotado, al body le toca un alto
   acotado y su `overflow-y:auto` tiene contra qué scrollear.

   Cuando el formulario envuelve al cuerpo y al pie —que es lo normal, para que el botón
   Guardar haga submit— el hijo directo pasa a ser el `<form>`, que es un bloque de alto
   automático: crece con su contenido, el body nunca recibe un alto acotado, y lo que
   sobra lo recorta el `overflow:hidden` de `.modal-content`. De ahí el síntoma exacto:
   contenido cortado, sin barra para bajar y sin pie.

   La regla devuelve al form el papel de columna intermedia. `overflow:hidden` no es
   adorno: además de recortar, es lo que le da al form (y al body dentro) tamaño mínimo
   automático 0, que es lo que permite que se encoja en vez de empujar.

   Va SOLO bajo `.modal-dialog-scrollable`: los modales cortos con form —«Editar planta»,
   por ejemplo— no tienen nada que acotar y no hay por qué tocarlos. */
.modal-dialog-scrollable .modal-content > form {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* EL ALTO DEL MODAL SCROLLEABLE (2026-09-08). Bootstrap le da
   `height: calc(100% - márgenes)`, o sea que SIEMPRE ocupa la ventana entera, traiga
   veinte campos o tres. El usuario lo notó en «Editar empleado» —«¿por qué está tan
   grande?»— en cuanto se arregló el scroll y se vio lo que ese alto fijo hacía de verdad.

   Se cambia por un TOPE, que es lo que se quería desde el principio: el modal mide lo que
   necesita y solo scrollea cuando se pasa. Pega en los siete modales scrolleables de la
   app, y en los cortos (Precios, Roles) es donde más se nota.

   85dvh y no 100%: además de quitar el alto fijo, se le deja aire arriba y abajo. Un modal
   que toca los dos bordes de la pantalla no se lee como una ventana sobre la página, se
   lee como otra página.

   Las dos declaraciones de `max-height` son a propósito, no un duplicado: `dvh` descuenta
   la barra del navegador en el móvil y `vh` no, así que la primera es el respaldo para
   quien no entienda `dvh` y la segunda gana donde sí. NO borrar la de arriba.

   El tope va en `.modal-content` y no en `.modal-dialog`: al poner el diálogo en `auto`,
   el `max-height:100%` que Bootstrap le da al contenido se queda sin referencia —un
   porcentaje contra un alto automático no resuelve— y el modal volvería a desbordarse. */
.modal-dialog-scrollable .modal-content {
  max-height: 85vh;
  max-height: 85dvh;
}

/* La otra mitad del cambio de arriba: sin quitar el alto fijo del diálogo, el tope del
   contenido no serviría de nada — el diálogo seguiría midiendo la ventana entera. */
.modal-dialog-scrollable { height: auto; }

/* Tamaño del título del modal.
   Bootstrap solo expone `--bs-modal-title-line-height`, no el tamaño: `.modal-title`
   hereda el de `h5` (1.25rem), que junto al peso 700 queda demasiado gritón para
   una ventana chica. No hay variable, así que va como declaración justificada. */
.modal-title { font-size: 1.05rem; }

/* La ENTRADA del modal (2026-09-02). Bootstrap lo baja 50 px en .3s con una curva que
   arranca rápido; en pantalla eso se lee como aparición seca, no como algo que cae. Aquí
   recorre 90 px y frena al llegar. No hay variable para la transición del modal, así que
   va como declaración justificada.

   SE ANIMA SIEMPRE, incluso con `prefers-reduced-motion: reduce`. Es una decisión tomada
   a sabiendas (2026-09-02), no un olvido: NO reponer aquí el bloque de reduced-motion.
   Bootstrap trae el suyo, pero queda antes que esta hoja y pesa igual (0,3,0), así que la
   regla de abajo lo pisa sola. Si algún día se quiere volver a respetar la preferencia,
   basta con reponer:
       @media (prefers-reduced-motion: reduce) {
         .modal.fade .modal-dialog { transition: none; }
       }
   El costo de no tenerlo: quien apagó las animaciones en su sistema —por mareo o
   sensibilidad al movimiento— recibe esta de todos modos. La campanita, en cambio, SÍ
   sigue respetando la preferencia (ver el final de campanita.css), así que hoy la app está
   dividida en ese criterio. */
.modal.fade .modal-dialog {
  transform: translate(0, -90px);
  transition: transform .38s cubic-bezier(.2, .8, .3, 1);
}

/* El punto de llegada. Bootstrap ya trae esta misma regla, pero la suya queda ANTES que
   esta hoja y las dos pesan igual (0,3,0): sin repetirla aquí, la de arriba ganaría también
   en el estado final, el diálogo se quedaría clavado 90 px arriba y no recorrería nada. Se
   ve idéntico a no tener animación —pasó al probarlo—, así que si alguien borra esta línea
   por parecer redundante, rompe la de arriba. */
.modal.show .modal-dialog { transform: none; }

.table {
  --bs-table-hover-bg: #F8F9FC;
}

/* Superficies BLANCAS sobre el fondo azulado de la página.
   Bootstrap 5.3 apunta el fondo de casi toda superficie elevada a `--bs-body-bg`
   (`--bs-card-bg`, `--bs-modal-bg`, `--bs-dropdown-bg`, y `--bs-table-bg` en
   luxsop.css). Con `--bs-body-bg` en #F5F7FF eso deja la tarjeta del MISMO tono que
   el papel: se confunde con el fondo y no se despega. El contraste es justamente lo
   que se quiere del azulado, así que lo que se cambia es la superficie, no el fondo. */
.card,
.modal,
.dropdown-menu {
  --bs-card-bg:     #fff;
  --bs-modal-bg:    #fff;
  --bs-dropdown-bg: #fff;
}

/* Esquinas de la tarjeta. El default de Bootstrap son 6px, que al lado de la
   tabla-tarjeta —12px, y las dos se ven juntas en la misma pantalla— se leen
   casi rectas. Se iguala a 12 para que las dos superficies sean la misma cosa. */
.card {
  --bs-card-border-radius: 12px;
}

/* El `info` de Bootstrap, reteñido al azul de la marca.
   De fábrica es CIAN (#cff4fc): el único color del sistema que no salía de la paleta de
   LuxSop, y saltaba a la vista en los chips de «Cotizada» y «En tránsito». El sistema
   anterior nunca tuvo ese problema —su `--info` era #1d4ed8, un azul de verdad—; el cian
   entró al traducir las píldoras a Bootstrap.
   Se reteñe la VARIABLE y no cada chip, así que también corrige `alert-info` y todo lo
   demás que use la familia. */
:root {
  --bs-info-bg-subtle:     #DCE4FF;
  --bs-info-text-emphasis: #1B2E7A;
  --bs-info-border-subtle: #B9C7F5;
}

/* Pestañas, los dos niveles. Bootstrap pinta el enlace inactivo del color de los
   enlaces —que aquí ya es navy—, y así la barra entera se ve activa. El sistema
   anterior tenía la inactiva en gris y la activa en navy; esto lo devuelve. */
.nav {
  --bs-nav-link-color:       #646C80;
  --bs-nav-link-hover-color: #162566;
}

/* Pestañas de módulo. El default de Bootstrap subraya la activa en
   --bs-emphasis-color, que es negro; LuxSop la quiere navy, como la `.tab` del
   sistema anterior. */
.nav-underline {
  --bs-nav-underline-link-active-color: #162566;
}

/* Sub-pestañas (el nivel de adentro). El activo de `nav-pills` viene en el azul
   de fábrica de Bootstrap, #0d6efd. */
.nav-pills {
  --bs-nav-pills-link-active-bg: #162566;
}
