/* ════════════════════════════════════════════════════════════════════════════════════════════
   LA ESCALA DE CAPAS — EL ÚNICO LUGAR DONDE SE ESCRIBE UN z-index (Orden 149)

   POR QUÉ EXISTE, con la medición que la pidió: el censo de la Orden 148 encontró el mismo bug
   en cuatro pantallas y dos formas distintas de romperse.
     · ROTAS POR NÚMERO: /compras (toasts en 50, velos en 60 y 70), /configuracion (50 vs 70) y
       /tienda-web (50 vs 200) pintaban TODOS sus mensajes DEBAJO del velo del modal abierto.
     · ROTAS POR EMPATE: /index, /automotriz y /pos tenían sus toasts en 200 y varios overlays
       TAMBIÉN en 200 (aviso de WhatsApp, logs de una orden, pedir reseña, historial de cierres).
       A igual z-index gana el ÚLTIMO del DOM, y esos overlays se agregan con appendChild mucho
       después que el contenedor de toasts, que vive en el HTML. `200 = 200` se lee como correcto
       en un diff y está roto: nadie lo ve revisando. Dos cosas en la misma CAPA NOMBRADA, en
       cambio, es obviamente un error.

   POR QUÉ EN CSS Y NO EN UNA CONSTANTE DE JS: los overlays se arman en JS con strings de clases
   y los contenedores viven en el HTML. Una constante de JS no cubre el HTML. Las clases sí cubren
   los dos, y las variables cubren además a las otras hojas de estilo (`z-index: var(--capa-…)`),
   que es como sidebar.css y vitrina.css entran a la escala sin partirse en dos archivos.

   TRES CAPAS. Los NIVELES de adentro de la primera no son gusto: cada uno salió del censo.

   ── CAPA 1 · PÁGINA ───────────────────────────────────────────────────────────────────────
   Todo lo que vive DENTRO de la página y se puede tapar. De abajo hacia arriba:
     chrome    la barra lateral y las barras fijas de la página.
     flotante  tooltips y menús flotantes: sobre el contenido, BAJO cualquier modal.
     modal     el velo `fixed inset-0` de un modal abierto desde la página.
     modal-2   la confirmación abierta DESDE un modal: tiene que tapar al que la abrió.
               (Sin este nivel, «¿seguro que quieres borrar?» aparece detrás del modal que
               preguntó — el bicho que la #349 arregló a mano en el gate de repuestos.)

   ╔══════════════════════════════════════════════════════════════════════════════════════════╗
   ║  LA REGLA QUE SOSTIENE A TODAS LAS DEMÁS:                                                ║
   ║  UN OVERLAY QUE SE ABRE **DESDE OTRO OVERLAY** VA SIEMPRE A LA CAPA DE ARRIBA.            ║
   ║  Si el que lo abre es `capa-modal`, el nuevo es `capa-modal-2`. Nunca los dos en la misma.║
   ╚══════════════════════════════════════════════════════════════════════════════════════════╝
   POR QUÉ ES LA VIGA, y no una preferencia de estilo: pasar de N números a 3 capas es LOSSY por
   construcción — adentro de una capa el orden relativo lo decide el orden del DOM. El censo de
   inversiones de la Orden 149 midió 30 pares que cambiaron de ganador al convertir, y 29 son
   inofensivos por UNA sola razón: no pueden estar abiertos a la vez. Con un velo `fixed inset-0`
   opaco puesto no se puede clickear la página de atrás, así que dos overlays solo conviven por
   un atajo global de teclado (hay exactamente uno: F12), por una apertura programática, o
   PORQUE UNO ABRIÓ AL OTRO. Esta regla es lo que mantiene ese tercer caso fuera de la misma capa
   — y por lo tanto lo que mantiene verdadero el argumento de las 29.
   EL LÍMITE, DICHO: hoy esto NO está enforced por ningún test (el guard verifica que los números
   salgan de acá, no quién abre a quién). Es convención escrita, y por eso está escrita ACÁ y en
   la receta, en vez de vivir en el cuerpo de una PR que nadie va a releer. Si algún día alguien
   abre un modal desde adentro de otro y le pone `capa-modal` «porque es un modal», el argumento
   se vuelve falso EN SILENCIO: el nuevo queda tapado por el que lo abrió cuando el opener está
   antes en el DOM. Un guard que lo verifique es trabajo propio, no un remate.

   ── CAPA 2 · AVISOS ───────────────────────────────────────────────────────────────────────
     aviso     toasts y banners. POR ENCIMA DE TODO MODAL DE PÁGINA, sin excepción: un mensaje
               que el usuario no puede leer es lo mismo que no haberlo escrito.

   ── CAPA 3 · BLOQUEO DEL SISTEMA ──────────────────────────────────────────────────────────
     bloqueo   licencia vencida, actualización obligatoria, mantenimiento. Por encima de TODO,
               los avisos incluidos — y esa excepción es a propósito: un «tienes que actualizar»
               tiene que tapar hasta un toast. Esta capa es la razón por la que los toasts NO
               pueden vivir en el top layer del navegador: «el aviso siempre arriba de todo» es
               falso para esta app, y el top layer haría este caso más difícil, no más fácil.

   LOS NÚMEROS NO SON EL CONTRATO — EL ORDEN SÍ. Están espaciados para que quepa un nivel nuevo
   sin renumerar nada, y son los que ya usaban las pantallas sanas (100/120 los modales del
   Taller, 200 los toasts): adoptar la escala que ya existía costó menos que inventar una.

   ── EL AVISO **PERMANENTE** CEDE MIENTRAS HAY UN MODAL ABIERTO (Orden 179 · 20-ago-2026) ──
   NO deroga «el aviso por encima de todo modal»: la afina, y la afina con el argumento que esta
   misma hoja ya usa doce líneas más abajo para que el toast le gane al banner — UNA PÉRDIDA SE
   RECUPERA SOLA Y LA OTRA NO.

   QUÉ SE MIDIÓ (Abel, en su propia ventana de 686x442): con el modal «Servicio / Producto Libre»
   abierto, `#banner-respaldo` —opaco, `position:fixed` abajo a la derecha, permanente hasta que
   alguien lo cierre y sin `pointer-events:none`— se comía el clic del botón «Agregar a la venta».
   El barrido con `elementFromPoint` sobre nueve puntos del botón, ANTES del arreglo:
       alto 800, ancho 1440→640 ......... 9/9 puntos del botón libres (el banner ni lo roza)
       alto 442, ancho >= 1060 .......... 9/9 libres
       alto 442, ancho 1040..740 ........ 6/9 — muere el tercio derecho, el centro todavía cobra
       alto 442, ancho <= 720 ........... 3/9 — MUERE EL CENTRO (el caso de Abel)
   O SEA: NO ES UN UMBRAL DE ANCHO. Es una colisión de dos dimensiones y el ALTO es la condición
   necesaria — una ventana angosta y ALTA (un teléfono vertical) no tiene solape ninguno. Un
   arreglo pensado «para pantallas angostas» habría arreglado lo que no fallaba y dejado roto el
   caso real. Queda escrito porque la hipótesis equivocada es barata de repetir.

   LO QUE **NO** SE HIZO, y por qué: mover los números. Subir el modal sobre 200 o bajar el aviso
   contradice el contrato de arriba, enrojece los dos guards que lo asertan y reabre la 148 (un
   toast enterrado desaparece para siempre). El bicho nunca fue el ORDEN: fue la GEOMETRÍA.

   LA REGLA, y por qué respeta la doctrina en vez de esquivarla: mientras un modal de página tiene
   la palabra, los avisos PERMANENTES (`.capa-aviso`: respaldo, fin de prueba, error de conexión)
   se apartan y vuelven solos al cerrarse el modal — no se pierde ningún mensaje, se posterga.
   Los FUGACES (`.capa-aviso-fugaz`) NO se apartan nunca: duran cuatro segundos y apartarlos es
   perderlos para siempre, que es exactamente lo que la 159 decidió evitar. La escala ya separaba
   los dos niveles para desempatar el z; acá esa misma separación decide QUIÉN CEDE EL PASO.

   LO QUE ESTA ESCALA **NO** GOBIERNA, y es una frontera derivada, no una lista a mano:
   el apilamiento LOCAL adentro de un componente —un badge sobre un ícono, un dropdown adentro de
   una tarjeta, una capa decorativa sobre un degradado— no compite con nada global y se queda como
   está. La regla es: lo que flota sobre la PÁGINA ENTERA (`position: fixed`) saca su z de acá.
   El guard de test/capas-z-index.test.js hace cumplir exactamente esa frontera.
   POR ESO ACÁ NO HAY UN NIVEL «sticky» NI UNO «local»: los encabezados de tabla pegajosos y los
   desplegables de una tarjeta siguen usando las utilidades `z-*` de Tailwind, y darles un nivel
   sería declarar un número para lo que esta escala dice explícitamente que no gobierna. Un nivel
   sin consumidores es una invitación a usarlo mal.
   ════════════════════════════════════════════════════════════════════════════════════════════ */
:root {
    --capa-chrome: 40;
    --capa-flotante: 90;
    --capa-modal: 100;
    --capa-modal-2: 120;
    --capa-aviso: 200;
    /* EL TOAST GANA AL BANNER (159, decisión de Abel del 14-ago). Los dos vivían en
       `--capa-aviso: 200` y el empate lo desempataba el ORDEN DEL DOM — que es exactamente el
       caso que esta escala nombra como el que obliga a un guard: se lee correcto en un diff.
       POR QUÉ GANA EL FUGAZ AL PERMANENTE, que parece al revés: el banner sigue ahí después de
       que el toast se va, así que taparlo cuesta cuatro segundos. Si el banner tapa un toast,
       el toast desaparece PARA SIEMPRE y el operador nunca se entera de si lo que hizo funcionó.
       Una pérdida se recupera sola y la otra no.
       Y ya nos pasó: la 148 es literalmente esto — el error de Compras existía, estaba bien
       escrito, y nadie lo vio nunca porque un velo lo tapaba. */
    --capa-aviso-fugaz: 210;
    --capa-bloqueo: 9000;
    /* (253) EL AVISO QUE TIENE QUE GANARLE AL BLOQUEO. Uno solo: la eliminación programada. La
       pantalla de bloqueo dice «tus datos están a salvo», y con una eliminación en curso eso es
       falso — el dueño necesita ver la fecha y saber que puede cancelar JUSTO ahí, que es donde
       cae si dejó vencer la suscripción en esos siete días. Empatar en 9000 no alcanzaba: el
       desempate por orden del DOM lo pintaba debajo (el bloqueo se agrega después). */
    --capa-bloqueo-aviso: 9100;
}

/* Las clases, para el HTML y para los strings de clases que arma el JS. Reemplazan a las
   utilidades `z-*` de Tailwind en todo lo que es `fixed`: misma especificidad (una clase), y
   esta hoja se linkea DESPUÉS de tailwind.css en cada página, así que si alguna vez conviven
   las dos, gana la capa nombrada. */
.capa-chrome   { z-index: var(--capa-chrome); }
.capa-flotante { z-index: var(--capa-flotante); }
.capa-modal    { z-index: var(--capa-modal); }
.capa-modal-2  { z-index: var(--capa-modal-2); }
.capa-aviso    { z-index: var(--capa-aviso); }
.capa-aviso-fugaz { z-index: var(--capa-aviso-fugaz); }
.capa-bloqueo  { z-index: var(--capa-bloqueo); }
.capa-bloqueo-aviso { z-index: var(--capa-bloqueo-aviso); }

/* ── EL AVISO PERMANENTE CEDE (Orden 179; el porqué está arriba, con la medición) ─────────────
   `:has()` y no JS: los modales se abren de 54 lugares (21 en HTML, 33 armados con strings de
   clases en JS) y engancharse a cada uno es la clase de arreglo que se olvida en el sitio 55.
   La convención que hace esto declarativo está medida y es uniforme: los modales estáticos se
   togglean con `.hidden` y los dinámicos se `.remove()` del DOM — cero `style.display` en todo
   `public/`. `:has()` ya está en producción en index.css y automotriz.css con este mismo idioma.
   ESPECIFICIDAD, dicho porque acá ya nos mordió (la 176: un `.hidden` que no escondía): esta
   regla es (0,3,1) y le gana a la utilidad `.flex` (0,1,0) que traen los dos banners del core,
   así que NO depende del orden de carga de las hojas. */
body:has(.capa-modal:not(.hidden):not([hidden]), .capa-modal-2:not(.hidden):not([hidden])) .capa-aviso,
/* (253) Y LA BARRA DE ELIMINACIÓN, que es un aviso permanente igual que los otros aunque viva en
   otra capa: sin esta línea, sus 9100 se comían el borde superior de TODO modal —la barra la ven
   los siete días, en toda pantalla y por todo el equipo— y los clics aterrizaban en ella. Es
   exactamente el defecto que cerró la 179; su guard seguía verde porque apuntaba sólo a
   `.capa-aviso`. La capa alta sigue haciendo su trabajo (ganarle a la pantalla de bloqueo, que no
   es un modal), y acá cede el paso como corresponde. */
body:has(.capa-modal:not(.hidden):not([hidden]), .capa-modal-2:not(.hidden):not([hidden])) .capa-bloqueo-aviso {
    display: none;
}
