<?php
/**
 * Puesto de Recepción — Módulo Turnero
 * Requiere login + módulo turnero.
 */
require_once __DIR__ . '/../../../config/config.php';
if (!isUserLoggedIn()) {
    header('Location: ' . BASE_URL . 'login.php');
    exit;
}

// Cargar catálogos para la ficha
try {
    $pdo = Database::getInstance()->getConnection();

    $lugarRecepcion = $pdo->query(
        "SELECT id, nombre FROM turnero_lugares WHERE tipo='recepcion' AND activo=1 ORDER BY sort_order LIMIT 1"
    )->fetch(PDO::FETCH_ASSOC);

    // Destinos agrupados: un representante por grupo_id, individuales si grupo_id=NULL
    $lugaresDestino = $pdo->query(
        "SELECT MIN(id) AS id,
                CASE WHEN grupo_id IS NOT NULL THEN 'Toma de Muestras' ELSE nombre END AS nombre,
                grupo_id
           FROM turnero_lugares
          WHERE tipo='muestras' AND activo=1
          GROUP BY COALESCE(grupo_id, id)
          ORDER BY MIN(sort_order)"
    )->fetchAll(PDO::FETCH_ASSOC);
    $lugarMuestras = $lugaresDestino[0] ?? null;

    $examenes = $pdo->query(
        "SELECT id, codigo, nombre, categoria FROM exam_tipos WHERE activo = 1 ORDER BY categoria, nombre"
    )->fetchAll(PDO::FETCH_ASSOC);

    // Agrupar exámenes por categoría
    $examenesAgrupados = [];
    foreach ($examenes as $ex) {
        $cat = $ex['categoria'] ?: 'General';
        $examenesAgrupados[$cat][] = $ex;
    }

    // Escritorio de recepción (vía ?desk_id=X)
    $deskId = (int)($_GET['desk_id'] ?? 0);
    $desk   = null;
    $desksRecepcion = $pdo->query(
        "SELECT id, nombre FROM turnero_lugares WHERE tipo='recepcion' AND activo=1 ORDER BY sort_order"
    )->fetchAll(PDO::FETCH_ASSOC);

    if ($deskId) {
        foreach ($desksRecepcion as $d) {
            if ($d['id'] === $deskId) { $desk = $d; break; }
        }
        if (!$desk) { $deskId = 0; }
    }
    // Si solo hay un escritorio, asignarlo automáticamente
    if (!$deskId && count($desksRecepcion) === 1) {
        $desk   = $desksRecepcion[0];
        $deskId = (int)$desk['id'];
    }
} catch (\Throwable $e) {
    $lugares = [];
    $examenesAgrupados = [];
    $deskId = 0;
    $desk   = null;
    $lugarRecepcion = null;
    $lugarMuestras  = null;
}

$deskNombre  = $desk['nombre'] ?? null;  // null = vista genérica
$adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['username'] ?? 'Operador';
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars($deskNombre ?? 'Recepción') ?> — Turnero</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="<?= BASE_URL ?>assets/css/styles.css?v=12" rel="stylesheet">
    <style>
        /* ── Layout de dos columnas ── */
        .rec-layout {
            display: grid;
            grid-template-columns: 320px 1fr;
            height: calc(100vh - 56px);
            overflow: hidden;
        }
        @media (max-width: 900px) {
            .rec-layout { grid-template-columns: 1fr; position: relative; overflow: hidden; }
            .rec-cola { transition: transform .2s ease; }
            .rec-cola.mobile-oculta { transform: translateX(-100%); position: absolute; inset: 0; pointer-events: none; }
            .rec-ficha { position: absolute; inset: 0; background: #fff; z-index: 10; transform: translateX(100%); transition: transform .2s ease; overflow-y: auto; }
            .rec-ficha.mobile-visible { transform: translateX(0); }
            .btn-volver-cola { display: inline-flex !important; align-items: center; gap: 6px; }
        }

        /* ── Columna cola ── */
        .rec-cola {
            background: #f8fafc;
            border-right: 1px solid #e2e8f0;
            display: flex; flex-direction: column;
            overflow: hidden;
        }
        .rec-cola-header {
            padding: 1rem 1.2rem .6rem;
            background: #fff; border-bottom: 1px solid #e2e8f0;
            flex-shrink: 0;
        }
        .cola-items { flex: 1; overflow-y: auto; padding: .5rem; }
        .cola-card {
            background: #fff; border: 1px solid #e2e8f0;
            border-radius: 10px; padding: .65rem .9rem;
            margin-bottom: .4rem; cursor: default;
            display: flex; align-items: center; gap: .6rem;
            transition: box-shadow .15s;
        }
        .cola-card.activo { border-color: #3b82f6; box-shadow: 0 0 0 2px #bfdbfe; }
        .cola-card .prio-dot {
            width: 36px; height: 36px; border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            font-size: 1.1rem; font-weight: 800; color: #fff; flex-shrink: 0;
        }
        .cola-card .turno-info { flex: 1; min-width: 0; }
        .cola-card .turno-info .cod { font-size: 1rem; font-weight: 700; }
        .cola-card .turno-info .pac { font-size: .78rem; color: #64748b;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .cola-vacia { text-align: center; padding: 3rem 1rem; color: #94a3b8; }

        /* ── Columna ficha ── */
        .rec-ficha {
            overflow-y: auto; padding: 1.5rem;
            background: #fff;
        }
        .ficha-placeholder {
            display: flex; flex-direction: column;
            align-items: center; justify-content: center;
            height: 100%; color: #94a3b8; text-align: center;
        }

        /* ── Secciones de la ficha ── */
        .ficha-section {
            background: #f8fafc; border: 1px solid #e2e8f0;
            border-radius: 12px; padding: 1.2rem; margin-bottom: 1rem;
        }
        .ficha-section h6 { color: #475569; font-size: .78rem;
            text-transform: uppercase; letter-spacing: .08em; margin-bottom: .8rem; }

        /* ── Búsqueda de paciente ── */
        .pac-resultado {
            border: 1px solid #e2e8f0; border-radius: 8px; padding: .5rem .75rem;
            cursor: pointer; margin-top: .25rem; transition: background .12s;
        }
        .pac-resultado:hover { background: #f1f5f9; }
        .pac-resultado .pac-nombre { font-weight: 600; font-size: .9rem; }
        .pac-resultado .pac-doc    { font-size: .78rem; color: #64748b; }
        .pac-seleccionado {
            background: #eff6ff; border: 1px solid #93c5fd;
            border-radius: 8px; padding: .65rem .9rem;
            display: flex; align-items: center; justify-content: space-between;
        }

        /* ── Checkboxes de exámenes ── */
        .exam-group-title { font-size: .75rem; color: #94a3b8;
            text-transform: uppercase; letter-spacing: .08em; margin: .6rem 0 .3rem; }
        .exam-check-item { display: flex; align-items: center; gap: .5rem;
            padding: .3rem .4rem; border-radius: 6px; cursor: pointer;
            transition: background .1s; font-size: .88rem; }
        .exam-check-item:hover { background: #f1f5f9; }
        .exam-check-item input[type=checkbox] { cursor: pointer; }

        /* ── Consentimientos ── */
        .consent-item {
            display: flex; align-items: center; gap: .5rem;
            padding: .5rem .7rem; border-radius: 10px;
            font-size: .84rem; margin-bottom: .4rem;
            border: 1px solid transparent;
        }
        .consent-item.firmado   { background: #f0fdf4; color: #166534; border-color: #bbf7d0; }
        .consent-item.pendiente { background: #fffbeb; color: #92400e; border-color: #fde68a; }
        .consent-item.enviado   { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
        .consent-item.visto     { background: #faf5ff; color: #6b21a8; border-color: #ddd6fe; }
        .consent-item.rechazado { background: #f8fafc; color: #64748b; border-color: #e2e8f0; }
        .consent-item .c-nom    { flex: 1; font-weight: 500; }
        .consent-item .c-badge  { font-size: .7rem; font-weight: 700; padding: 1px 8px;
                                   border-radius: 99px; border: 1px solid currentColor; opacity: .85; }
        .consent-acciones       { display: flex; gap: .3rem; flex-shrink: 0; }
        .consent-acciones .btn  { font-size: .72rem; padding: 2px 8px; border-radius: 7px; }
        .consent-prof-row       { display:flex; align-items:center; gap:.4rem; font-size:.75rem;
                                   margin-top:.25rem; padding-top:.25rem; border-top:1px solid rgba(0,0,0,.07); }
        .consent-prof-row .badge { font-size:.65rem; }

        /* ── Barra de acciones ── */
        .ficha-acciones {
            position: sticky; bottom: 0;
            background: #fff; border-top: 1px solid #e2e8f0;
            padding: 1rem 0 .25rem; margin-top: 1rem;
            display: flex; gap: .5rem; flex-wrap: wrap;
        }

        /* ── Badge de turno activo en topbar ── */
        .badge-turno-activo {
            background: #eff6ff; color: #1d4ed8;
            border: 1px solid #bfdbfe; border-radius: 8px;
            padding: .25rem .75rem; font-size: .82rem; font-weight: 700;
        }

        /* ── Toast ── */
        .rec-toast {
            position: fixed; bottom: 2rem; right: 2rem; z-index: 9999;
            display: flex; align-items: center; gap: .7rem;
            padding: .8rem 1.2rem; border-radius: 12px;
            background: #fff; border: 1px solid #e2e8f0;
            box-shadow: 0 8px 30px rgba(0,0,0,.12);
            font-size: .9rem; font-weight: 500;
            transform: translateY(120%); opacity: 0;
            transition: transform .3s ease, opacity .3s ease;
            pointer-events: none;
        }
        .rec-toast.show {
            transform: translateY(0); opacity: 1;
        }
        .rec-toast.success { border-left: 4px solid #22c55e; }
        .rec-toast.info    { border-left: 4px solid #3b82f6; }
        .rec-toast.warn    { border-left: 4px solid #f59e0b; }
        .rec-toast.error   { border-left: 4px solid #ef4444; }
        .rec-toast .ico    { font-size: 1.2rem; }
        .rec-toast.success .ico { color: #22c55e; }
        .rec-toast.info    .ico { color: #3b82f6; }
        .rec-toast.warn    .ico { color: #f59e0b; }
        .rec-toast.error   .ico { color: #ef4444; }

        /* ── Historial del paciente ── */
        .hist-toggle-btn {
            display: flex; align-items: center; gap: 6px;
            width: 100%; padding: 6px 10px; margin-top: 8px;
            background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;
            font-size: .78rem; font-weight: 600; color: #475569;
            cursor: pointer; text-align: left; transition: background .15s;
        }
        .hist-toggle-btn:hover { background: #f1f5f9; }
        .hist-toggle-btn .hist-chev { margin-left: auto; transition: transform .2s; }
        .hist-toggle-btn.open .hist-chev { transform: rotate(180deg); }
        .hist-pac-body {
            border: 1px solid #e2e8f0; border-top: none;
            border-radius: 0 0 8px 8px; background: #fff;
            max-height: 260px; overflow-y: auto;
        }
        .pac-timeline { padding: 10px 12px; }
        .timeline-item {
            display: flex; gap: 10px; align-items: flex-start;
            padding-bottom: 10px; position: relative;
        }
        .timeline-item:not(:last-child)::before {
            content: ''; position: absolute; left: 6px; top: 14px;
            width: 2px; bottom: 0; background: #e2e8f0;
        }
        .timeline-dot {
            width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0;
            margin-top: 2px; border: 2px solid #fff;
            box-shadow: 0 0 0 2px currentColor;
        }
        .timeline-content { flex: 1; min-width: 0; }
        .timeline-fecha { font-size: .68rem; color: #94a3b8; }
        .timeline-codigo { font-size: .82rem; font-weight: 700; }
        .timeline-lugar { font-size: .73rem; color: #64748b; }
        .timeline-eb { font-size: .62rem; padding: 1px 7px; border-radius: 99px; font-weight: 700; display: inline-block; margin-top: 2px; }
    </style>
</head>
<body>
<?php
$SIDEBAR_TITLE = 'Turnero';
$SIDEBAR_ICON  = 'fas fa-ticket-alt';
require_once __DIR__ . '/../../../shared/components/sidebar.php';
?>

<?php if (!$deskId && count($desksRecepcion) > 1): ?>
<!-- Modal selector de escritorio (se muestra si no hay desk_id en URL) -->
<div class="modal fade" id="modalDeskSelect" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header" style="background:var(--doc-color,#1565c0);color:#fff">
                <h5 class="modal-title"><i class="fas fa-desktop me-2"></i>Seleccione su escritorio</h5>
            </div>
            <div class="modal-body pb-2">
                <p class="text-muted small mb-3">¿Desde qué escritorio de recepción está trabajando hoy?</p>
                <div class="d-grid gap-2">
                    <?php foreach ($desksRecepcion as $d): ?>
                    <a href="?m=turnero&v=recepcion&desk_id=<?= $d['id'] ?>"
                       class="btn btn-outline-primary btn-lg">
                        <i class="fas fa-chair me-2"></i><?= htmlspecialchars($d['nombre']) ?>
                    </a>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
    new bootstrap.Modal(document.getElementById('modalDeskSelect')).show();
});
</script>
<?php endif; ?>

<main class="main-content" style="padding:0">

    <!-- ── Top bar ──────────────────────────────────────────── -->
    <div class="content-header d-flex align-items-center justify-content-between px-3 py-2 border-bottom bg-white"
         style="position:sticky;top:0;z-index:100">
        <div class="d-flex align-items-center gap-2">
            <i class="fas fa-concierge-bell text-primary"></i>
            <strong><?= htmlspecialchars($deskNombre ?? 'Recepción') ?></strong>
            <span id="badge-turno-activo" class="badge-turno-activo d-none">
                Turno: <span id="badge-codigo">—</span>
            </span>
        </div>
        <div class="d-flex align-items-center gap-2">
            <span class="text-muted small"><?= htmlspecialchars($adminNombre) ?></span>
            <?php if ($deskId): ?>
            <a href="<?= BASE_URL ?>erp.php?m=turnero&v=display_recepcion&desk_id=<?= $deskId ?>" class="btn btn-outline-info btn-sm" target="_blank">
                <i class="fas fa-tv me-1"></i>Ver Pantalla
            </a>
            <?php endif; ?>
            <button class="btn btn-primary btn-sm" id="btn-llamar" onclick="llamarSiguiente()">
                <i class="fas fa-bell me-1"></i>Llamar siguiente
            </button>
        </div>
    </div>

    <div class="rec-layout">

        <!-- ══ Columna izquierda: cola ════════════════════════ -->
        <div class="rec-cola">
            <div class="rec-cola-header">
                <div class="d-flex align-items-center justify-content-between">
                    <span class="fw-semibold text-secondary small">
                        <i class="fas fa-list-ol me-1"></i>EN ESPERA
                    </span>
                    <span class="badge bg-primary rounded-pill" id="badge-count">0</span>
                </div>
            </div>
            <div class="cola-items" id="cola-items">
                <div class="cola-vacia">
                    <i class="fas fa-hourglass-start fa-2x mb-2 d-block"></i>
                    Cola vacía
                </div>
            </div>
        </div>

        <!-- ══ Columna derecha: ficha del turno ═══════════════ -->
        <div class="rec-ficha" id="rec-ficha">
            <button class="btn btn-sm btn-outline-secondary btn-volver-cola mb-3"
                    style="display:none" onclick="volverACola()">
                <i class="fas fa-arrow-left"></i> Cola
            </button>

            <div class="ficha-placeholder" id="ficha-placeholder">
                <i class="fas fa-ticket-alt fa-3x mb-3" style="color:#cbd5e1"></i>
                <p class="mb-0 fw-semibold">Sin turno activo</p>
                <small class="text-muted">Haga clic en <i class="fas fa-bell"></i> de un turno para llamarlo, o use "Llamar siguiente"</small>
            </div>

            <!-- Ficha de turno (oculta hasta llamar) -->
            <div id="ficha-turno" class="d-none">

                <!-- Encabezado del turno -->
                <div class="d-flex align-items-center gap-3 mb-3">
                    <div id="ficha-prio-dot" class="prio-dot"
                         style="width:52px;height:52px;border-radius:12px;display:flex;align-items:center;
                                justify-content:center;font-size:1.6rem;font-weight:900;color:#fff;background:#3b82f6">
                        —
                    </div>
                    <div class="flex-grow-1">
                        <div class="h4 mb-0 fw-bold" id="ficha-codigo">—</div>
                        <div class="text-muted small" id="ficha-prio-nombre">—</div>
                    </div>
                    <button class="btn btn-outline-primary btn-sm" onclick="rellamarActivo()"
                            title="Volver a llamar este turno (suena en pantalla)">
                        <i class="fas fa-bell"></i> Re-llamar
                    </button>
                </div>

                <!-- ── Sección 1: Paciente ── -->
                <!-- ── Número de orden ── -->
                <div class="ficha-section" style="padding-bottom:10px;border-bottom:1px solid #f1f5f9;margin-bottom:4px">
                    <div class="d-flex align-items-center gap-2">
                        <label style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#94a3b8;white-space:nowrap;margin:0">
                            <i class="fas fa-hashtag me-1"></i>N.° Orden
                        </label>
                        <input type="text" id="inp-consecutivo"
                               class="form-control form-control-sm"
                               style="max-width:140px;font-weight:700;font-size:.95rem;letter-spacing:.04em"
                               placeholder="Cargando…" autocomplete="off">
                        <button class="btn btn-outline-secondary btn-sm" title="Regenerar siguiente" onclick="recargarConsecutivo()" type="button">
                            <i class="fas fa-rotate-right" style="font-size:.75rem"></i>
                        </button>
                    </div>
                </div>

                <div class="ficha-section">
                    <h6><i class="fas fa-user me-1"></i>Paciente</h6>

                    <!-- Si el kiosko capturó un nombre -->
                    <div id="bloque-nombre-kiosko" class="d-none mb-2">
                        <small class="text-muted">Kiosko:</small>
                        <div class="fw-semibold" id="lbl-nombre-kiosko"></div>
                        <div id="bloque-pac-kiosko" class="d-none mt-1">
                            <small class="text-muted">Paciente:</small>
                            <div class="fw-semibold text-primary" id="lbl-pac-kiosko-nombre"></div>
                        </div>
                    </div>

                    <div id="bloque-pac-no-vinculado">
                        <div class="input-group mb-2">
                            <input type="text" id="inp-buscar-pac"
                                   class="form-control form-control-sm"
                                   placeholder="Buscar por nombre o documento…"
                                   autocomplete="off">
                            <button class="btn btn-outline-secondary btn-sm" onclick="buscarPaciente()" type="button">
                                <i class="fas fa-search"></i>
                            </button>
                        </div>
                        <div id="lista-pacientes-res"></div>
                    </div>

                    <div id="bloque-pac-seleccionado" class="d-none">
                        <div class="pac-seleccionado">
                            <div>
                                <div class="fw-semibold" id="lbl-pac-nombre">—</div>
                                <div class="text-muted small" id="lbl-pac-doc">—</div>
                                <div class="text-muted small" id="lbl-pac-cel"></div>
                            </div>
                            <div class="d-flex gap-1">
                                <button class="btn btn-outline-primary btn-sm" onclick="abrirModalPaciente(pacienteActivo?.id)" title="Ver / Editar paciente">
                                    <i class="fas fa-pen fa-xs"></i>
                                </button>
                                <button class="btn btn-outline-secondary btn-sm" onclick="cambiarPaciente()" title="Buscar otro paciente">
                                    <i class="fas fa-exchange-alt fa-xs"></i>
                                </button>
                            </div>
                        </div>

                        <!-- Historial colapsable del paciente -->
                        <div id="sec-historial-pac" class="d-none">
                            <button class="hist-toggle-btn" id="btn-hist-toggle" onclick="toggleHistorialPaciente()">
                                <i class="fas fa-history" style="color:#6366f1"></i>
                                Historial del paciente
                                <i class="fas fa-chevron-down hist-chev"></i>
                            </button>
                            <div id="hist-pac-body" class="hist-pac-body d-none">
                                <div id="hist-pac-content" class="pac-timeline">
                                    <div class="text-center text-muted py-2 small">
                                        <i class="fas fa-spinner fa-spin me-1"></i>Cargando…
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Embarazo -->
                        <div class="mt-2">
                            <div class="form-check">
                                <input class="form-check-input" type="checkbox" id="chk-embarazada">
                                <label class="form-check-label small fw-semibold text-danger" for="chk-embarazada">
                                    <i class="fas fa-baby me-1"></i>Paciente embarazada
                                </label>
                            </div>
                        </div>

                        <!-- Médico tratante -->
                        <div class="mt-2" id="bloque-medico">
                            <div class="small fw-semibold text-secondary mb-1">
                                <i class="fas fa-user-md me-1"></i>Médico tratante <span class="text-muted fw-normal">(opcional)</span>
                            </div>
                            <div id="medico-seleccionado" class="d-none mb-1">
                                <span class="badge text-bg-light border" style="font-size:.8rem;padding:5px 9px" id="medico-badge-txt"></span>
                                <button type="button" class="btn btn-link btn-sm p-0 ms-1 text-danger" onclick="quitarMedico()" title="Quitar médico"><i class="fas fa-times"></i></button>
                            </div>
                            <div id="medico-buscador">
                                <input type="text" id="inp-buscar-medico" class="form-control form-control-sm"
                                       placeholder="Buscar por nombre, código o doc…"
                                       autocomplete="off" oninput="buscarMedico()">
                                <div id="medico-dropdown" class="position-relative">
                                    <ul id="medico-resultados" class="list-unstyled mb-0 border rounded bg-white shadow-sm position-absolute w-100 d-none"
                                        style="z-index:200;max-height:180px;overflow-y:auto;top:2px"></ul>
                                </div>
                            </div>
                            <input type="hidden" id="inp-medico-id">
                        </div>
                    </div>
                </div>

                <!-- ── Sección 2: Lugar destino ── -->
                <div class="ficha-section">
                    <h6><i class="fas fa-map-marker-alt me-1"></i>Lugar destino</h6>
                    <select id="sel-lugar" class="form-select form-select-sm">
                        <option value="">— Seleccione destino —</option>
                        <?php foreach ($lugaresDestino as $ld): ?>
                        <option value="<?= (int)$ld['id'] ?>"><?= htmlspecialchars($ld['nombre']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>

                <!-- ── Sección 3: Exámenes ── -->
                <div class="ficha-section">
                    <h6><i class="fas fa-vial me-1"></i>Exámenes solicitados</h6>
                    <div class="form-check mb-2">
                        <input class="form-check-input" type="checkbox" id="chk-solo-muestras" onchange="toggleSoloMuestras()">
                        <label class="form-check-label small fw-semibold text-warning" for="chk-solo-muestras">
                            <i class="fas fa-vial me-1"></i>Solo entrega de muestras
                        </label>
                    </div>
                    <div id="lista-examenes">
                        <?php foreach ($examenesAgrupados as $cat => $items): ?>
                        <div class="exam-group-title"><?= htmlspecialchars($cat) ?></div>
                        <?php foreach ($items as $ex): ?>
                        <label class="exam-check-item">
                            <input type="checkbox" class="exam-chk"
                                   value="<?= (int)$ex['id'] ?>"
                                   data-nombre="<?= htmlspecialchars($ex['nombre']) ?>">
                            <span><strong><?= htmlspecialchars($ex['codigo']) ?></strong>
                                — <?= htmlspecialchars($ex['nombre']) ?></span>
                        </label>
                        <?php endforeach; ?>
                        <?php endforeach; ?>
                    </div>
                    <div class="mt-2 d-flex gap-2 flex-wrap">
                        <button class="btn btn-outline-secondary btn-sm" onclick="toggleTodosExamenes(false)">
                            Limpiar
                        </button>
                    </div>
                </div>

                <!-- ── Sección 4: Pago ── -->
                <div class="ficha-section">
                    <h6><i class="fas fa-dollar-sign me-1"></i>Cobro (opcional)</h6>
                    <div class="row g-2">
                        <div class="col-6">
                            <input type="number" id="inp-total" class="form-control form-control-sm"
                                   placeholder="Total $" step="100" min="0">
                        </div>
                        <div class="col-6">
                            <select id="sel-pago" class="form-select form-select-sm" onchange="togglePagoCombinado()">
                                <option value="">— Forma de pago —</option>
                                <option value="efectivo">Efectivo</option>
                                <option value="transferencia">Transferencia</option>
                                <option value="tarjeta">Tarjeta</option>
                                <option value="eps">EPS / Convenio</option>
                                <option value="cortesia">Cortesía</option>
                                <option value="combinado">Pago combinado</option>
                            </select>
                        </div>
                    </div>
                    <!-- Panel pago combinado -->
                    <div id="panel-combinado" class="d-none mt-2 p-2 border rounded" style="background:#f8fafc">
                        <div class="row g-2 align-items-center mb-1">
                            <div class="col-5"><label class="form-label mb-0 small fw-semibold"><i class="fas fa-money-bill-wave me-1 text-success"></i>Efectivo</label></div>
                            <div class="col-7"><input type="number" id="comb-efectivo" class="form-control form-control-sm" placeholder="$0" min="0" step="100" oninput="sumarCombinado()"></div>
                        </div>
                        <div class="row g-2 align-items-center mb-1">
                            <div class="col-5"><label class="form-label mb-0 small fw-semibold"><i class="fas fa-university me-1 text-primary"></i>Transferencia</label></div>
                            <div class="col-7"><input type="number" id="comb-transferencia" class="form-control form-control-sm" placeholder="$0" min="0" step="100" oninput="sumarCombinado()"></div>
                        </div>
                        <div class="row g-2 align-items-center">
                            <div class="col-5"><label class="form-label mb-0 small fw-semibold"><i class="fas fa-credit-card me-1 text-warning"></i>Tarjeta</label></div>
                            <div class="col-7"><input type="number" id="comb-tarjeta" class="form-control form-control-sm" placeholder="$0" min="0" step="100" oninput="sumarCombinado()"></div>
                        </div>
                    </div>
                    <textarea id="inp-obs" class="form-control form-control-sm mt-2"
                              rows="2" placeholder="Observaciones…" maxlength="500"></textarea>
                </div>

                <!-- ── Sección 5: Consentimientos ── -->
                <div class="ficha-section" id="sec-consentimientos" style="display:none">
                    <div class="d-flex align-items-center justify-content-between mb-2">
                        <h6 class="mb-0"><i class="fas fa-file-signature me-1"></i>Consentimientos informados</h6>
                        <button class="btn btn-sm btn-outline-primary py-0 px-2"
                                id="btn-reenviar-consent" onclick="enviarConsentimientosTodos()"
                                title="Enviar todos por WhatsApp">
                            <i class="fas fa-paper-plane me-1"></i>Enviar todos
                        </button>
                    </div>
                    <div id="lista-consentimientos"></div>
                </div>

                <!-- ── Acciones ── -->
                <div class="ficha-acciones">
                    <button class="btn btn-success" id="btn-guardar" onclick="guardarSolicitud()">
                        <i class="fas fa-save me-1"></i>Guardar solicitud
                    </button>
                    <button class="btn btn-primary d-none" id="btn-pasar-lugar" onclick="pasarALugar()">
                        <i class="fas fa-arrow-right me-1"></i>Pasar a lugar
                    </button>
                    <button class="btn btn-warning d-none" id="btn-enviar-consent" onclick="enviarConsentimientos()">
                        <i class="fas fa-paper-plane me-1"></i>Enviar consentimientos
                    </button>
                    <button class="btn btn-outline-secondary" id="btn-soltar" onclick="soltarTurno()" title="Liberar turno para que otro escritorio lo llame">
                        <i class="fas fa-undo-alt me-1"></i>Soltar
                    </button>
                    <button class="btn btn-secondary ms-auto" onclick="marcarAusente()">
                        <i class="fas fa-user-slash me-1"></i>Ausente
                    </button>
                </div>
            </div><!-- /ficha-turno -->
        </div><!-- /rec-ficha -->

    </div><!-- /rec-layout -->
</main>

<!-- ═══ Modal firma enfermero ═══════════════════════════════════════ -->
<div class="modal fade" id="modalFirmaEnfermero" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header py-2">
                <h6 class="modal-title mb-0"><i class="fas fa-pen-nib me-1"></i>Firma del enfermero</h6>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body text-center">
                <p class="text-muted small mb-2" id="fe-nombre-consentimiento"></p>
                <canvas id="fe-canvas" width="440" height="180"
                        style="border:1px solid #cbd5e1;border-radius:8px;touch-action:none;cursor:crosshair;max-width:100%"></canvas>
                <div class="d-flex justify-content-between mt-2">
                    <button class="btn btn-sm btn-outline-secondary" onclick="feCanvas.limpiar()">
                        <i class="fas fa-eraser me-1"></i>Limpiar
                    </button>
                    <span class="text-muted small align-self-center">Firme en el recuadro</span>
                </div>
            </div>
            <div class="modal-footer py-2">
                <button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
                <button type="button" class="btn btn-primary btn-sm" onclick="feGuardarFirma()">
                    <i class="fas fa-check me-1"></i>Guardar firma
                </button>
            </div>
        </div>
    </div>
</div>

<!-- ═══ Modal Paciente (crear / ver / editar) ════════════════════════════ -->
<div class="modal fade" id="modalPacienteRec" tabindex="-1">
    <div class="modal-dialog modal-lg modal-dialog-scrollable">
        <div class="modal-content border-0 shadow-lg overflow-hidden" style="border-radius:1rem">

            <!-- Header con avatar -->
            <div id="mpac-header"
                 style="background:linear-gradient(135deg,#1043a0 0%,#1565c0 100%);
                        color:#fff;padding:1.3rem 1.5rem 1rem;
                        display:flex;align-items:center;gap:.9rem">
                <div id="mpac-avatar"
                     style="width:52px;height:52px;border-radius:50%;
                            background:rgba(255,255,255,.18);display:flex;
                            align-items:center;justify-content:center;
                            font-size:1.4rem;font-weight:800;color:#fff;
                            border:2px solid rgba(255,255,255,.35);flex-shrink:0">?</div>
                <div class="flex-grow-1">
                    <div style="font-size:1rem;font-weight:700" id="mpac-titulo">Nuevo Paciente</div>
                    <div style="font-size:.75rem;opacity:.75" id="mpac-subtitulo">Completa los datos del paciente</div>
                </div>
                <button type="button" class="btn-close btn-close-white ms-auto" data-bs-dismiss="modal"></button>
            </div>

            <div class="modal-body py-3 px-4">
                <form id="form-paciente-rec" autocomplete="off">
                    <input type="hidden" id="mpac-id">

                    <!-- Datos personales -->
                    <div class="ficha-section mb-3">
                        <h6><i class="fas fa-id-card me-1"></i>Datos personales</h6>
                        <div class="row g-2">
                            <div class="col-12">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-nombre"
                                           required placeholder="Nombre completo"
                                           oninput="mpacAvatar(this.value)">
                                    <label>Nombre completo <span class="text-danger">*</span></label>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <select class="form-select form-select-sm" id="mpac-tipo-doc">
                                        <option value="CC">CC — Cédula</option>
                                        <option value="CE">CE — Extranjería</option>
                                        <option value="TI">TI — Tarjeta Identidad</option>
                                        <option value="PA">PA — Pasaporte</option>
                                        <option value="DE">DE — Doc. Extranjero</option>
                                        <option value="NIT">NIT</option>
                                        <option value="RC">RC — Reg. Civil</option>
                                    </select>
                                    <label>Tipo documento</label>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-doc" placeholder="Número documento">
                                    <label>Número documento</label>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="date" class="form-control form-control-sm" id="mpac-fnac" placeholder="Fecha nacimiento">
                                    <label>Fecha nacimiento</label>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Contacto -->
                    <div class="ficha-section mb-3">
                        <h6><i class="fas fa-phone me-1"></i>Contacto</h6>
                        <div class="row g-2">
                            <div class="col-sm-5">
                                <label class="form-label small fw-semibold mb-1" style="color:#64748b">Teléfono</label>
                                <div class="input-group input-group-sm">
                                    <select id="mpac-tel-prefijo" class="form-select" style="max-width:82px">
                                        <option value="57" selected>🇨🇴 57</option>
                                        <option value="58">🇻🇪 58</option>
                                        <option value="1">🇺🇸 1</option>
                                    </select>
                                    <input type="tel" class="form-control" id="mpac-tel"
                                           placeholder="3001234567" onblur="mpacVerificarWA()">
                                </div>
                                <div id="mpac-wa-badge" style="font-size:.78rem;min-height:18px;margin-top:3px"></div>
                                <input type="hidden" id="mpac-user-id">
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="email" class="form-control form-control-sm" id="mpac-email" placeholder="Email">
                                    <label>Email</label>
                                </div>
                            </div>
                            <div class="col-sm-3">
                                <div class="form-floating">
                                    <select class="form-select form-select-sm" id="mpac-genero">
                                        <option value="">—</option>
                                        <option value="M">Masculino</option>
                                        <option value="F">Femenino</option>
                                        <option value="O">Otro</option>
                                    </select>
                                    <label>Género</label>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Ubicación y EPS -->
                    <div class="ficha-section mb-2">
                        <h6><i class="fas fa-map-marker-alt me-1"></i>Ubicación y EPS</h6>
                        <div class="row g-2">
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-eps" placeholder="EPS">
                                    <label>EPS</label>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-ciudad" placeholder="Ciudad" value="Cúcuta">
                                    <label>Ciudad</label>
                                </div>
                            </div>
                            <div class="col-sm-4">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-barrio" placeholder="Barrio">
                                    <label>Barrio</label>
                                </div>
                            </div>
                            <div class="col-12">
                                <div class="form-floating">
                                    <input type="text" class="form-control form-control-sm" id="mpac-dir" placeholder="Dirección">
                                    <label>Dirección</label>
                                </div>
                            </div>
                            <div class="col-12">
                                <div class="form-floating">
                                    <textarea class="form-control form-control-sm" id="mpac-notas"
                                              placeholder="Notas internas" style="height:68px"></textarea>
                                    <label>Notas internas</label>
                                </div>
                            </div>
                        </div>
                    </div>

                </form>
            </div>

            <div class="modal-footer" style="background:#f8faff;border-top:1px solid #e8edf5;padding:.8rem 1.25rem">
                <button type="button" class="btn btn-sm btn-light px-3" data-bs-dismiss="modal">
                    <i class="fas fa-times me-1"></i>Cancelar
                </button>
                <button type="button" class="btn btn-sm btn-primary px-4" id="mpac-btn-guardar" onclick="mpacGuardar()">
                    <i class="fas fa-save me-1"></i>Guardar paciente
                </button>
            </div>
        </div>
    </div>
</div>

<div class="rec-toast" id="rec-toast">
    <span class="ico" id="toast-ico"><i class="fas fa-check-circle"></i></span>
    <span id="toast-msg"></span>
</div>

<script>
// ── Estado ────────────────────────────────────────────────────
let turnoActivo     = null;
let pacienteActivo  = null;
let solicitudActiva = null;
let consentimientos = [];
let pollingColaId   = null;

const API     = '<?= BASE_URL ?>modules/turnero/api/';
const API_PAC = '<?= BASE_URL ?>api/lab/get_pacientes.php';
const BASE_WA = '<?= BASE_URL ?>';
const DESK_ID     = <?= $deskId ?: 'null' ?>;
const DESK_NOMBRE = '<?= addslashes($deskNombre ?? 'Recepción') ?>';

// ── Arranque ──────────────────────────────────────────────────
let pollingConsentimientosId = null;

document.addEventListener('DOMContentLoaded', () => {
    cargarCola();
    pollingColaId = setInterval(cargarCola, 3000);
    document.getElementById('inp-buscar-pac')
        .addEventListener('keydown', e => { if (e.key === 'Enter') buscarPaciente(); });
    document.getElementById('sel-lugar')
        .addEventListener('change', onLugarChange);
    // Refrescar consentimientos al volver a la pestaña (firma en otra pestaña)
    document.addEventListener('visibilitychange', () => {
        if (!document.hidden && turnoActivo) refrescarConsentimientosLugar();
    });
});

// ── Polling automático de consentimientos cuando hay uno abierto ──
async function refrescarConsentimientosLugar() {
    if (!turnoActivo) return;
    try {
        const res = await fetch(`${API}get_consentimientos.php?turno_id=${turnoActivo.id}`);
        const json = await res.json();
        if (json.ok && json.consentimientos) {
            consentimientos = json.consentimientos;
            renderConsentimientos(consentimientos);
        }
    } catch (_) {}
}
// ── Formularios del lugar (aparecen al seleccionar lugar) ────
// El dropdown sel-lugar es solo para elegir destino del paciente.
// Los consentimientos del desk se cargan via cargarConsentimientosDesk() y no dependen de este cambio.
function onLugarChange() {}
async function abrirFormularioLugar(formularioId, nombre) {
    if (!turnoActivo) { mostrarError('Llama un turno primero.'); return; }
    if (!pacienteActivo) { mostrarError('Vincula el paciente antes de abrir el consentimiento.'); return; }

    try {
        const res = await fetch(API + 'create_consent_token.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: formularioId, paciente_id: pacienteActivo?.id || null }),
        });
        const json = await res.json();
        if (json.ok && (json.data?.url || json.url)) {
            window.open(json.data?.url || json.url, '_blank');
            // Polling automático para detectar la firma
            if (!pollingConsentimientosId) {
                pollingConsentimientosId = setInterval(refrescarConsentimientosLugar, 3000);
            }
        } else {
            mostrarError(json.error || 'No se pudo generar el enlace de firma.');
        }
    } catch (err) {
        mostrarError('Error al generar enlace: ' + err.message);
    }
}

// ── Cola ──────────────────────────────────────────────────────
async function cargarCola() {
    try {
        const res  = await fetch(API + 'get_cola.php?area=recepcion');
        const json = await res.json();
        if (!json.ok) return;
        renderCola(json);
    } catch (_) {}
}

function renderCola(snap) {
    const lista    = document.getElementById('cola-items');
    const todos    = snap.cola || [];
    const badge    = document.getElementById('badge-count');

    // Filtrar: 'espera' todos; 'en_recepcion' solo los de este escritorio
    const visibles = todos.filter(t =>
        t.estado === 'espera' ||
        (t.estado === 'en_recepcion' && (t.recepcion_desk_id === null || t.recepcion_desk_id == DESK_ID))
    );
    badge.textContent = visibles.length;

    if (visibles.length === 0) {
        lista.innerHTML = `<div class="cola-vacia">
            <i class="fas fa-hourglass-start fa-2x mb-2 d-block"></i>Cola vacía</div>`;
        return;
    }
    lista.innerHTML = visibles.map(t => `
        <div class="cola-card ${turnoActivo?.id === t.id ? 'activo' : ''}" data-id="${t.id}">
            <div class="prio-dot" style="background:${t.prioridad_color};cursor:pointer" onclick="seleccionarTurno(${t.id})">${t.prioridad_codigo}</div>
            <div class="turno-info" style="cursor:pointer" onclick="seleccionarTurno(${t.id})">
                <div class="cod">${escHtml(t.codigo)}</div>
                <div class="pac">${escHtml(t.paciente_nombre || 'Sin nombre')}</div>
            </div>
            <button onclick="llamarTurnoEspecifico(${t.id}, '${t.estado}')"
                    title="${t.estado === 'en_recepcion' ? 'Re-llamar este turno' : 'Llamar este turno ahora'}"
                    style="flex-shrink:0;background:#2563eb;border:none;color:#fff;
                           border-radius:7px;padding:5px 9px;font-size:.78rem;cursor:pointer">
                <i class="fas ${t.estado === 'en_recepcion' ? 'fa-volume-up' : 'fa-bell'}"></i>
            </button>
        </div>`).join('');
}

// ── Llamar siguiente ──────────────────────────────────────────
async function llamarSiguiente() {
    const btn = document.getElementById('btn-llamar');
    btn.disabled = true;
    mostrarToast('Consultando siguiente turno…', 'info', 1500);
    try {
        const res  = await fetch(API + 'llamar_turno.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ area: 'recepcion', desk_id: DESK_ID }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }

        const turnoLlamado = json.turno ?? json.data?.turno;
        if (!turnoLlamado) {
            mostrarAviso('Cola vacía', 'No hay turnos en espera.');
            resetPlaceholder();
            return;
        }
        mostrarLlamando(turnoLlamado.codigo);
        abrirFicha(turnoLlamado);
        cargarCola();
    } catch (err) {
        mostrarError(err.message);
    } finally {
        btn.disabled = false;
    }
}

// ── Seleccionar turno de la cola (ver ficha sin cambiar estado) ─────
async function seleccionarTurno(turnoId) {
    try {
        const res  = await fetch(API + 'get_turno.php?id=' + turnoId);
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error || 'No se pudo cargar el turno'); return; }
        abrirFicha(json.turno ?? json.data?.turno);
    } catch (err) {
        mostrarError('Error al cargar turno: ' + err.message);
    }
}

// ── Llamar turno específico (cambia estado → en_recepcion) ─────────
async function llamarTurnoEspecifico(turnoId, estadoActual) {
    // Mostrar feedback inmediato
    const card = document.querySelector(`.cola-card[data-id="${turnoId}"]`);
    if (card) {
        const cod = card.querySelector('.cod')?.textContent || '';
        mostrarLlamando(cod);
    }
    // Si ya está en recepción: re-llamar (actualiza llamado_at para que la pantalla TV reactive)
    if (estadoActual === 'en_recepcion') {
        try {
            const res  = await fetch(API + 'rellamar.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ turno_id: turnoId, desk_id: DESK_ID }),
            });
            const json = await res.json();
            if (json.ok && json.turno) { abrirFicha(json.turno); return; }
        } catch (_) {}
        // Fallback: solo abrir ficha
        seleccionarTurno(turnoId);
        return;
    }
    try {
        const res  = await fetch(API + 'cambiar_estado.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoId, nuevo_estado: 'en_recepcion' }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        abrirFicha(json.turno);
        cargarCola();
    } catch (err) {
        mostrarError('Error al llamar turno: ' + err.message);
    }
}

// ── Re-llamar desde la ficha ────────────────────────────────
async function rellamarActivo() {
    if (!turnoActivo) return;
    mostrarLlamando(turnoActivo.codigo);
    try {
        await fetch(API + 'rellamar.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, desk_id: DESK_ID }),
        });
    } catch (_) {}
}

// ── Abrir ficha ───────────────────────────────────────────────
async function cargarConsecutivo() {
    const inp = document.getElementById('inp-consecutivo');
    if (!inp) return;
    inp.value = '…';
    try {
        const r = await fetch(API + 'get_consecutivo.php');
        const d = await r.json();
        if (d.ok) inp.value = d.consecutivo;
    } catch(_) { inp.value = ''; }
}
function recargarConsecutivo() { cargarConsecutivo(); }

function abrirFicha(turno) {
    turnoActivo     = turno;
    pacienteActivo  = null;
    solicitudActiva = null;

    document.getElementById('ficha-placeholder').classList.add('d-none');
    document.getElementById('ficha-turno').classList.remove('d-none');

    cargarConsecutivo();

    // Datos del turno
    document.getElementById('ficha-codigo').textContent     = turno.codigo;
    document.getElementById('ficha-prio-nombre').textContent = turno.prioridad_nombre || '';
    const dot = document.getElementById('ficha-prio-dot');
    dot.textContent   = turno.prioridad_codigo || '—';
    dot.style.background = turno.prioridad_color || '#3b82f6';

    // Badge top
    document.getElementById('badge-turno-activo').classList.remove('d-none');
    document.getElementById('badge-codigo').textContent = turno.codigo;

    // Nombre del kiosko (valor capturado en kiosko)
    if (turno.paciente_nombre) {
        document.getElementById('bloque-nombre-kiosko').classList.remove('d-none');
        document.getElementById('lbl-nombre-kiosko').textContent = turno.paciente_nombre;
        document.getElementById('bloque-pac-kiosko').classList.add('d-none');
        document.getElementById('inp-buscar-pac').value = turno.paciente_nombre;
    }

    // Reset secciones
    resetCheckboxes();
    document.getElementById('sec-consentimientos').style.removeProperty('display');
    document.getElementById('sec-consentimientos').style.display = 'none';
    document.getElementById('btn-pasar-lugar').classList.add('d-none');
    document.getElementById('btn-enviar-consent').classList.add('d-none');
    document.getElementById('btn-guardar').classList.remove('d-none');
    document.getElementById('btn-guardar').disabled = false;
    desvincularPaciente();

    // Auto-vincular paciente si ya viene con ID desde el kiosko
    if (turno.paciente_id) {
        fetch(`${API_PAC}?id=${turno.paciente_id}`)
            .then(r => r.json())
            .then(json => {
                const data = (json.data || json.registros || [])[0];
                if (data && !pacienteActivo) seleccionarPaciente(data);
            })
            .catch(() => {});
    }

    // Cargar consentimientos del desk actual para este turno
    if (DESK_ID) cargarConsentimientosDesk(turno.id);
    mostrarFichaMobile();
}

// ── Cargar consentimientos del desk para el turno ─────────────
async function cargarConsentimientosDesk(turnoId) {
    const sec   = document.getElementById('sec-consentimientos');
    const lista = document.getElementById('lista-consentimientos');

    try {
        // 1. Si el turno ya tiene registros creados, mostrarlos con su estado real
        const resExist = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}`);
        const jsonExist = await resExist.json();
        if (jsonExist.ok && jsonExist.consentimientos?.length) {
            consentimientos = jsonExist.consentimientos.map(c => ({
                ...c,
                formulario_nombre: c.formulario_nombre || c.nombre,
            }));
            renderConsentimientos(consentimientos);
            sec.style.display = '';
            return;
        }

        // 2. Aún no existen registros: mostrar los configurados para el desk como pendientes
        const resDesk = await fetch(`${API}get_lugar_formularios.php?lugar_id=${DESK_ID}`);
        const jsonDesk = await resDesk.json();
        if (!jsonDesk.ok || !jsonDesk.formularios?.length) {
            sec.style.display = 'none';
            return;
        }

        lista.innerHTML = jsonDesk.formularios.map(f => {
            const nom = escHtml(f.nombre);
            return `<div class="consent-item pendiente">
                <i class="fas fa-file-signature"></i>
                <span class="c-nom">${nom}</span>
                <span class="c-badge">Pendiente</span>
                <div class="consent-acciones">
                    <button class="btn btn-outline-primary"
                            onclick="abrirFormularioLugar(${f.id}, '${nom.replace(/'/g, "\\'")}')"
                            title="Abrir formulario en nueva pestaña">
                        <i class="fas fa-external-link-alt"></i> Firmar
                    </button>
                </div>
            </div>`;
        }).join('');
        sec.style.display = '';
    } catch (_) {
        sec.style.display = 'none';
    }
}

// ── Buscador de paciente ──────────────────────────────────────
async function buscarPaciente() {
    const q = document.getElementById('inp-buscar-pac').value.trim();
    if (q.length < 2) return;
    try {
        const res  = await fetch(`${API_PAC}?busqueda=${encodeURIComponent(q)}&limit=8`);
        const json = await res.json();
        const lista = document.getElementById('lista-pacientes-res');
        const datos = json.data || json.registros || [];
        if (!datos.length) {
            lista.innerHTML = `<div class="text-muted small mt-1">Sin resultados.
                <a href="#" onclick="abrirModalPaciente(null,'${escHtml(q).replace(/'/g,"\\'")}');return false">Crear nuevo</a></div>`;
            return;
        }
        lista.innerHTML = datos.map(p => `
            <div class="pac-resultado" onclick="seleccionarPaciente(${JSON.stringify(p).replace(/"/g,'&quot;')})">
                <div class="pac-nombre">${escHtml(p.nombre_completo||p.full_name||p.nombre||'')}</div>
                <div class="pac-doc">${escHtml(p.tipo_documento||'')} ${escHtml(p.documento||p.numero_documento||'')}
                    ${p.telefono||p.celular ? '· ' + escHtml(p.telefono||p.celular) : ''}</div>
            </div>`).join('');
    } catch (_) {}
}

function seleccionarPaciente(pac) {
    pacienteActivo = pac;
    // Persistir vínculo en BD para que create_consent_token pueda verificar paciente_id
    if (turnoActivo?.id && pac?.id) {
        fetch(API + 'vincular_paciente.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, paciente_id: pac.id }),
        }).catch(() => {});
    }
    document.getElementById('bloque-pac-no-vinculado').classList.add('d-none');
    document.getElementById('bloque-pac-seleccionado').classList.remove('d-none');
    const pacNombre = (pac.full_name || pac.nombre_completo || (pac.nombre||'') + ' ' + (pac.apellido||'')).trim();
    document.getElementById('lbl-pac-nombre').textContent = pacNombre;
    document.getElementById('lbl-pac-doc').textContent =
        (pac.tipo_documento||'') + ' ' + (pac.documento||pac.numero_documento||'');
    document.getElementById('lbl-pac-cel').textContent =
        pac.telefono || pac.celular || '';
    document.getElementById('lista-pacientes-res').innerHTML = '';
    // Mostrar nombre del paciente vinculado debajo del valor del kiosko
    if (!document.getElementById('bloque-nombre-kiosko').classList.contains('d-none')) {
        document.getElementById('lbl-pac-kiosko-nombre').textContent = pacNombre;
        document.getElementById('bloque-pac-kiosko').classList.remove('d-none');
    }

    // Mostrar historial del paciente
    const secHist = document.getElementById('sec-historial-pac');
    secHist.classList.remove('d-none');
    // Resetear estado colapsado
    document.getElementById('hist-pac-body').classList.add('d-none');
    document.getElementById('btn-hist-toggle').classList.remove('open');
    // Precargar en background (usuario decide si abre)
    _historialPacienteCargado = false;
    _historialPacienteId = pac.id;
}

function togglePagoCombinado() {
    const combinado = document.getElementById('sel-pago').value === 'combinado';
    document.getElementById('panel-combinado').classList.toggle('d-none', !combinado);
    const inp = document.getElementById('inp-total');
    inp.readOnly = combinado;
    inp.style.background = combinado ? '#e9ecef' : '';
    if (combinado) sumarCombinado();
}
function sumarCombinado() {
    const v = id => parseFloat(document.getElementById(id).value) || 0;
    const total = v('comb-efectivo') + v('comb-transferencia') + v('comb-tarjeta');
    document.getElementById('inp-total').value = total || '';
}
function resetPagoCombinado() {
    ['comb-efectivo','comb-transferencia','comb-tarjeta'].forEach(id => document.getElementById(id).value = '');
    document.getElementById('panel-combinado').classList.add('d-none');
    const inp = document.getElementById('inp-total');
    inp.readOnly = false;
    inp.style.background = '';
}

function desvincularPaciente() {
    pacienteActivo = null;
    _historialPacienteId = null;
    _historialPacienteCargado = false;
    document.getElementById('bloque-pac-no-vinculado').classList.remove('d-none');
    document.getElementById('bloque-pac-seleccionado').classList.add('d-none');
    document.getElementById('bloque-pac-kiosko').classList.add('d-none');
    document.getElementById('sec-historial-pac').classList.add('d-none');
    document.getElementById('hist-pac-body').classList.add('d-none');
    document.getElementById('btn-hist-toggle').classList.remove('open');
    document.getElementById('lista-pacientes-res').innerHTML = '';
    document.getElementById('inp-buscar-pac').value = '';
    document.getElementById('chk-embarazada').checked = false;
}

function cambiarPaciente() {
    desvincularPaciente();
    setTimeout(() => document.getElementById('inp-buscar-pac').focus(), 80);
}

// ── Historial del paciente ──────────────────────────────────────
let _historialPacienteId     = null;
let _historialPacienteCargado = false;

async function toggleHistorialPaciente() {
    const body = document.getElementById('hist-pac-body');
    const btn  = document.getElementById('btn-hist-toggle');
    const open = !body.classList.contains('d-none');
    body.classList.toggle('d-none', open);
    btn.classList.toggle('open', !open);
    if (!open && !_historialPacienteCargado && _historialPacienteId) {
        _historialPacienteCargado = true;
        await cargarHistorialPaciente(_historialPacienteId);
    }
}

async function cargarHistorialPaciente(pacienteId) {
    const content = document.getElementById('hist-pac-content');
    content.innerHTML = '<div class="text-center text-muted py-2 small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando historial…</div>';
    try {
        const res  = await fetch(`${API}get_historial.php?paciente_id=${pacienteId}&per_page=5&page=1`);
        const json = await res.json();
        if (!json.ok || !json.turnos || !json.turnos.length) {
            content.innerHTML = '<div class="text-center text-muted py-3 small"><i class="fas fa-inbox me-1"></i>Sin visitas anteriores registradas</div>';
            return;
        }
        content.innerHTML = renderHistorialTimeline(json.turnos, json.total);
    } catch(_) {
        content.innerHTML = '<div class="text-center text-danger py-2 small">Error al cargar historial</div>';
    }
}

function renderHistorialTimeline(turnos, total) {
    const ESTADO_LBL = {
        espera:'Espera', en_recepcion:'Recepción', en_espera_lugar:'Esp. lugar',
        en_servicio:'En servicio', finalizado:'Finalizado', ausente:'Ausente', cancelado:'Cancelado',
    };
    const ESTADO_STYLE = {
        finalizado:     'background:#f1f5f9;color:#334155',
        ausente:        'background:#fee2e2;color:#991b1b',
        cancelado:      'background:#f1f5f9;color:#9ca3af',
        en_servicio:    'background:#dcfce7;color:#166534',
        en_espera_lugar:'background:#fde68a;color:#92400e',
        en_recepcion:   'background:#dbeafe;color:#1e40af',
        espera:         'background:#fef9c3;color:#78350f',
    };
    const CONS_ICON = {
        pendiente: '📋', enviado: '📤', visto: '👁', firmado: '✅', rechazado: '❌'
    };
    const totalLabel = total > turnos.length ? `<div class="text-end px-3 pb-1" style="font-size:.67rem;color:#94a3b8">Mostrando ${turnos.length} de ${total} visitas</div>` : '';
    const items = turnos.map(t => {
        const color = t.prioridad_color || '#6366f1';
        const lugar = escHtml(t.lugar_nombre || 'Recepción');
        const fecha = t.fecha_sesion || '—';
        const est   = t.estado || '';
        const eStyle = ESTADO_STYLE[est] || 'background:#f1f5f9;color:#334155';
        const eLbl  = ESTADO_LBL[est] || est;
        const mins  = t.servicio_min != null ? `<span style="font-size:.65rem;color:#94a3b8;margin-left:4px">${t.servicio_min} min</span>` : '';

        // Exámenes
        let examStr = '';
        if (t.examenes && t.examenes.length) {
            examStr = `<div style="margin-top:6px;font-size:.75rem">
                <strong style="color:#64748b">Exámenes:</strong>
                <div style="color:#475569">${t.examenes.map(e => escHtml(e.nombre)).join(', ')}</div>
            </div>`;
        }

        // Comentarios
        let comStr = '';
        if (t.comentarios && t.comentarios.length) {
            comStr = `<div style="margin-top:6px;font-size:.72rem;border-top:1px solid #e2e8f0;padding-top:6px">
                <strong style="color:#64748b">📝 Últimos comentarios:</strong>
                <div style="color:#475569;margin-top:4px">${t.comentarios.map(c =>
                    `<div style="margin-bottom:3px"><strong>${escHtml(c.usuario_nombre)}</strong>: ${escHtml(c.comentario)}</div>`
                ).join('')}</div>
            </div>`;
        }

        return `<div class="timeline-item">
            <div class="timeline-dot" style="color:${color};background:${color}"></div>
            <div class="timeline-content">
                <div class="timeline-fecha">${escHtml(fecha)}</div>
                <div class="timeline-codigo" style="color:${color}">${escHtml(t.codigo)}</div>
                <div class="timeline-lugar">${lugar}</div>
                <span class="timeline-eb" style="${eStyle}">${escHtml(eLbl)}</span>${mins}
                ${examStr}${comStr}
            </div>
        </div>`;
    }).join('');
    return `<div class="pac-timeline">${items}</div>${totalLabel}`;
}

// ── Guardar solicitud ─────────────────────────────────────────
async function guardarSolicitud() {
    if (!turnoActivo) return;
    if (!pacienteActivo) { mostrarError('Seleccione un paciente antes de guardar.'); return; }

    const lugarId = parseInt(document.getElementById('sel-lugar').value);
    if (!lugarId) { mostrarError('Seleccione el lugar destino.'); return; }

    const soloMuestras = document.getElementById('chk-solo-muestras').checked;

    // ✅ VALIDACIÓN: verificar que los consentimientos del lugar estén firmados (omitir en solo muestras)
    if (!soloMuestras) {
        const consentPendientes = Array.from(document.querySelectorAll('.consent-item.pendiente, .consent-item.enviado, .consent-item.visto')).length;
        if (consentPendientes > 0) {
            mostrarError('⚠️ El paciente debe firmar los consentimientos del lugar antes de guardar la solicitud.');
            return;
        }
    }
    const examIds = Array.from(document.querySelectorAll('.exam-chk:checked')).map(c => parseInt(c.value));
    if (!soloMuestras && !examIds.length) { mostrarError('Seleccione al menos un examen.'); return; }

    const btn = document.getElementById('btn-guardar');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando…';

    try {
        const res  = await fetch(API + 'create_solicitud.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                turno_id:      turnoActivo.id,
                paciente_id:   pacienteActivo.id,
                lugar_id:      lugarId,
                exam_tipo_ids: examIds,
                numero_orden:  document.getElementById('inp-consecutivo').value.trim() || null,
                total_cobrado:  parseFloat(document.getElementById('inp-total').value) || null,
                metodo_pago:    document.getElementById('sel-pago').value || null,
                pagos_detalle:  document.getElementById('sel-pago').value === 'combinado' ? {
                    efectivo:      parseFloat(document.getElementById('comb-efectivo').value) || 0,
                    transferencia: parseFloat(document.getElementById('comb-transferencia').value) || 0,
                    tarjeta:       parseFloat(document.getElementById('comb-tarjeta').value) || 0,
                } : null,
                observaciones:  document.getElementById('inp-obs').value.trim() || null,
                embarazada:     document.getElementById('chk-embarazada').checked ? 1 : 0,
                solo_muestras:  soloMuestras ? 1 : 0,
                medico_id:      parseInt(document.getElementById('inp-medico-id').value) || null,
            }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }

        solicitudActiva = json.solicitud ?? json.data?.solicitud;
        consentimientos = json.consentimientos_requeridos ?? json.data?.consentimientos_requeridos ?? [];

        // Asegurar que turnoActivo tiene el estado correcto (en_recepcion)
        if (turnoActivo) turnoActivo.estado = 'en_recepcion';

        btn.innerHTML = '<i class="fas fa-check me-1"></i>Guardado';

        // Detener polling de consentimientos (ya se guardó)
        if (pollingConsentimientosId) {
            clearInterval(pollingConsentimientosId);
            pollingConsentimientosId = null;
        }

        // No mostrar consentimientos post-guardado aquí (ya vienen de create_solicitud)
        // Solo renderizar si vienen nuevos
        if (consentimientos && consentimientos.length > 0) {
            renderConsentimientos(consentimientos);
            document.getElementById('sec-consentimientos').style.display = '';
            document.getElementById('btn-enviar-consent').classList.remove('d-none');
        }

        document.getElementById('btn-pasar-lugar').classList.remove('d-none');
        document.getElementById('btn-guardar').classList.add('d-none');

    } catch (err) {
        mostrarError(err.message);
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-save me-1"></i>Guardar solicitud';
    }
}

// ── Labels / iconos para estados ─────────────────────────────
const CONSENT_META = {
    firmado   : { cls:'firmado',   ico:'fa-check-circle', lbl:'Firmado'   },
    enviado   : { cls:'enviado',   ico:'fa-envelope',     lbl:'Enviado'   },
    visto     : { cls:'visto',     ico:'fa-eye',          lbl:'Visto'     },
    rechazado : { cls:'rechazado', ico:'fa-ban',          lbl:'Rechazado' },
    pendiente : { cls:'pendiente', ico:'fa-clock',        lbl:'Pendiente' },
};

function renderConsentimientos(lista) {
    const el = document.getElementById('lista-consentimientos');
    if (!lista.length) {
        el.innerHTML = '<div class="text-muted small"><i class="fas fa-check-circle text-success me-1"></i>Sin consentimientos requeridos</div>';
        return;
    }
    el.innerHTML = lista.map(c => {
        const m   = CONSENT_META[c.estado] || CONSENT_META.pendiente;
        const ya  = ['firmado','rechazado'].includes(c.estado);
        const token = escHtml(c.token || '');
        const nom   = escHtml(c.formulario_nombre || 'Consentimiento');
        const fId   = c.formulario_id;
        const nomJs = (c.formulario_nombre || 'Consentimiento').replace(/'/g, "\\'");

        // Botón de firma paciente (solo si no está firmado/rechazado)
        const btnFirmar = (!ya)
            ? `<button class="btn btn-outline-primary" onclick="firmarConsentimiento(${fId}, '${nomJs}')"
                       title="Abrir firma en nueva pestaña">
                   <i class="fas fa-external-link-alt"></i> Firmar
               </button>` : '';

        // Botón ver/enviar WhatsApp
        const btnWa = ya
            ? (c.token ? `<a href="${BASE_WA}ver_formulario_enviado.php?token=${token}" target="_blank"
                   class="btn btn-outline-secondary" title="Ver formulario firmado">
                   <i class="fas fa-eye"></i> Ver
               </a>` : '')
            : `<button class="btn btn-outline-success" onclick="enviarConsentimientoUno(${c.turno_id || turnoActivo?.id})"
                       title="Enviar enlace de firma por WhatsApp">
                   <i class="fab fa-whatsapp"></i> WhatsApp
               </button>`;

        // Fila de firma del profesional (solo visible si el paciente ya firmó)
        let profRow = '';
        if (c.estado === 'firmado') {
            const tienePro = c.tiene_firma_profesional == 1 || c.tiene_firma_profesional === true;
            if (tienePro) {
                profRow = `<div class="consent-prof-row">
                    <i class="fas fa-user-nurse text-success"></i>
                    <span class="text-success">Firma enfermero</span>
                    <span class="badge bg-success ms-1">OK</span>
                </div>`;
            } else {
                profRow = `<div class="consent-prof-row">
                    <i class="fas fa-user-nurse text-warning"></i>
                    <span class="text-warning fw-semibold">Falta firma enfermero</span>
                    <button class="btn btn-warning btn-sm ms-auto" style="font-size:.7rem;padding:1px 7px"
                            onclick="abrirFirmaEnfermero(${fId}, '${nomJs}')">
                        <i class="fas fa-pen-nib me-1"></i>Firmar
                    </button>
                </div>`;
            }
        }

        return `<div class="consent-item ${m.cls}" style="flex-wrap:wrap">
            <div style="display:flex;align-items:center;gap:.5rem;width:100%">
                <i class="fas ${m.ico}"></i>
                <span class="c-nom">${nom}</span>
                <span class="c-badge">${m.lbl}</span>
                <div class="consent-acciones">${btnFirmar}${btnWa}</div>
            </div>
            ${profRow}
        </div>`;
    }).join('');
}

// ── Firma del enfermero: canvas modal ─────────────────────────
let _feFormularioId = null;
const feCanvas = {
    _el: null, _ctx: null, _drawing: false,
    init() {
        this._el  = document.getElementById('fe-canvas');
        this._ctx = this._el.getContext('2d');
        this._ctx.strokeStyle = '#1e293b';
        this._ctx.lineWidth   = 2;
        this._ctx.lineCap     = 'round';
        this._el.addEventListener('pointerdown', e => { this._drawing = true; this._ctx.beginPath(); this._move(e); });
        this._el.addEventListener('pointermove', e => { if (!this._drawing) return; this._ctx.lineTo(...this._pos(e)); this._ctx.stroke(); });
        ['pointerup','pointerleave'].forEach(ev => this._el.addEventListener(ev, () => { this._drawing = false; }));
    },
    _pos(e) { const r = this._el.getBoundingClientRect(); return [e.clientX - r.left, e.clientY - r.top]; },
    _move(e) { const [x,y] = this._pos(e); this._ctx.moveTo(x, y); },
    limpiar() { this._ctx.clearRect(0, 0, this._el.width, this._el.height); },
    vacio() {
        const d = this._ctx.getImageData(0, 0, this._el.width, this._el.height).data;
        return !d.some(v => v !== 0);
    },
    png() { return this._el.toDataURL('image/png'); },
};

function abrirFirmaEnfermero(formularioId, nombre) {
    if (!turnoActivo) { mostrarError('No hay turno activo.'); return; }
    _feFormularioId = formularioId;
    document.getElementById('fe-nombre-consentimiento').textContent = nombre;
    if (!feCanvas._el) feCanvas.init();
    feCanvas.limpiar();
    const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('modalFirmaEnfermero'));
    modal.show();
}

async function feGuardarFirma() {
    if (!turnoActivo || !_feFormularioId) return;
    if (feCanvas.vacio()) { mostrarError('Dibuja la firma antes de guardar.'); return; }
    const png = feCanvas.png();
    const btn = document.querySelector('#modalFirmaEnfermero .btn-primary');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando…';
    try {
        const res  = await fetch(API + 'firmar_profesional_consentimiento.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: _feFormularioId, svg: png }),
        });
        const json = await res.json();
        if (json.ok) {
            bootstrap.Modal.getOrCreateInstance(document.getElementById('modalFirmaEnfermero')).hide();
            mostrarToast('Firma del enfermero guardada', 'success');
            await refrescarConsentimientosLugar();
        } else {
            mostrarError(json.error || 'No se pudo guardar la firma.');
        }
    } catch(e) {
        mostrarError('Error al guardar: ' + e.message);
    } finally {
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-check me-1"></i>Guardar firma';
    }
}

// ── Firmar en nueva pestaña ──────────────────────────────────
async function firmarConsentimiento(formularioId, nombre) {
    if (!turnoActivo) { mostrarError('No hay turno activo.'); return; }
    try {
        const res = await fetch(API + 'create_consent_token.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: formularioId, paciente_id: pacienteActivo?.id || null }),
        });
        const json = await res.json();
        if (json.ok && (json.url || json.data?.url)) {
            window.open(json.url || json.data.url, '_blank');
            // Iniciar polling automático para detectar firma
            if (!pollingConsentimientosId) {
                pollingConsentimientosId = setInterval(() => {
                    refrescarConsentimientosLugar();
                }, 3000);
            }
        } else {
            mostrarError(json.error || 'No se pudo crear el token de firma');
        }
    } catch (err) {
        mostrarError('Error al abrir firma: ' + err.message);
    }
}
function verFirmado(token) {
    window.open(BASE_WA + 'ver_formulario_enviado.php?token=' + encodeURIComponent(token), '_blank');
}

// ── Refrescar estado de consentimientos ───────────────────────
async function refrescarConsentimientos(turnoId) {
    try {
        const res  = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (json.ok) {
            consentimientos = json.consentimientos || [];
            renderConsentimientos(consentimientos);
        }
    } catch(_) {}
}

// ── Enviar consentimientos (todos) ───────────────────────────
async function enviarConsentimientosTodos() {
    if (!turnoActivo || !solicitudActiva) return;
    const btn = document.getElementById('btn-reenviar-consent');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Enviando…';
    try {
        const res  = await fetch(API + 'send_consentimiento.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        consentimientos = json.consentimientos ?? consentimientos;
        renderConsentimientos(consentimientos);
        btn.innerHTML = '<i class="fas fa-check me-1"></i>Enviado';
        setTimeout(() => { btn.innerHTML = '<i class="fas fa-paper-plane me-1"></i>Enviar todos'; }, 3000);
    } catch (err) {
        mostrarError(err.message);
        btn.innerHTML = '<i class="fas fa-paper-plane me-1"></i>Enviar todos';
    } finally {
        btn.disabled = false;
    }
}

// ── Enviar consentimiento individual ─────────────────────────
async function enviarConsentimientoUno(turnoId) {
    if (!turnoId) return;
    try {
        const res  = await fetch(API + 'send_consentimiento.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoId }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        consentimientos = json.consentimientos ?? consentimientos;
        renderConsentimientos(consentimientos);
    } catch (err) {
        mostrarError(err.message);
    }
}

// ── Enviar consentimientos (legacy — usado por btn-enviar-consent) ──
async function enviarConsentimientos() { return enviarConsentimientosTodos(); }

// ── Pasar a lugar ─────────────────────────────────────────────
async function pasarALugar() {
    if (!turnoActivo || !solicitudActiva) return;

    const btn = document.getElementById('btn-pasar-lugar');
    btn.disabled = true;

    try {
        const res  = await fetch(API + 'cambiar_estado.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                turno_id:     turnoActivo.id,
                nuevo_estado: 'en_espera_lugar',
                lugar_id:     solicitudActiva.lugar_id,
            }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); btn.disabled = false; return; }

        // Reiniciar ficha
        turnoActivo     = null;
        solicitudActiva = null;
        document.getElementById('ficha-turno').classList.add('d-none');
        document.getElementById('badge-turno-activo').classList.add('d-none');

        mostrarToast('Turno pasado al lugar.', 'success', 2000);

        setTimeout(() => {
            cargarCola();
            resetPlaceholder();
        }, 500);

    } catch (err) {
        mostrarError(err.message);
        btn.disabled = false;
    }
}

// ── Ausente ───────────────────────────────────────────────────
async function marcarAusente() {
    if (!turnoActivo) return;
    if (!confirm(`¿Marcar turno ${turnoActivo.codigo} como AUSENTE?`)) return;

    await fetch(API + 'cambiar_estado.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ turno_id: turnoActivo.id, nuevo_estado: 'ausente' }),
    });

    turnoActivo = null;
    solicitudActiva = null;
    document.getElementById('ficha-turno').classList.add('d-none');
    document.getElementById('ficha-placeholder').classList.remove('d-none');
    document.getElementById('badge-turno-activo').classList.add('d-none');
    cargarCola();
    volverACola();
}

// ── Soltar turno ──────────────────────────────────────────────
async function soltarTurno() {
    if (!turnoActivo) return;
    if (!confirm(`¿Soltar turno ${turnoActivo.codigo}? Otro escritorio podrá llamarlo.`)) return;

    await fetch(API + 'cambiar_estado.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ turno_id: turnoActivo.id, nuevo_estado: 'espera' }),
    });

    turnoActivo = null;
    solicitudActiva = null;
    document.getElementById('ficha-turno').classList.add('d-none');
    document.getElementById('ficha-placeholder').classList.remove('d-none');
    document.getElementById('badge-turno-activo').classList.add('d-none');
    mostrarToast('Turno liberado', 'success');
    cargarCola();
    volverACola();
}

// ── Helpers ───────────────────────────────────────────────────
// ── Médico tratante ─────────────────────────────────────────────
let _medicoTimer = null;
const API_MEDICOS = '<?= BASE_URL ?>modules/medicos/api/list.php';

function buscarMedico() {
    clearTimeout(_medicoTimer);
    const q = document.getElementById('inp-buscar-medico').value.trim();
    const ul = document.getElementById('medico-resultados');
    if (q.length < 2) { ul.classList.add('d-none'); ul.innerHTML = ''; return; }
    _medicoTimer = setTimeout(async () => {
        const res  = await fetch(API_MEDICOS + '?q=' + encodeURIComponent(q));
        const json = await res.json();
        const rows = (json.data || []).slice(0, 8);
        if (!rows.length) { ul.innerHTML = '<li class="px-3 py-2 text-muted small">Sin resultados</li>'; ul.classList.remove('d-none'); return; }
        ul.innerHTML = rows.map(m =>
            `<li class="px-3 py-2 small" style="cursor:pointer;border-bottom:1px solid #f1f5f9"
                 onmousedown="seleccionarMedico(${m.id},'${escJs(m.codigo)}','${escJs(m.nombres)} ${escJs(m.apellidos)}','${escJs(m.cod_especialidad||'')}')">
                <span class="fw-semibold">${esc(m.nombres)} ${esc(m.apellidos)}</span>
                <span class="text-muted ms-1">[${esc(m.codigo)}]</span>
                ${m.cod_especialidad ? `<span class="badge text-bg-light ms-1" style="font-size:.7rem">${esc(m.cod_especialidad)}</span>` : ''}
             </li>`
        ).join('');
        ul.classList.remove('d-none');
    }, 250);
}

function seleccionarMedico(id, codigo, nombre, esp) {
    document.getElementById('inp-medico-id').value = id;
    document.getElementById('medico-badge-txt').textContent = nombre + (esp ? ' · ' + esp : '') + ' [' + codigo + ']';
    document.getElementById('medico-seleccionado').classList.remove('d-none');
    document.getElementById('medico-buscador').classList.add('d-none');
    document.getElementById('medico-resultados').classList.add('d-none');
}

function quitarMedico() {
    document.getElementById('inp-medico-id').value = '';
    document.getElementById('medico-seleccionado').classList.add('d-none');
    document.getElementById('medico-buscador').classList.remove('d-none');
    document.getElementById('inp-buscar-medico').value = '';
}

function resetMedico() {
    quitarMedico();
}

function escJs(s) { return String(s||'').replace(/\\/g,'\\\\').replace(/'/g,"\\'"); }

function toggleSoloMuestras() {
    const solo = document.getElementById('chk-solo-muestras').checked;
    document.querySelectorAll('.exam-chk').forEach(c => { c.checked = false; c.disabled = solo; });
    document.getElementById('lista-examenes').style.opacity = solo ? '0.4' : '';
}

function resetCheckboxes() {
    document.getElementById('chk-solo-muestras').checked = false;
    document.querySelectorAll('.exam-chk').forEach(c => { c.checked = false; c.disabled = false; });
    document.getElementById('lista-examenes').style.opacity = '';
    document.getElementById('sel-pago').value = '';
    document.getElementById('inp-total').value = '';
    document.getElementById('inp-obs').value = '';
    resetPagoCombinado();
    resetMedico();
}
function toggleTodosExamenes(val) {
    document.querySelectorAll('.exam-chk').forEach(c => c.checked = val);
}

function escHtml(str) {
    const d = document.createElement('div');
    d.appendChild(document.createTextNode(String(str)));
    return d.innerHTML;
}
const esc = escHtml;

function resetPlaceholder() {
    const ph = document.getElementById('ficha-placeholder');
    ph.innerHTML = `
        <i class="fas fa-ticket-alt fa-3x mb-3" style="color:#cbd5e1"></i>
        <p class="mb-0 fw-semibold">Sin turno activo</p>
        <small class="text-muted">Haga clic en "Llamar siguiente" o en <i class="fas fa-bell"></i> de un turno de la cola</small>`;
    volverACola();
}

function esMobile() { return window.innerWidth <= 900; }
function mostrarFichaMobile() {
    if (!esMobile()) return;
    document.getElementById('rec-ficha').classList.add('mobile-visible');
    document.querySelector('.rec-cola').classList.add('mobile-oculta');
}
function volverACola() {
    document.getElementById('rec-ficha').classList.remove('mobile-visible');
    document.querySelector('.rec-cola').classList.remove('mobile-oculta');
}

function mostrarError(msg) {
    mostrarToast(msg, 'error', 4000);
}
function mostrarAviso(titulo, msg) {
    mostrarToast(titulo + ': ' + msg, 'warn', 3500);
}
function mostrarLlamando(codigo) {
    mostrarToast('Llamando turno ' + codigo + '…', 'info', 2000);
}

/* ── Ocupación exclusiva del escritorio ──────────────────────── */
(function(_ID, _NOMBRE, _VIEW, _PARAM) {
    if (!_ID) return;

    function _e(s) {
        const d = document.createElement('div');
        d.appendChild(document.createTextNode(String(s ?? '')));
        return d.innerHTML;
    }
    function _post(body) {
        return fetch(API + 'ocupar_lugar.php', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(Object.assign({ lugar_id: _ID }, body)),
        }).then(r => r.json());
    }
    function _redirigirSiguiente(disponibles) {
        if (disponibles && disponibles.length) {
            window.location.href = BASE_WA + 'erp.php?m=turnero&v=' + _VIEW + '&' + _PARAM + '=' + disponibles[0].id;
        } else {
            window.location.href = BASE_WA + 'erp.php?m=turnero';
        }
    }

    /* Pantalla de bloqueo */
    function _mostrarBloqueado(ocupadoPor) {
        document.body.innerHTML =
            '<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;' +
            'min-height:100vh;background:#f8faff;font-family:sans-serif;gap:14px;text-align:center;padding:28px">' +
            '<div style="font-size:4rem">🔒</div>' +
            '<h2 style="color:#1565c0;margin:0">' + _e(_NOMBRE) + ' está abierta en otro equipo</h2>' +
            '<p style="color:#555;font-size:1.05rem;max-width:440px;line-height:1.6">' +
            'Actualmente usada por <strong>' + _e(ocupadoPor) + '</strong>.<br>' +
            'Puedes solicitar que cierre su sesión o ir al siguiente escritorio disponible.</p>' +
            '<div style="display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-top:4px">' +
            '<button id="_btn-solicitar" onclick="window._ocToma()" ' +
            'style="padding:12px 26px;background:#1565c0;color:#fff;border:none;border-radius:8px;font-size:1rem;cursor:pointer;font-weight:600">' +
            '📢 Solicitar cierre en ese equipo</button>' +
            '<button id="_btn-siguiente" onclick="window._ocSiguiente()" ' +
            'style="padding:12px 26px;background:#f0f4ff;color:#1565c0;border:2px solid #1565c0;border-radius:8px;font-size:1rem;cursor:pointer;font-weight:600">' +
            '➡ Ir al siguiente disponible</button>' +
            '</div>' +
            '<div id="_oc-estado" style="min-height:24px;color:#777;font-size:.95rem;margin-top:4px"></div>' +
            '</div>';
    }
    function _setEstado(msg, color) {
        const el = document.getElementById('_oc-estado');
        if (el) el.innerHTML = '<span style="color:' + (color||'#555') + '">' + msg + '</span>';
    }

    /* Solicitar toma de control */
    let _checkTransferTimer = null;
    window._ocToma = async function() {
        const btn = document.getElementById('_btn-solicitar');
        if (btn) btn.disabled = true;
        _setEstado('Enviando solicitud…', '#555');
        try {
            const j = await _post({ action: 'solicitar' });
            if (!j.ok) { _setEstado('Error al enviar solicitud.', '#c62828'); if (btn) btn.disabled = false; return; }
            if (j.transferido) { location.reload(); return; }
            _setEstado('✉ Solicitud enviada. El otro equipo tiene 5 segundos para responder…', '#1565c0');
            clearInterval(_checkTransferTimer);
            _checkTransferTimer = setInterval(async () => {
                try {
                    const r = await _post({ action: 'check_transfer' });
                    if (r.disponible) {
                        clearInterval(_checkTransferTimer);
                        _setEstado('✅ Escritorio liberado. Tomando control…', '#2e7d32');
                        const rc = await _post({ action: 'claim' });
                        if (rc.disponible) location.reload();
                        else _setEstado('No se pudo tomar el control. Recargue la página.', '#c62828');
                    } else if (r.denegado) {
                        clearInterval(_checkTransferTimer);
                        _setEstado('❌ La solicitud fue denegada.', '#c62828');
                        if (btn) { btn.disabled = false; btn.textContent = '📢 Volver a solicitar'; }
                    }
                } catch(_) {}
            }, 1500);
        } catch(e) {
            _setEstado('Error de red: ' + e.message, '#c62828');
            if (btn) btn.disabled = false;
        }
    };

    /* Ir al siguiente disponible */
    window._ocSiguiente = async function() {
        const btn = document.getElementById('_btn-siguiente');
        if (btn) btn.disabled = true;
        _setEstado('Buscando escritorio disponible…', '#555');
        try {
            const j = await _post({ action: 'disponibles' });
            if (!j.ok || !j.disponibles.length) {
                _setEstado('No hay otros escritorios disponibles.', '#c62828');
                if (btn) btn.disabled = false;
                return;
            }
            _redirigirSiguiente(j.disponibles);
        } catch(e) {
            _setEstado('Error de red.', '#c62828');
            if (btn) btn.disabled = false;
        }
    };

    /* Modal de solicitud entrante (para el ocupante actual) */
    let _modalActivo = false;
    function _mostrarModalSolicitud(solicitante) {
        if (_modalActivo) return;
        _modalActivo = true;
        const modal = document.createElement('div');
        modal.style.cssText =
            'position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:99999;display:flex;align-items:center;justify-content:center';
        modal.innerHTML =
            '<div style="background:#fff;border-radius:14px;padding:32px 28px;max-width:420px;width:92%;text-align:center;box-shadow:0 8px 32px rgba(0,0,0,.25)">' +
            '<div style="font-size:2.5rem">⚠️</div>' +
            '<h3 style="color:#c62828;margin:10px 0 6px">Solicitud de transferencia</h3>' +
            '<p style="color:#333;margin:0 0 6px"><strong>' + _e(solicitante) + '</strong> quiere usar este escritorio.</p>' +
            '<p style="color:#555;font-size:.95rem">Si no responde, se cerrará automáticamente en <strong id="_sol-cnt">5</strong> segundos.</p>' +
            '<div style="display:flex;gap:10px;justify-content:center;margin-top:18px">' +
            '<button id="_sol-aceptar" style="padding:10px 22px;background:#c62828;color:#fff;border:none;border-radius:8px;font-size:1rem;cursor:pointer;font-weight:600">Aceptar y ceder</button>' +
            '<button id="_sol-denegar" style="padding:10px 22px;background:#f5f5f5;color:#333;border:1px solid #ccc;border-radius:8px;font-size:1rem;cursor:pointer">Denegar</button>' +
            '</div></div>';
        document.body.appendChild(modal);

        let secs = 5;
        const tick = setInterval(() => {
            secs--;
            const el = document.getElementById('_sol-cnt');
            if (el) el.textContent = secs;
            if (secs <= 0) { clearInterval(tick); _liberar(); }
        }, 1000);

        async function _liberar() {
            modal.remove();
            await _post({ action: 'aceptar' }).catch(() => {});
            try {
                const j = await _post({ action: 'disponibles' });
                _redirigirSiguiente(j.disponibles || []);
            } catch(_) {
                window.location.href = BASE_WA + 'erp.php?m=turnero';
            }
        }

        document.getElementById('_sol-aceptar').onclick = () => { clearInterval(tick); _liberar(); };
        document.getElementById('_sol-denegar').onclick = async () => {
            clearInterval(tick);
            modal.remove();
            _modalActivo = false;
            await _post({ action: 'denegar' }).catch(() => {});
        };
    }

    /* Arranque */
    async function _iniciar() {
        try {
            const j = await _post({ action: 'claim' });
            if (!j.ok) return;
            if (!j.disponible) { _mostrarBloqueado(j.ocupado_por); return; }
            // Heartbeat cada 60 s
            setInterval(() => _post({ action: 'ping' }).catch(() => {}), 60000);
            // Polling de solicitudes entrantes cada 2 s
            setInterval(async () => {
                if (_modalActivo) return;
                try {
                    const r = await _post({ action: 'check_solicitud' });
                    if (r.hay_solicitud) _mostrarModalSolicitud(r.solicitante);
                } catch(_) {}
            }, 2000);
        } catch(_) {}
    }

    window.addEventListener('beforeunload', () => {
        navigator.sendBeacon(API + 'ocupar_lugar.php',
            new Blob([JSON.stringify({ lugar_id: _ID, action: 'release' })], { type: 'application/json' }));
    });

    _iniciar();
})(DESK_ID, DESK_NOMBRE, 'recepcion', 'desk_id');

// ── Modal paciente (crear / ver / editar) ────────────────────
const _mpacModal = () => bootstrap.Modal.getOrCreateInstance(document.getElementById('modalPacienteRec'));

function mpacAvatar(nombre) {
    const parts = nombre.trim().split(/\s+/).filter(Boolean);
    document.getElementById('mpac-avatar').textContent = parts.length >= 2
        ? (parts[0][0] + parts[1][0]).toUpperCase()
        : (parts[0]?.[0] || '?').toUpperCase();
}

async function abrirModalPaciente(id, nombrePrefill) {
    // Reset form
    document.getElementById('form-paciente-rec').reset();
    document.getElementById('mpac-id').value   = '';
    document.getElementById('mpac-avatar').textContent = '?';
    document.getElementById('mpac-wa-badge').innerHTML = '';
    document.getElementById('mpac-user-id').value = '';
    document.getElementById('mpac-ciudad').value  = 'Cúcuta';

    if (id) {
        document.getElementById('mpac-titulo').textContent    = 'Cargando…';
        document.getElementById('mpac-subtitulo').textContent = '';
        _mpacModal().show();
        try {
            const r = await fetch(`${API_PAC}?id=${id}`);
            const d = await r.json();
            const p = (d.data || d.registros || [])[0];
            if (!p) { mostrarError('No se pudo cargar el paciente.'); return; }
            mpacRellenar(p);
        } catch (_) { mostrarError('Error al cargar paciente.'); }
    } else {
        document.getElementById('mpac-titulo').textContent    = 'Nuevo Paciente';
        document.getElementById('mpac-subtitulo').textContent = 'Completa los datos del paciente';
        if (nombrePrefill) {
            document.getElementById('mpac-nombre').value = nombrePrefill;
            mpacAvatar(nombrePrefill);
        }
        _mpacModal().show();
        setTimeout(() => document.getElementById('mpac-nombre').focus(), 300);
    }
}

function mpacRellenar(p) {
    document.getElementById('mpac-id').value       = p.id;
    document.getElementById('mpac-nombre').value   = p.nombre_completo || '';
    document.getElementById('mpac-doc').value      = p.numero_documento || '';
    document.getElementById('mpac-tipo-doc').value = p.tipo_documento || 'CC';
    document.getElementById('mpac-fnac').value     = (p.fecha_nacimiento || '').slice(0, 10);
    document.getElementById('mpac-email').value    = p.email || '';
    document.getElementById('mpac-genero').value   = p.genero || '';
    document.getElementById('mpac-eps').value      = p.eps || '';
    document.getElementById('mpac-ciudad').value   = p.ciudad || 'Cúcuta';
    document.getElementById('mpac-barrio').value   = p.barrio || '';
    document.getElementById('mpac-dir').value      = p.direccion || '';
    document.getElementById('mpac-notas').value    = p.notas_admin || '';

    // Teléfono con prefijo
    let tel = p.telefono || '';
    const prefijos = ['57','58','1'];
    let prefijo = '57';
    for (const pf of prefijos) {
        if (tel.startsWith(pf) && tel.length > pf.length) {
            prefijo = pf; tel = tel.slice(pf.length); break;
        }
    }
    document.getElementById('mpac-tel-prefijo').value = prefijo;
    document.getElementById('mpac-tel').value = tel;

    mpacAvatar(p.nombre_completo || '');
    document.getElementById('mpac-titulo').textContent    = 'Editar Paciente';
    document.getElementById('mpac-subtitulo').textContent = p.nombre_completo || '';
}

async function mpacVerificarWA() {
    const prefijo = document.getElementById('mpac-tel-prefijo').value || '57';
    let tel = (document.getElementById('mpac-tel').value || '').replace(/[^0-9]/g, '');
    if (tel.length === 10) tel = prefijo + tel;
    const badge = document.getElementById('mpac-wa-badge');
    if (!tel || tel.length < 10) { badge.innerHTML = ''; return; }
    badge.innerHTML = '<span class="text-muted"><i class="fas fa-spinner fa-spin me-1"></i>Verificando…</span>';
    try {
        const r = await fetch(`<?= BASE_URL ?>api/lab/check_whatsapp.php?phone=${encodeURIComponent(tel)}`);
        const d = await r.json();
        if (d.ok && d.found) {
            badge.innerHTML = '<span class="text-success"><i class="fab fa-whatsapp me-1"></i>Registrado en WhatsApp</span>';
            document.getElementById('mpac-user-id').value = d.user_id;
        } else {
            badge.innerHTML = '<span class="text-muted"><i class="fas fa-times-circle me-1"></i>Sin WhatsApp registrado</span>';
            document.getElementById('mpac-user-id').value = '';
        }
    } catch(_) { badge.innerHTML = ''; }
}

async function mpacGuardar() {
    const nombre = document.getElementById('mpac-nombre').value.trim();
    if (!nombre) { mostrarError('El nombre es obligatorio.'); return; }
    if (!/^[\p{L}\s'\-\.]+$/u.test(nombre)) {
        mostrarError('El nombre solo debe contener letras, tildes y espacios.'); return;
    }
    if (nombre.split(/\s+/).filter(Boolean).length < 2) {
        mostrarError('Ingresa nombre y apellido (mínimo 2 palabras).'); return;
    }

    const tipoDoc = document.getElementById('mpac-tipo-doc').value;
    const docVal  = document.getElementById('mpac-doc').value.trim();
    if (docVal && ['CC','TI','RC','CE'].includes(tipoDoc)) {
        const digits = docVal.replace(/[^0-9]/g, '');
        if (digits.length < 4 || digits.length > 12) {
            mostrarError('El documento debe tener entre 4 y 12 dígitos.'); return;
        }
    }

    const emailVal = document.getElementById('mpac-email').value.trim();
    if (emailVal && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailVal)) {
        mostrarError('El correo electrónico no es válido.'); return;
    }

    const prefijo = document.getElementById('mpac-tel-prefijo').value || '57';
    let tel = document.getElementById('mpac-tel').value.replace(/[^0-9]/g, '');
    if (tel.length === 10) tel = prefijo + tel;
    if (tel && prefijo === '57') {
        const sinPref = tel.replace(/^57/, '');
        if (!/^3\d{9}$/.test(sinPref)) {
            mostrarError('El celular colombiano debe comenzar por 3 y tener 10 dígitos.'); return;
        }
    }

    const id = document.getElementById('mpac-id').value;
    const datos = {
        nombre_completo:  nombre,
        tipo_documento:   tipoDoc,
        numero_documento: docVal || null,
        fecha_nacimiento: document.getElementById('mpac-fnac').value || null,
        telefono:         tel || null,
        email:            emailVal || null,
        genero:           document.getElementById('mpac-genero').value || null,
        eps:              document.getElementById('mpac-eps').value.trim() || null,
        ciudad:           document.getElementById('mpac-ciudad').value.trim() || null,
        barrio:           document.getElementById('mpac-barrio').value.trim() || null,
        direccion:        document.getElementById('mpac-dir').value.trim() || null,
        notas_admin:      document.getElementById('mpac-notas').value.trim() || null,
        user_id:          document.getElementById('mpac-user-id').value || null,
    };
    if (id) datos.id = parseInt(id);

    const btn = document.getElementById('mpac-btn-guardar');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando…';

    try {
        const r = await fetch('<?= BASE_URL ?>api/lab/save_paciente.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(datos),
        });
        const d = await r.json();

        if (!d.success && !d.ok) {
            mostrarError(d.error || 'Error al guardar el paciente.');
            return;
        }

        _mpacModal().hide();
        mostrarToast(d.message || 'Paciente guardado.', 'success');

        if (id) {
            // Edición: actualizar datos en pantalla si es el paciente activo
            if (pacienteActivo && pacienteActivo.id == id) {
                pacienteActivo.nombre_completo  = nombre;
                pacienteActivo.numero_documento = docVal;
                pacienteActivo.tipo_documento   = tipoDoc;
                pacienteActivo.telefono         = tel;
                document.getElementById('lbl-pac-nombre').textContent =
                    (pacienteActivo.full_name || nombre).trim();
                document.getElementById('lbl-pac-doc').textContent =
                    tipoDoc + ' ' + (docVal || '');
                document.getElementById('lbl-pac-cel').textContent = tel || '';
            }
        } else {
            // Creación: vincular al turno automáticamente
            const nuevoPac = {
                id: d.id || d.data?.id,
                nombre_completo: nombre,
                full_name: nombre,
                tipo_documento: tipoDoc,
                numero_documento: docVal,
                telefono: tel,
            };
            seleccionarPaciente(nuevoPac);
        }
    } catch (err) {
        mostrarError('Error de red: ' + err.message);
    } finally {
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-save me-1"></i>Guardar paciente';
    }
}

// ── Toast ────────────────────────────────────────────────────
let toastTimer = null;
function mostrarToast(msg, type = 'info', duration = 2500) {
    const el = document.getElementById('rec-toast');
    const ico = document.getElementById('toast-ico');
    const txt = document.getElementById('toast-msg');
    const icons = { success: 'fa-check-circle', info: 'fa-info-circle', warn: 'fa-exclamation-triangle', error: 'fa-times-circle' };
    el.className = 'rec-toast ' + type;
    ico.innerHTML = '<i class="fas ' + (icons[type] || icons.info) + '"></i>';
    txt.textContent = msg;
    el.classList.add('show');
    clearTimeout(toastTimer);
    toastTimer = setTimeout(() => el.classList.remove('show'), duration);
}
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="<?= defined('APP_URL') ? rtrim(APP_URL,'/') : '' ?>/assets/js/lab-sidebar.js"></script>
</body>
</html>
