diff --git a/assets/css/styles.css b/assets/css/styles.css
index a4480ab..c2fb113 100644
--- a/assets/css/styles.css
+++ b/assets/css/styles.css
@@ -991,6 +991,54 @@ body {
}
}
+/* =================================
+ LAB SIDEBAR TOGGLE (mobile)
+ ================================= */
+
+/* El botón hamburguesa solo es visible en mobile/tablet */
+.lab-sidebar-toggle {
+ display: none !important;
+ flex-shrink: 0;
+ margin-right: 8px;
+}
+
+/* content-header cuando tiene el toggle: evitar desbordamiento del título */
+.content-header.has-sidebar-toggle {
+ gap: 8px;
+ flex-wrap: nowrap;
+}
+.content-header.has-sidebar-toggle > div:nth-child(2) {
+ min-width: 0;
+ flex: 1;
+}
+.content-header.has-sidebar-toggle h1 {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ font-size: clamp(.9rem, 2.5vw, 1.4rem);
+}
+
+@media (max-width: 991.98px) {
+ .lab-sidebar-toggle { display: inline-flex !important; }
+ .content-header.has-sidebar-toggle { padding: 10px 12px; }
+ /* Evitar que el body haga scroll horizontal cuando el sidebar está abierto */
+ body.sidebar-open { overflow: hidden; }
+ /* Contenedores con padding excesivo en móvil */
+ .container-fluid { padding-left: 10px !important; padding-right: 10px !important; }
+}
+
+@media (max-width: 575.98px) {
+ /* Cards de lab en 2 columnas en móvil pequeño */
+ .col-md-3, .col-xl-3, .col-lg-3 { flex: 0 0 50%; max-width: 50%; }
+ /* Tablas lab: texto más pequeño */
+ .table th, .table td { font-size: .78rem; padding: 7px 8px; }
+ /* Header sub-info en móvil */
+ .content-header small { font-size: .7rem; }
+ /* Botón Nuevo en header: ocultar texto, solo icono */
+ .content-header .btn-primary .me-1 ~ * { display: none; }
+}
+
/* =================================
CHAT STYLES
================================= */
diff --git a/assets/js/lab-sidebar.js b/assets/js/lab-sidebar.js
new file mode 100644
index 0000000..6a3fce2
--- /dev/null
+++ b/assets/js/lab-sidebar.js
@@ -0,0 +1,78 @@
+/**
+ * lab-sidebar.js — Toggle responsivo del sidebar para todas las páginas del Módulo Lab.
+ * Se auto-inyecta en el header y maneja el overlay.
+ */
+(function () {
+ 'use strict';
+
+ // ── 1. Overlay ──────────────────────────────────────────────────────────
+ var overlay = document.createElement('div');
+ overlay.className = 'sidebar-overlay';
+ document.body.appendChild(overlay);
+
+ // ── 2. Botón hamburguesa ────────────────────────────────────────────────
+ var btn = document.createElement('button');
+ btn.id = 'sidebar-toggle';
+ btn.className = 'btn btn-light btn-sm lab-sidebar-toggle';
+ btn.title = 'Abrir menú';
+ btn.innerHTML = '';
+
+ // Inyectar como primer hijo del content-header
+ var header = document.querySelector('.content-header');
+ if (header) {
+ header.insertBefore(btn, header.firstChild);
+ header.classList.add('has-sidebar-toggle');
+ }
+
+ // ── 3. Toggle logic ──────────────────────────────────────────────────────
+ var sidebar = document.querySelector('.sidebar');
+
+ function openSidebar() {
+ if (!sidebar) return;
+ sidebar.classList.add('open');
+ overlay.style.display = 'block';
+ document.body.classList.add('sidebar-open');
+ }
+
+ function closeSidebar() {
+ if (!sidebar) return;
+ sidebar.classList.remove('open');
+ overlay.style.display = 'none';
+ document.body.classList.remove('sidebar-open');
+ }
+
+ btn.addEventListener('click', function (e) {
+ e.stopPropagation();
+ if (sidebar && sidebar.classList.contains('open')) {
+ closeSidebar();
+ } else {
+ openSidebar();
+ }
+ });
+
+ // Cerrar al hacer clic en el overlay
+ overlay.addEventListener('click', closeSidebar);
+
+ // Cerrar con Escape
+ document.addEventListener('keydown', function (e) {
+ if (e.key === 'Escape') closeSidebar();
+ });
+
+ // Cerrar al navegar (móvil: clic en enlace del sidebar)
+ if (sidebar) {
+ sidebar.querySelectorAll('.nav-link').forEach(function (link) {
+ link.addEventListener('click', function () {
+ if (window.innerWidth < 992) closeSidebar();
+ });
+ });
+ }
+
+ // ── 4. Visibility control ────────────────────────────────────────────────
+ // El CSS ya maneja display vía media queries; solo necesitamos que el botón
+ // sea display:none en desktop y visible en mobile. Lo hacemos por CSS inline
+ // inicial y dejamos que styles.css lo maneje vía #sidebar-toggle.
+ // Aplicamos clase específica para que el CSS pueda targetarla:
+ // .lab-sidebar-toggle { display: none } en >=992px lo hace styles.css
+ // via #sidebar-toggle { display: none !important }
+
+})();
diff --git a/lab_configuracion.php b/lab_configuracion.php
index e3befb5..ab4e0b4 100644
--- a/lab_configuracion.php
+++ b/lab_configuracion.php
@@ -328,5 +328,6 @@ async function guardar() {
}
}
+