/* ===========================================================================
   datahub — CSS propio.

   NORMA DURA: nos adaptamos a Tabler, Tabler no se adapta a nosotros. Este
   fichero NO contiene ni un solo estilo que imite un componente de Tabler.
   Todo lo que hay aquí es una de estas tres cosas, y cada una está justificada
   por escrito porque Tabler no la cubre:

     1. Cromo flotante sobre el mapa (desenfoque translúcido).
     2. Asa y arrastre del cajón inferior en móvil.
     3. Zona segura del iPhone (`env(safe-area-inset-*)`), que ningún tema
        pensado para escritorio resuelve.
     4. `touch-action: none` en el asa de arrastre del inicio (modo «Ordenar»).
     5. Salto de página entre las hojas del informe de glucosa (`@media print`).

   Los tres primeros patrones vienen del design system del proyecto hermano
   aft-platform, donde ya están aprobados como excepción explícita:
   `platform/design-system/patterns/mobile-first-shell.md` y
   `platform/design-system/components/bottom-sheet.md`.

   Prefijo `dh-` en todo. Si algo de aquí empieza a parecerse a un componente
   de Tabler, es que se ha hecho mal: bórralo y usa el primitivo real.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Cromo translúcido sobre el mapa
   ---------------------------------------------------------------------------
   `bg-*-lt` de Tabler es color al 10% de opacidad: pensado para un fondo
   sólido, ilegible flotando sobre un mapa (medido en aft-platform). Aquí se
   usa la superficie real del tema más desenfoque, que da contraste 5.0 sobre
   cualquier mapa (WCAG AA pide 4.5).                                        */

.dh-translucent-bar {
  background: color-mix(in srgb, var(--tblr-bg-surface) 82%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  box-shadow: 0 -1px 12px rgba(0, 0, 0, .12);
}

/* Chips de capas activas flotando sobre el mapa. Fondo opaco a propósito: un
   chip translúcido sobre un mapa con etiquetas debajo no se lee. */
.dh-chip {
  background: var(--tblr-bg-surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .2);
}

/* ---------------------------------------------------------------------------
   2. Cajón inferior (bottom sheet)
   ---------------------------------------------------------------------------
   El contenedor es `.offcanvas.offcanvas-bottom`, primitivo REAL de Tabler.
   Lo único propio es el asa y el gesto de arrastre, que Bootstrap no trae
   (solo cierra con Esc, backdrop o botón).

   El alto se fija sobre la variable real `--tblr-offcanvas-height`, NUNCA con
   `height` a secas: Tabler anima esa variable, y pisar `height` rompe la
   transición de apertura. Se acompaña de un `height` con selector de la misma
   especificidad que Tabler porque en aft-platform se midió un caso donde la
   variable sola no bastaba (ver `components/bottom-sheet.md`).

   `dvh` y no `vh`: en Safari real `vh` cuenta la barra del navegador aunque
   esté oculta y el cajón queda más alto de lo que cabe en pantalla.          */

.offcanvas.offcanvas-bottom.dh-bottom-sheet {
  --tblr-offcanvas-height: 82dvh;
  height: 82dvh;
  border-radius: 16px 16px 0 0;
  display: flex;
  flex-direction: column;
}

.offcanvas.offcanvas-bottom.dh-bottom-sheet.dh-sheet-auto {
  --tblr-offcanvas-height: auto;
  height: auto;
  max-height: 82dvh;
}

.dh-bottom-sheet-grip {
  width: 38px;
  height: 4px;
  border-radius: 2px;
  background: var(--tblr-border-color);
  margin: .5rem auto .25rem;
  flex: none;
}

/* Durante el arrastre se anula la transición para que el cajón siga al dedo
   sin el retraso de la animación. */
.dh-bottom-sheet-dragging {
  transition: none !important;
}

/* Panel lateral que funciona a CUALQUIER ancho.
   ---------------------------------------------------------------------------
   Ojo con `.offcanvas-md` y sus hermanos: son offcanvas RESPONSIVE. Por encima
   de su breakpoint Bootstrap desactiva su propio JS a propósito y Tabler les
   pone `background-color: transparent !important`. Usarlos para "cajón abajo en
   móvil, panel al lado en escritorio" NO funciona: en escritorio no se abren y
   se ven rotos. Fue un fallo real que tumbó todos los paneles del producto.

   La solución es `offcanvas-end` a secas, que va a cualquier ancho, más esta
   regla para que en móvil ocupe la pantalla: 400px en un teléfono de 390
   dejaría el contenido pegado al borde. */
.offcanvas.offcanvas-end.dh-panel {
  --tblr-offcanvas-width: 440px;
}

@media (max-width: 575.98px) {
  .offcanvas.offcanvas-end.dh-panel {
    --tblr-offcanvas-width: 100%;
  }
}

/* ---------------------------------------------------------------------------
   3. Zona segura del iPhone
   ---------------------------------------------------------------------------
   Sin esto, Safari en iPhone deja una franja blanca bajo la barra inferior o
   tapa contenido con la barra de gestos. No hay primitivo de Tabler para el
   notch: es una necesidad de plataforma, no de tema visual.                  */

.dh-safe-bottom {
  padding-bottom: calc(.5rem + env(safe-area-inset-bottom));
}

.dh-fab-stack {
  bottom: calc(var(--dh-barra-alto, 4.5rem) + env(safe-area-inset-bottom));
}

/* ---------------------------------------------------------------------------
   Mapa — geometría del lienzo y cromo flotante
   ---------------------------------------------------------------------------
   Composición pedida por el propietario (2026-09-10): el mapa ocupa TODA la
   pantalla bajo la cabecera, y el resto de controles flotan encima ceñidos al
   ancho por defecto de la plantilla. Antes el mapa era una columna más en el
   flujo, y había que bajar con la rueda para llegar a la línea de tiempo.

   `--dh-top` lo calcula el JavaScript midiendo el borde inferior real de la
   barra de navegación. Es más robusto que un `100vh` a ciegas: no depende de
   conocer de antemano la altura de la cabecera, que cambia con el tema y con el
   idioma.                                                                    */

/* La cabecera, por encima de TODO el cromo del mapa.
   ---------------------------------------------------------------------------
   FALLO REAL (2026-09-10, visto en un iPhone): el menú principal se abría y no
   se veía. En móvil, `#navbar-menu` es un `collapse` DENTRO de la cabecera, así
   que al desplegarse crece hacia abajo... justo donde empieza el mapa. La
   cabecera no llevaba `z-index`, el mapa sí (aunque fuera 0) y va después en el
   documento, así que ganaba el mapa y el menú quedaba debajo. Desde fuera
   parecía que el botón del menú no hacía nada.

   1000 lo deja por encima del cromo del mapa (500 a 502) y por debajo de los
   modales y cajones de Bootstrap (1045 en adelante), que es donde tiene que
   estar: el menú tapa el mapa, pero un cajón abierto tapa el menú.

   No se remide `--dh-top` al desplegar el menú a propósito: el menú es una capa
   que se pone ENCIMA, y empujar el mapa hacia abajo daría un salto de media
   pantalla cada vez que se abre. */
.page > header {
  position: relative;
  z-index: 1000;
}

/* ...y dentro de la cabecera, la fila de marca y usuario por encima de la del
   menú. Son dos `<header>` hermanos con el MISMO z-index, así que decide el
   orden del documento y gana el segundo — el del menú. El desplegable de la
   cuenta cuelga de la primera fila y se sale de su caja hacia abajo, justo
   donde empieza la segunda: se pintaba DETRÁS del menú y parecía cortado.
   No vale subirle el z-index al `.dropdown-menu`: su padre ya abrió un
   contexto de apilado con el 1000 de arriba, y dentro de ese contexto ningún
   número lo saca. Lo que hay que ordenar son los dos hermanos. */
.page > header.navbar {
  z-index: 1001;
}

#dh-mapa {
  position: fixed;
  top: var(--dh-top, 3.5rem);
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  z-index: 0;
}

/* La capa de cromo ocupa la misma caja que el mapa pero NO intercepta el ratón:
   sin `pointer-events: none` aquí, arrastrar el mapa por una zona vacía del
   cromo no funcionaría. Cada hijo que sí debe recibir clics lo reactiva. */
.dh-overlay {
  position: fixed;
  top: var(--dh-top, 3.5rem);
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 500;
  pointer-events: none;
  display: flex;
  flex-direction: column;
}

.dh-overlay > .container-xl {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;      /* sin esto, un hijo con scroll estira el contenedor */
  padding-top: .5rem;
  padding-bottom: .5rem;
  gap: .5rem;
}

.dh-overlay-fila {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: .5rem;
}

/* Todo lo que se pueda pulsar recupera los eventos del ratón. */
.dh-overlay .card,
.dh-overlay .btn,
.dh-overlay .badge,
.dh-overlay .form-range,
.dh-overlay input,
.dh-overlay select,
.dh-overlay label {
  pointer-events: auto;
}

/* Las tarjetas flotantes son translúcidas con desenfoque: sobre un mapa, un
   fondo sólido tapa demasiado y uno transparente no se lee. Medido en
   aft-platform: con la superficie del tema al 82% más desenfoque, el contraste
   sale 5.0, y WCAG AA pide 4.5. */
.dh-overlay .card {
  background: color-mix(in srgb, var(--tblr-bg-surface) 88%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  box-shadow: 0 2px 16px rgba(0, 0, 0, .18);
}

/* El panel de capas tiene su propio scroll: nunca empuja al mapa ni obliga a
   desplazar la página. */
#esc-panel {
  max-height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

#esc-panel > .card {
  max-height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* La línea de tiempo, abajo y siempre a la vista: era el motivo de la queja
   ("que no haya que hacer scroll para ver cuándo pasó"). */
.dh-overlay-pie {
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
   Las dos pieles, y cuál se ve
   ---------------------------------------------------------------------------
   El mapa emite los DOS marcados —escritorio y móvil— y solo monta uno, el que
   corresponda al ancho (ver ARQUITECTURA_MAPA.md). El CSS esconde el otro sin
   ambigüedad, para que ni siquiera un fallo de JavaScript pueda dejar los dos
   a la vez en pantalla.

   `display: none !important` y no el atributo `hidden`: la piel se destapa
   quitando `hidden` desde su propio montaje, así que hace falta que la regla de
   ancho gane por encima de eso.                                              */

@media (max-width: 991.98px) {
  #esc-overlay { display: none !important; }

  /* El control de zoom sobra en táctil: el pellizco ya hace zoom y competía por
     sitio con la barra inferior. */
  .leaflet-control-zoom { display: none; }
}

@media (min-width: 992px) {
  #mov-piel { display: none !important; }
}

/* ---------------------------------------------------------------------------
   Geometría de la piel de móvil
   ---------------------------------------------------------------------------
   No es la de escritorio encogida. Aquí no hay columna lateral ni pie con
   gráfica: hay una barra fina arriba que dice el periodo, una tira abajo con
   los recuentos, y el mapa entero en medio. Todo lo que se toca queda al
   alcance del pulgar.

   La barra del periodo es un botón de verdad, no un div con un manejador: se
   llega a ella con el teclado y la lee un lector de pantalla.

   La tira de abajo sí es un div, porque contiene DOS botones —reproducir y
   abrir la línea de tiempo— y un botón dentro de otro no es marcado válido.  */

.dh-mov-barra,
.dh-mov-tira {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  width: 100%;
  border: 0;
  border-radius: 0;
  padding: .45rem .75rem;
  color: inherit;
  text-align: left;
}

.dh-mov-barra {
  top: var(--dh-top, 3.5rem);
  border-bottom: 1px solid var(--tblr-border-color);
  font-size: .85rem;
}

.dh-mov-tira {
  bottom: 0;
  border-top: 1px solid var(--tblr-border-color);
  /* La zona segura del iPhone: sin esto, la barra de gestos tapa las cifras. */
  padding-bottom: calc(.45rem + env(safe-area-inset-bottom));
  min-height: 3.2rem;
}

/* Sin capas temporales no hay línea de tiempo que abrir. Se apaga el botón que
   la abre, no la tira entera: los recuentos siguen siendo ciertos y visibles. */
#mov-tira-abrir[disabled] {
  opacity: .75;
  pointer-events: none;
}

/* El mapa empieza bajo la barra del periodo, no bajo la cabecera. */
@media (max-width: 991.98px) {
  #dh-mapa { top: calc(var(--dh-top, 3.5rem) + 2.4rem); }
}

/* La atribución de Leaflet, por encima de la tira de recuentos: abajo del todo
   quedaba medio tapada por las cifras. */
@media (max-width: 991.98px) {
  .leaflet-bottom.leaflet-right {
    bottom: calc(3.4rem + env(safe-area-inset-bottom));
  }
}

/* Los botones flotantes, por encima de la tira de recuentos. */
.dh-mov-fabs {
  position: fixed;
  right: .75rem;
  bottom: calc(4.2rem + env(safe-area-inset-bottom));
  z-index: 501;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

/* El aviso de «señala el punto» va centrado y bajo la barra del periodo: es lo
   único que puede haber ahí cuando el mapa está esperando un toque. */
.dh-mov-aviso {
  position: fixed;
  top: calc(var(--dh-top, 3.5rem) + 3rem);
  left: .75rem;
  right: .75rem;
  z-index: 502;
}

/* La atribución de Leaflet.
   ---------------------------------------------------------------------------
   Es obligatoria por licencia de OpenStreetMap y CARTO: no se puede ocultar.
   Pero con la caja blanca que trae de serie, subida por encima del cromo,
   quedaba flotando en mitad del mapa como un cartel suelto.

   Se deja pegada al borde inferior derecho, que es su sitio de siempre, y se
   integra con el tema: fondo translúcido en vez de blanco fijo, y letra
   pequeña. Sigue siendo legible y deja de llamar la atención. */
.leaflet-bottom.leaflet-right {
  bottom: 0;
}

.leaflet-control-attribution {
  background: color-mix(in srgb, var(--tblr-bg-surface) 75%, transparent) !important;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--tblr-secondary) !important;
  font-size: 10px !important;
  padding: 1px 6px !important;
  border-radius: 4px 0 0 0;
}

.leaflet-control-attribution a {
  color: var(--tblr-secondary) !important;
}

/* La tarjeta del pie no llega al borde de la pantalla en escritorio (va ceñida
   al `container-xl`), así que la atribución cabe a su derecha sin taparla. Por
   debajo de ese ancho sí se solaparían, y ahí se sube justo lo necesario. */
@media (max-width: 1400px) {
  .leaflet-bottom.leaflet-right {
    bottom: calc(var(--dh-barra-alto, 3rem) + env(safe-area-inset-bottom));
  }
}

/* ---------------------------------------------------------------------------
   Reparto vertical del cromo
   ---------------------------------------------------------------------------
   Esto se escribió primero confiando en la cadena de flex (contenedor al 100%,
   fila que crece, columna que se estira, separador que empuja) y NO funcionó:
   el pie se quedaba pegado debajo de la barra del «cuándo», con los chips
   encima, en vez de bajar al fondo.

   Cuando una cadena de alturas flex tiene cuatro eslabones, basta que uno no
   resuelva su altura para que se venga abajo entera, y depurar cuál es el que
   falla cuesta más que no depender de ella. Así que se fija explícitamente en
   cada nivel, y el pie se ancla con `margin-top: auto`, que empuja un elemento
   al final de su contenedor sin necesitar ningún separador que crezca.        */

.dh-overlay > .container-xl {
  flex: 1 1 auto;
}

.dh-overlay-fila {
  align-items: stretch;
  height: 100%;
}

/* Las dos columnas, a toda la altura de la fila.
   ---------------------------------------------------------------------------
   `min-height: 0` y `min-width: 0` son los dos imprescindibles, y por el mismo
   motivo: un elemento flex trae de fábrica `min-width/min-height: auto`, que
   significa "no me encojas por debajo de mi contenido". Con eso puesto, un hijo
   ancho o alto EMPUJA al contenedor en vez de desplazarse o recortarse dentro.

   Sin `min-width: 0`, la línea de texto del pie ("8120 eventos repartidos en
   tramos de 1 semana...") ensanchaba la columna derecha más allá del
   contenedor, y el `text-truncate` que debía recortarla no hacía nada: para
   truncar hace falta que el ancestro pueda encogerse. Se veía al ocultar y
   volver a mostrar el panel de capas, porque ahí es cuando la columna cambia de
   ancho. */
#esc-panel,
.dh-overlay-derecha {
  height: 100%;
  min-height: 0;
  min-width: 0;
}

.dh-overlay-fila {
  min-width: 0;
}

/* La gráfica tampoco puede empujar: se adapta al ancho que le den. */
#esc-g-timeline,
#esc-g-timeline .apexcharts-canvas,
#mov-g-timeline,
#mov-g-timeline .apexcharts-canvas {
  max-width: 100%;
}

#esc-panel > .card {
  height: 100%;
}

/* Ocultar el panel de capas.
   ---------------------------------------------------------------------------
   No vale con quitar y poner `d-none` por JavaScript: el panel lleva también
   `d-lg-flex`, que es `display: flex !important` dentro de su media query, y
   gana. El botón de ocultar no hacía absolutamente nada en escritorio, que es
   justo donde tiene sentido usarlo.

   Con el id delante, la especificidad sube lo suficiente para ganarle a la
   utilidad de Bootstrap sin pelearse con `!important`. */
#esc-panel.dh-panel-oculto {
  display: none !important;
}

/* El pie, anclado abajo. `margin-top: auto` es la forma robusta: no depende de
   que ningún separador crezca. */
.dh-overlay-derecha > .dh-overlay-pie {
  margin-top: auto;
}

/* La gráfica de la línea de tiempo es una tira de contexto, no una pantalla de
   análisis: cada píxel que ocupa se lo quita al mapa y al panel de capas. */
#g-timeline {
  min-height: 0;
}

#g-timeline .apexcharts-canvas {
  margin: 0 auto;
}

/* Tom Select y cualquier desplegable que cuelgue del <body> se pintan por
   debajo del offcanvas de Tabler (1045) y parecen "no funcionar" dentro de un
   cajón. Bug real y recurrente; se sube por encima. */
.ts-dropdown { z-index: 1060; }

/* ---------------------------------------------------------------------------
   Menús de acción dentro de una tabla
   ---------------------------------------------------------------------------
   `.table-responsive` lleva `overflow-x: auto`, y eso RECORTA cualquier
   desplegable que se salga de la caja. Con una tabla de pocas filas el menú de
   acciones se abría dentro del propio scroll y quedaba medio cortado.

   El arreglo de verdad va en JS (`datahub.js` posiciona estos menús con
   estrategia `fixed`, que escapa del recorte). Esto de aquí es el cinturón: un
   poco de aire por debajo para que, aun sin JS, el menú tenga dónde caer.

   No se usa `overflow: visible` sobre `.table-responsive`: eso rompería el
   scroll horizontal, que es justo para lo que existe esa clase. */
.table-responsive:has(.dropdown-menu.show) {
  overflow: visible;
}

.card > .table-responsive:last-child {
  padding-bottom: 0;
}

/* ---------------------------------------------------------------------------
   Visor JSON de la pantalla de MCP
   ---------------------------------------------------------------------------
   Tabler no trae resaltado de sintaxis. Los colores salen de la paleta real de
   Tabler (`--tblr-*`), no de una paleta inventada, para que el visor cambie
   solo con el modo claro/oscuro.                                             */

.dh-json {
  font-family: var(--tblr-font-monospace);
  font-size: .8125rem;
  line-height: 1.5;
  white-space: pre;
  overflow: auto;
  tab-size: 2;
}

.dh-json .k { color: var(--tblr-purple); }
.dh-json .s { color: var(--tblr-green); }
.dh-json .n { color: var(--tblr-blue); }
.dh-json .b { color: var(--tblr-orange); font-weight: 600; }
.dh-json .z { color: var(--tblr-secondary); font-style: italic; }
.dh-json .p { color: var(--tblr-secondary); }

/* Nodo plegable del visor: el triángulo es un `::before` sobre un `<span>`,
   no un icono de Tabler, porque va inline dentro de una línea monoespaciada
   y cualquier icono con su propia caja rompe la alineación de columnas. */
.dh-json .t {
  cursor: pointer;
  user-select: none;
  color: var(--tblr-secondary);
}
.dh-json .t::before { content: "▾ "; }
.dh-json .t.dh-cerrado::before { content: "▸ "; }
.dh-json .t.dh-cerrado + .dh-json-cuerpo { display: none; }

/* ---------------------------------------------------------------------------
   Barra de reparto de espacio (catálogo de fuentes)
   ---------------------------------------------------------------------------
   Es un `.progress` real de Tabler con varios `.progress-bar` dentro, que ya
   soporta de fábrica. Lo único propio es el cursor, para que se note que cada
   tramo tiene tooltip.                                                       */

.dh-reparto .progress-bar { cursor: help; }

/* ---------------------------------------------------------------------------
   Asa de arrastre de las tarjetas del inicio (modo «Ordenar»)
   ---------------------------------------------------------------------------
   Tabler no trae arrastrar y soltar. Todo el aspecto del asa son utilidades y
   componentes reales (btn, btn-icon, cursor-grab, bg-body, border...). Lo único
   propio es `touch-action: none`, que Bootstrap/Tabler no ofrecen como
   utilidad: sin ella, en un móvil el navegador interpreta el gesto sobre el asa
   como un desplazamiento de la página, cancela el arrastre y la tarjeta no se
   mueve. Solo afecta al asa (no al resto de la tarjeta, que sigue desplazándose
   con normalidad), y solo existe mientras se ordena.                         */

.dh-asa { touch-action: none; }

/* ---------------------------------------------------------------------------
   Hojas del informe de glucosa (salud_informe.php)
   ---------------------------------------------------------------------------
   El informe son tres tarjetas que al imprimir tienen que ser tres folios A4,
   cada una empezando en el suyo. Tabler imprime la tarjeta sin borde y evita
   partirla por dentro (`.card { break-inside: avoid }`), pero no trae ninguna
   utilidad de salto de página (en su CSS solo existe `break-inside`; no hay
   `break-before` ni `page-break-*`). Solo en impresión y solo entre hojas.   */

@media print {
  .dh-informe-hoja + .dh-informe-hoja { break-before: page; }
}
