<?php
/**
 * Puesto Lugar / Estación de Servicio — Módulo Turnero
 * Genérica: sirve para Toma de Muestras 1, 2, Rayos X, etc.
 */
require_once __DIR__ . '/../../../config/config.php';
if (!isUserLoggedIn()) {
    header('Location: ' . BASE_URL . 'login.php');
    exit;
}

require_once __DIR__ . '/../_acceso.php';
turneroExigirRol(['bacteriologo', 'supervisor']);

// Tablet asignada → forzar su lugar por token de navegador (o IP como fallback)
$lugarForzado = 0;
try {
    $_dispPdo  = Database::getInstance()->getConnection();
    $_dispRow  = null;
    // 1. Chequeo por token de navegador (cookie)
    $_devToken = trim($_COOKIE['turnero_token'] ?? '');
    if ($_devToken) {
        $_s = $_dispPdo->prepare(
            "SELECT td.lugar_id, td.nombre, tl.tipo
               FROM turnero_dispositivos td
               JOIN turnero_lugares tl ON tl.id = td.lugar_id
              WHERE td.token = ? AND td.activo = 1 LIMIT 1"
        );
        $_s->execute([$_devToken]);
        $_dispRow = $_s->fetch(PDO::FETCH_ASSOC) ?: null;
    }
    // 2. Fallback por IP
    if (!$_dispRow) {
        $_clientIp = trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? '')[0]);
        $_s = $_dispPdo->prepare(
            "SELECT td.lugar_id, td.nombre, tl.tipo
               FROM turnero_dispositivos td
               JOIN turnero_lugares tl ON tl.id = td.lugar_id
              WHERE td.ip = ? AND td.token IS NULL AND td.activo = 1 LIMIT 1"
        );
        $_s->execute([$_clientIp]);
        $_dispRow = $_s->fetch(PDO::FETCH_ASSOC) ?: null;
    }
    if ($_dispRow) {
        $_SESSION['turnero_dispositivo'] = $_dispRow;
        $_forzado = (int)$_dispRow['lugar_id'];
        if ($_dispRow['tipo'] === 'recepcion') {
            header('Location: ' . BASE_URL . 'erp.php?m=turnero&v=recepcion&desk_id=' . $_forzado); exit;
        }
        $_pedido = (int)($_GET['lugar_id'] ?? 0);

        // Un equipo fijo queda atado a su estación, pero algunas —Pediatría,
        // Ginecología— se atienden desde cualquier puesto: se marcan como de
        // acceso libre y no se redirige.
        $_libre = false;
        if ($_pedido && $_pedido !== $_forzado) {
            $_sl = $_dispPdo->prepare(
                "SELECT acceso_libre FROM turnero_lugares WHERE id = ? AND activo = 1 LIMIT 1"
            );
            $_sl->execute([$_pedido]);
            $_libre = (bool)$_sl->fetchColumn();
        }

        if ($_pedido !== $_forzado && !$_libre) {
            header('Location: ' . BASE_URL . 'erp.php?m=turnero&v=lugar&lugar_id=' . $_forzado); exit;
        }
        // El equipo sigue atado a su estación aunque esté atendiendo una de
        // acceso libre: la vista muestra la pedida (sale de lugar_id), pero el
        // botón de cambiar sigue oculto y no puede saltar a cualquier otra.
        $lugarForzado = $_forzado;
    }
} catch (\Throwable $_) {}

try {
    $pdo    = Database::getInstance()->getConnection();
    $lugares = $pdo->query(
        "SELECT id, nombre, descripcion, formulario_modo, tipo FROM turnero_lugares WHERE activo = 1 ORDER BY sort_order ASC"
    )->fetchAll(PDO::FETCH_ASSOC);
} catch (\Throwable) {
    $lugares = [];
}

$lugarIdParam  = isset($_GET['lugar_id']) ? (int)$_GET['lugar_id'] : 0;

$lugarNombre     = 'Estación de Servicio';
$lugarFormModo   = 'link';
$lugarTipo       = 'muestras';
foreach ($lugares as $l) {
    if ((int)$l['id'] === $lugarIdParam) {
        $lugarNombre   = $l['nombre'];
        $lugarFormModo = $l['formulario_modo'] ?? 'link';
        $lugarTipo     = $l['tipo']           ?? 'muestras';
        break;
    }
}

$adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['username'] ?? 'Operador';
$adminFirmaSvg = null;
try {
    $stmt = Database::getInstance()->getConnection()
        ->prepare("SELECT firma_svg FROM admin_users WHERE id = ? LIMIT 1");
    $stmt->execute([(int)($_SESSION['admin_user']['id'] ?? 0)]);
    $adminFirmaSvg = $stmt->fetchColumn() ?: null;
} catch (\Throwable $_) {}

// Especialidades (Ginecología, Pediatría) — excluir el lugar actual
$especialidades = [];
foreach ($lugares as $_el) {
    $_en = mb_strtolower($_el['nombre']);
    if ((str_contains($_en, 'ginecol') || str_contains($_en, 'pediatr'))
        && (int)$_el['id'] !== $lugarIdParam) {
        $especialidades[] = $_el;
    }
}

$formulariosList = [];
try {
    $formulariosList = Database::getInstance()->getConnection()
        ->query("SELECT id, nombre FROM lab_formularios WHERE is_active = 1 ORDER BY nombre ASC")
        ->fetchAll(PDO::FETCH_ASSOC);
} catch (\Throwable $_) {}
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars($lugarNombre) ?> — Turnero</title>
    <script>(function(){try{var m=window.matchMedia('(prefers-color-scheme: dark)');function a(d){document.documentElement.setAttribute('data-bs-theme',d?'dark':'light');}a(m.matches);m.addEventListener('change',function(e){a(e.matches);});}catch(e){}})();</script>
    <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=15" rel="stylesheet">
    <style>
        /* ── Layout ─────────────────────────────────────────────── */
        .lugar-layout {
            display: grid;
            grid-template-columns: 370px 1fr;
            height: calc(100vh - 52px);
            overflow: hidden;
        }
        @media (max-width: 680px) {
            .lugar-layout { grid-template-columns: 1fr; position: relative; overflow: hidden; }
            .lugar-cola   { transition: transform .2s ease; }
            .lugar-cola.mobile-oculta { transform: translateX(-100%); position: absolute; inset: 0; pointer-events: none; }
            .lugar-ficha  { position: absolute; inset: 0; background: #fff; z-index: 10;
                            transform: translateX(100%); transition: transform .2s ease; overflow-y: auto; }
            .lugar-ficha.mobile-visible { transform: translateX(0); }
        }

        /* ── Cola ───────────────────────────────────────────────── */
        .lugar-cola {
            background: #f8fafc;
            border-right: 1px solid #e2e8f0;
            display: flex; flex-direction: column; overflow: hidden;
        }
        .lugar-cola-hdr {
            padding: .85rem 1rem .65rem;
            background: #fff; border-bottom: 1px solid #e2e8f0;
            flex-shrink: 0;
        }
        .cola-hdr-row {
            display: flex; align-items: center; justify-content: space-between; margin-bottom: .65rem;
        }
        .cola-hdr-title {
            font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
            color: #64748b; font-weight: 700;
        }
        .cola-counts { display: flex; gap: .4rem; align-items: center; }
        .cola-count-chip {
            font-size: .68rem; font-weight: 700; border-radius: 99px;
            padding: 1px 9px; border: 1px solid;
        }
        .cola-count-chip.espera   { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
        .cola-count-chip.servicio { background: #f0fdf4; color: #166534; border-color: #bbf7d0; }

        .btn-llamar-next {
            width: 100%; padding: .65rem 1rem; border: none; border-radius: 10px;
            background: #2563eb; color: #fff; font-weight: 700; font-size: .92rem;
            cursor: pointer; display: flex; align-items: center; justify-content: center; gap: .5rem;
            transition: background .15s, transform .1s;
        }
        .btn-llamar-next:hover    { background: #1d4ed8; }
        .btn-llamar-next:active   { transform: scale(.98); }
        .btn-llamar-next:disabled { background: #94a3b8; cursor: not-allowed; }

        .cola-items { flex: 1; overflow-y: auto; padding: .5rem; }

        /* ── Especialidades en cola ── */
        .esp-toplinks {
            display: flex; gap: .35rem; flex-wrap: wrap; flex-shrink: 0;
            padding: .45rem .75rem; background: #fff;
            border-bottom: 1px solid #f1f5f9;
        }
        .esp-toplink {
            display: inline-flex; align-items: center; gap: .3rem;
            padding: .2rem .6rem; border-radius: 99px; font-size: .75rem; font-weight: 600;
            color: var(--esp-c, #64748b);
            border: 1.5px solid color-mix(in srgb, var(--esp-c, #64748b) 30%, transparent);
            background: color-mix(in srgb, var(--esp-c, #64748b) 8%, #fff);
            text-decoration: none; white-space: nowrap; transition: background .12s;
        }
        .esp-toplink:hover { background: color-mix(in srgb, var(--esp-c) 18%, #fff); }
        .esp-toplink .esp-cnt {
            background: var(--esp-c); color: #fff; border-radius: 99px;
            padding: 0 5px; font-size: .65rem; min-width: 16px; text-align: center;
        }
        #esp-panel { flex-shrink: 0; border-bottom: 2px solid #e2e8f0; }
        .esp-grupo { padding: .35rem .6rem; }
        .esp-grupo + .esp-grupo { border-top: 1px solid #f1f5f9; }
        .esp-grupo-hdr {
            display: flex; align-items: center; gap: .35rem;
            font-size: .72rem; font-weight: 700; color: #475569; margin-bottom: .2rem;
        }
        .esp-grupo-count {
            background: var(--esp-gc); color: #fff; border-radius: 99px; padding: 0 5px; font-size: .65rem;
        }
        .esp-grupo-ir {
            margin-left: auto; font-size: .7rem; font-weight: 600;
            color: var(--esp-gc); text-decoration: none;
        }
        .esp-grupo-ir:hover { text-decoration: underline; }
        .esp-pac-row {
            display: flex; align-items: center; gap: .4rem;
            padding: .18rem .25rem; border-radius: 5px; font-size: .77rem;
            text-decoration: none; color: #1e293b; transition: background .1s;
        }
        .esp-pac-row:hover { background: #f1f5f9; }
        .esp-pac-orden { font-weight: 700; font-family: monospace; color: var(--esp-gc); font-size: .7rem; flex-shrink: 0; }
        .esp-pac-hora  { margin-left: auto; font-size: .68rem; color: #94a3b8; flex-shrink: 0; }

        /* ── Sala de espera entre muestras ── */
        #espera-muestras-panel { flex-shrink: 0; border-bottom: 2px solid #fde68a; background: #fffbeb; }
        .espera-m-hdr {
            display: flex; align-items: center; gap: .4rem;
            padding: .4rem .75rem .25rem; font-size: .72rem; font-weight: 700; color: #92400e;
        }
        .espera-m-count {
            background: #f97316; color: #fff; border-radius: 99px; padding: 0 6px; font-size: .65rem;
        }
        .espera-m-row {
            display: flex; align-items: center; gap: .5rem;
            padding: .22rem .75rem; font-size: .78rem; color: #1e293b;
            border-top: 1px solid #fde68a;
        }
        .espera-m-orden { font-weight: 700; font-family: monospace; color: #f97316; font-size: .7rem; flex-shrink: 0; }
        .espera-m-cd { font-size: .71rem; font-weight: 700; flex-shrink: 0; white-space: nowrap; }
        .espera-m-cd.ok   { color: #16a34a; }
        .espera-m-cd.warn { color: #d97706; }
        .espera-m-cd.crit { color: #dc2626; animation: parpadeo-alerta .8s infinite; }
        .btn-llamar-espera {
            margin-left: auto; flex-shrink: 0;
            padding: .18rem .55rem; font-size: .72rem; font-weight: 700;
            border: 1.5px solid #22c55e; color: #16a34a; background: #fff;
            border-radius: 7px; cursor: pointer; transition: background .1s;
        }
        .btn-llamar-espera:hover { background: #f0fdf4; }

        .cola-section-sep {
            font-size: .65rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
            color: #94a3b8; padding: .3rem .4rem .15rem; margin-top: .25rem;
        }

        .cola-card {
            background: #fff; border: 1px solid #e2e8f0; border-radius: 11px;
            padding: .65rem .9rem; margin-bottom: .3rem;
            display: flex; align-items: center; gap: .55rem;
            cursor: pointer; transition: border-color .15s, box-shadow .15s, background .15s;
            min-height: 62px;
        }
        .cola-card:hover              { border-color: #a5b4fc; box-shadow: 0 2px 8px rgba(99,102,241,.12); }
        .cola-card.activo             { border-color: #6366f1; box-shadow: 0 0 0 2px #c7d2fe; }
        .cola-card.en-servicio-card   { border-color: #16a34a; background: #f0fdf4; }
        .cola-card.en-servicio-card:hover  { border-color: #15803d; }
        .cola-card.en-servicio-card.activo { box-shadow: 0 0 0 2px #bbf7d0; }

        .prio-dot {
            width: 36px; height: 36px; border-radius: 9px; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            font-size: 1rem; font-weight: 800; color: #fff;
        }
        .turno-info { flex: 1; min-width: 0; }
        .turno-info .cod { font-size: .95rem; font-weight: 700; line-height: 1.2; }
        .turno-info .pac {
            font-size: .74rem; color: #64748b;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        .turno-info .t-badge-row { display: flex; align-items: center; gap: .3rem; margin-top: 2px; flex-wrap: wrap; }
        .tiempo-chip {
            font-size: .6rem; font-weight: 700; border-radius: 99px;
            padding: 0 6px; line-height: 1.7;
        }
        .tiempo-chip.ok   { background: #f0fdf4; color: #166534; }
        .tiempo-chip.warn { background: #fffbeb; color: #92400e; }
        .tiempo-chip.crit { background: #fef2f2; color: #991b1b; }
        .muestra-chip {
            font-size: .6rem; font-weight: 700; color: #ea580c;
            background: #fff7ed; border-radius: 99px; padding: 0 6px; line-height: 1.7;
        }
        .toma-prog-chip {
            font-size: .6rem; font-weight: 700; border-radius: 99px;
            padding: 0 6px; line-height: 1.7; white-space: nowrap;
        }
        .toma-prog-chip.ok   { background: #eff6ff; color: #1d4ed8; }
        .toma-prog-chip.warn { background: #fffbeb; color: #92400e; }
        .toma-prog-chip.crit { background: #fef2f2; color: #991b1b; animation: parpadeo-alerta 1s infinite; }
        @keyframes parpadeo-alerta { 0%,100%{opacity:1} 50%{opacity:.55} }
        .cola-card.toma-prog { border-color: #f97316 !important; }
        .cola-card.toma-prog.crit-card { border-color: #dc2626 !important; background: #fef2f2 !important; }

        .card-en-servicio-pill {
            flex-shrink: 0; display: flex; flex-direction: column; align-items: center;
            background: #16a34a; color: #fff; border-radius: 7px;
            padding: 3px 7px; font-size: .6rem; font-weight: 800; letter-spacing: .03em;
            gap: 1px; text-align: center;
        }
        .card-en-servicio-pill i { font-size: .75rem; }

        .card-bell-btn {
            flex-shrink: 0; background: #2563eb; border: none; color: #fff;
            border-radius: 10px; width: 44px; height: 44px;
            display: flex; align-items: center; justify-content: center;
            font-size: .95rem; cursor: pointer; transition: background .12s;
        }
        .card-bell-btn:hover { background: #1d4ed8; }

        .cola-vacia { text-align: center; padding: 2.5rem 1rem; color: #94a3b8; font-size: .88rem; }

        /* ── Ficha ──────────────────────────────────────────────── */
        .lugar-ficha { overflow-y: auto; padding: 0; background: #fff; display: flex; flex-direction: column; }
        .ficha-inner { flex: 1; padding: 1.2rem 1.4rem 1rem; }

        .ficha-placeholder {
            flex: 1; display: flex; flex-direction: column;
            align-items: center; justify-content: center;
            color: #94a3b8; text-align: center; padding: 3rem 1rem;
        }

        /* Mobile top bar (back button) */
        .ficha-mobile-topbar {
            display: none; align-items: center; gap: .6rem;
            padding: .55rem 1rem; background: #f8fafc;
            border-bottom: 1px solid #e2e8f0; flex-shrink: 0;
            position: sticky; top: 0; z-index: 20;
        }
        @media (max-width: 680px) {
            .ficha-mobile-topbar { display: flex; }
        }
        .ficha-mobile-topbar .btn-back {
            background: none; border: none; padding: 4px 6px;
            color: #2563eb; font-size: .88rem; font-weight: 600;
            cursor: pointer; display: flex; align-items: center; gap: .3rem;
        }
        .ficha-mobile-topbar .m-cod { font-size: .78rem; color: #64748b; font-weight: 600; }

        /* ── Ficha header ───────────────────────────────────────── */
        .ficha-turno-hdr {
            background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 13px;
            padding: .9rem 1.1rem; margin-bottom: 1rem;
        }
        .fth-top {
            display: flex; align-items: center; gap: .6rem; margin-bottom: .5rem;
        }
        .prio-dot-sm {
            width: 30px; height: 30px; border-radius: 7px; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            font-size: .82rem; font-weight: 800; color: #fff;
        }
        .fth-meta { flex: 1; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
        .fth-cod  { font-size: .82rem; font-weight: 800; color: #334155; }
        .fth-prio { font-size: .75rem; color: #64748b; }
        .fth-pac-nom {
            font-size: 1.35rem; font-weight: 800; color: #1e293b; line-height: 1.2;
            letter-spacing: -.01em;
        }
        .fth-pac-nom.loading {
            height: 22px; width: 60%; border-radius: 6px;
            background: linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%);
            background-size: 200% 100%; animation: skel-wave 1.4s infinite;
        }
        @keyframes skel-wave {
            0%   { background-position: 200% 0 }
            100% { background-position: -200% 0 }
        }

        /* ── Secciones ──────────────────────────────────────────── */
        .ficha-sec {
            background: #f8fafc; border: 1px solid #e2e8f0;
            border-radius: 12px; padding: 1.2rem; margin-bottom: .85rem;
        }
        .ficha-sec-hdr {
            display: flex; align-items: center; gap: .4rem;
            font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
            color: #475569; font-weight: 700; margin-bottom: .7rem;
        }
        .ficha-sec-hdr i { font-size: .85rem; }

        /* ── Datos paciente ── */
        .pac-dato { display: flex; gap: .5rem; align-items: baseline; margin-bottom: .25rem; }
        .pac-dato .lbl { font-size: .72rem; color: #94a3b8; min-width: 78px; flex-shrink: 0; }
        .pac-dato .val { font-size: .87rem; color: #1e293b; font-weight: 500; }

        /* ── Exámenes ── */
        .exam-pill {
            display: inline-flex; align-items: center; gap: .3rem;
            background: #eff6ff; color: #1d4ed8; border-radius: 20px;
            padding: .22rem .7rem; font-size: .78rem; font-weight: 600; margin: .15rem;
            border: 1px solid #bfdbfe;
        }

        /* ── Consentimientos ── */
        .consent-row {
            display: flex; align-items: center; gap: .6rem;
            padding: .5rem .7rem; border-radius: 10px; margin-bottom: .35rem;
            font-size: .84rem; border: 1px solid transparent; min-height: 46px;
        }
        .consent-row.firmado             { background: #f0fdf4; color: #166534; border-color: #bbf7d0; }
        .consent-row.cerrado_anticipado  { background: #fef9c3; color: #78350f; border-color: #fde68a; }
        .consent-row.rechazado  { background: #f8fafc; color: #64748b; border-color: #e2e8f0; }
        .consent-row.enviado    { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
        .consent-row.pendiente  { background: #fffbeb; color: #92400e; border-color: #fde68a; }
        .consent-row.visto      { background: #faf5ff; color: #6b21a8; border-color: #ddd6fe; }
        .consent-row.en_progreso { background: #fff7ed; color: #9a3412; border-color: #fed7aa; }
        .consent-row.en_progreso.alerta { background: #fef2f2; color: #991b1b; border-color: #fca5a5;
                                          animation: parpadeo-alerta 1s infinite; }
        @keyframes parpadeo-alerta { 0%,100%{opacity:1} 50%{opacity:.6} }
        .toma-progreso { font-size:.67rem; background:#ea580c; color:#fff;
                         border-radius:99px; padding:1px 7px; font-weight:700; white-space:nowrap; }
        .toma-countdown { font-size:.67rem; color:inherit; opacity:.75; white-space:nowrap; }
        .consent-row .nom-form { flex: 1; font-weight: 500; }
        .consent-row .c-badge  { font-size: .67rem; padding: 1px 8px; border-radius: 99px;
                                  border: 1px solid currentColor; font-weight: 700; opacity: .85; }
        .consent-row .acciones-consent { display: flex; gap: .3rem; flex-shrink: 0; }
        .consent-row .acciones-consent .btn { font-size: .72rem; padding: 2px 9px; border-radius: 7px; }

        /* ── Tomas pendientes de visita anterior ── */
        #sec-tomas-prev { display:none; }
        .tomas-prev-hdr { font-size:.78rem; font-weight:700; color:#92400e;
                          background:#fff7ed; border:1px solid #fed7aa;
                          border-radius:8px 8px 0 0; padding:6px 12px;
                          display:flex; align-items:center; gap:6px; }
        .tomas-prev-list { border:1px solid #fed7aa; border-top:none;
                           border-radius:0 0 8px 8px; overflow:hidden; }
        .toma-prev-row { display:flex; align-items:center; gap:.6rem;
                         padding:.45rem .7rem; background:#fffbeb;
                         font-size:.83rem; color:#78350f; }
        .toma-prev-row + .toma-prev-row { border-top:1px solid #fde68a; }
        .toma-prev-row .nom-form { flex:1; font-weight:500; }
        .toma-prev-row .acciones-consent { display:flex; gap:.3rem; flex-shrink:0; }
        .toma-prev-row .acciones-consent .btn { font-size:.72rem; padding:2px 9px; border-radius:7px; }

        /* ── Barra de acciones ── */
        .ficha-acciones {
            position: sticky; bottom: 0;
            background: rgba(255,255,255,.97);
            backdrop-filter: blur(6px);
            border-top: 1px solid #e2e8f0;
            padding: .8rem 1.4rem .9rem;
            margin-top: auto; flex-shrink: 0;
        }
        .accion-consent-warn {
            display: flex; align-items: center; gap: .5rem;
            background: #fffbeb; border: 1px solid #fcd34d; border-radius: 9px;
            padding: .5rem .8rem; font-size: .8rem; color: #92400e; font-weight: 600;
            margin-bottom: .65rem;
        }
        .accion-consent-warn i { color: #f59e0b; flex-shrink: 0; }
        .accion-primary-row { margin-bottom: .45rem; }
        .btn-accion-primary {
            width: 100%; padding: .8rem; border: none; border-radius: 11px;
            font-size: 1rem; font-weight: 700; cursor: pointer;
            display: flex; align-items: center; justify-content: center; gap: .45rem;
            transition: background .15s, transform .1s, opacity .15s;
        }
        .btn-accion-primary:active   { transform: scale(.98); }
        .btn-accion-primary:disabled { opacity: .5; cursor: not-allowed; }
        .btn-accion-primary.azul  { background: #2563eb; color: #fff; }
        .btn-accion-primary.azul:hover  { background: #1d4ed8; }
        .btn-accion-primary.verde { background: #16a34a; color: #fff; }
        .btn-accion-primary.verde:hover { background: #15803d; }
        .accion-secondary-row {
            display: flex; gap: .4rem; align-items: center; flex-wrap: wrap;
        }
        .btn-accion-sec {
            flex: 1; min-width: 80px;
            padding: .55rem .5rem; border-radius: 9px;
            font-size: .82rem; font-weight: 600; cursor: pointer;
            display: flex; align-items: center; justify-content: center; gap: .35rem;
            border: 1.5px solid; background: transparent; transition: background .12s;
        }
        .btn-accion-sec.warning { color: #92400e; border-color: #fcd34d; }
        .btn-accion-sec.warning:hover { background: #fffbeb; }
        .btn-accion-sec.info    { color: #1e40af; border-color: #93c5fd; }
        .btn-accion-sec.info:hover    { background: #eff6ff; }
        .btn-accion-sec.danger  { color: #991b1b; border-color: #fca5a5; }
        .btn-accion-sec.danger:hover  { background: #fef2f2; }

        /* ── Bloqueo banner ── */
        .bloqueo-banner {
            background: #fef2f2; border: 1px solid #fca5a5; border-radius: 10px;
            padding: .6rem .9rem; font-size: .82rem; color: #991b1b;
            display: flex; align-items: center; gap: .5rem; margin-bottom: .7rem;
        }

        /* ── Selector ── */
        .selector-lugar-overlay {
            position: fixed; inset: 0; background: #f1f5f9;
            z-index: 200; display: flex; align-items: center; justify-content: center;
        }
        .selector-lugar-box {
            background: #fff; border-radius: 20px; padding: 2.5rem;
            width: min(90vw, 480px); box-shadow: 0 8px 40px rgba(0,0,0,.12); text-align: center;
        }
        .selector-lugar-box h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 1.5rem; }

        /* ── Modal paciente ── */
        #modal-pac-lugar { display:none; position:fixed; inset:0; z-index:9500;
            background:rgba(0,0,0,.55); align-items:center; justify-content:center; padding:16px; }
        #modal-pac-lugar.show { display:flex; }
        .mpac-dialog {
            background:#fff; border-radius:16px; width:min(96vw,540px);
            max-height:90vh; display:flex; flex-direction:column; overflow:hidden;
            box-shadow:0 8px 40px rgba(0,0,0,.22);
        }
        .mpac-hdr {
            display:flex; align-items:center; justify-content:space-between;
            padding:1.1rem 1.25rem; border-bottom:1px solid rgba(255,255,255,.15); flex-shrink:0;
            background:linear-gradient(135deg,#1043a0 0%,#1565c0 100%);
        }
        .mpac-hdr-title { font-weight:700; font-size:.97rem; color:#fff; display:flex; align-items:center; gap:.5rem; }
        .mpac-close { background:rgba(255,255,255,.15); border:none; font-size:1.1rem; color:#fff; cursor:pointer; padding:4px 8px; border-radius:6px; }
        .mpac-close:hover { background:rgba(255,255,255,.25); }
        .mpac-body { overflow-y:auto; padding:18px; flex:1; }
        .mpac-dato { display:flex; gap:.5rem; align-items:baseline; margin-bottom:.4rem; }
        .mpac-dato .lbl { font-size:.72rem; color:#94a3b8; min-width:95px; flex-shrink:0; }
        .mpac-dato .val { font-size:.88rem; color:#1e293b; font-weight:500; }
        .mpac-sec-title {
            font-size:.7rem; text-transform:uppercase; letter-spacing:.07em;
            color:#475569; font-weight:700; margin:14px 0 8px;
            display:flex; align-items:center; gap:.4rem;
        }
        /* Historial timeline */
        .mpac-timeline { padding: 0; }
        .mpac-lbl { font-size:.7rem; color:#64748b; font-weight:600; display:block; margin-bottom:2px; }
        .mpac-aviso { font-size:.74rem; color:#1e40af; background:#eff6ff; border:1px solid #bfdbfe;
                      border-radius:8px; padding:7px 10px; margin-bottom:10px; }
        .mpac-lock { background:#fffbeb; border:1px solid #fde68a; border-radius:8px;
                     padding:9px 11px; margin:4px 0 10px; }
        .mpac-lock-txt { font-size:.72rem; color:#92400e; margin-bottom:7px; line-height:1.45; }
        .mpac-aviso-firmados { font-size:.74rem; color:#7f1d1d; background:#fef2f2;
                               border:1px solid #fecaca; border-radius:8px;
                               padding:8px 11px; margin-bottom:10px; line-height:1.45; }
        .mtl-item {
            display:flex; gap:10px; align-items:flex-start;
            padding-bottom:12px; position:relative;
        }
        .mtl-item:not(:last-child)::before {
            content:''; position:absolute; left:6px; top:14px;
            width:2px; bottom:0; background:#e2e8f0;
        }
        .mtl-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;
        }
        .mtl-content { flex:1; min-width:0; }
        .mtl-fecha  { font-size:.68rem; color:#94a3b8; }
        .mtl-codigo { font-size:.82rem; font-weight:700; }
        .mtl-lugar  { font-size:.73rem; color:#64748b; }
        .mtl-eb { font-size:.62rem; padding:1px 7px; border-radius:99px; font-weight:700; display:inline-block; margin-top:2px; }

        /* ── Banner toma alerta ── */
        #banner-toma-alerta {
            display: none; position: fixed; top: 52px; left: 0; right: 0; z-index: 8900;
            background: #dc2626; color: #fff;
            padding: .65rem 1.2rem; display: none;
            align-items: center; gap: .75rem; font-size: .9rem; font-weight: 600;
            box-shadow: 0 4px 20px rgba(220,38,38,.45);
            animation: parpadeo-alerta 1s infinite;
        }
        #banner-toma-alerta.show { display: flex; }
        #banner-toma-alerta .btn-banner-pac {
            background: rgba(255,255,255,.2); border: 1.5px solid rgba(255,255,255,.5);
            color: #fff; border-radius: 8px; padding: 3px 12px; font-size: .8rem;
            cursor: pointer; font-weight: 700; transition: background .12s;
        }
        #banner-toma-alerta .btn-banner-pac:hover { background: rgba(255,255,255,.35); }
        #banner-toma-alerta .btn-banner-x {
            margin-left: auto; background: none; border: none; color: rgba(255,255,255,.8);
            font-size: 1.1rem; cursor: pointer; padding: 0 4px;
        }

        /* ── 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; }

        /* ── Widget muestras ────────────────────────────────────── */
        .muestra-row {
            display: flex; align-items: center; gap: .6rem;
            padding: .5rem .7rem; border-radius: 10px; margin-bottom: .35rem;
            font-size: .84rem; border: 1px solid transparent;
        }
        .muestra-row.pendiente  { background: #fffbeb; border-color: #fde68a; }
        .muestra-row.recibida   { background: #f0fdf4; border-color: #bbf7d0; color: #166534; }
        .muestra-row.rechazada  { background: #fff7ed; border-color: #fed7aa; color: #c2410c; }
        .muestra-info           { flex: 1; min-width: 0; }
        .muestra-label          { font-weight: 600; font-size: .82rem; font-family: monospace; }
        .muestra-motivo         { font-size: .7rem; margin-top: 2px; opacity: .85; }
        .muestra-examenes       { font-size: .7rem; margin-top: 2px; opacity: .85; }
        .muestra-ts             { font-size: .68rem; color: #94a3b8; flex-shrink: 0; }
        .btn-muestra-accion {
            border: none; border-radius: 8px; padding: 3px 11px;
            font-size: .75rem; font-weight: 700; cursor: pointer;
            display: flex; align-items: center; gap: .25rem;
            transition: opacity .12s;
        }
        .btn-muestra-accion:active  { opacity: .75; }
        .btn-muestra-accion.recibir  { background: #16a34a; color: #fff; }
        .btn-muestra-accion.rechazar { background: #fff; color: #c2410c; border: 1.5px solid #fed7aa; }
        .muestras-summary {
            font-size: .72rem; color: #64748b; margin-bottom: .5rem;
            display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
        }
        .muestras-summary .mc { font-weight: 700; border-radius: 99px; padding: 1px 8px;
                                 font-size: .68rem; }
        .muestras-summary .mc.pend { background: #fef9c3; color: #854d0e; }
        .muestras-summary .mc.rec  { background: #dcfce7; color: #166534; }
        .muestras-summary .mc.rech { background: #fff7ed; color: #c2410c; }
    </style>
</head>
<body>

<?php
$SIDEBAR_TITLE = 'Turnero';
$SIDEBAR_ICON  = 'fas fa-ticket-alt';
require_once __DIR__ . '/../../../shared/components/sidebar.php';
?>

<!-- ══ Selector inicial ══════════════════════════════════════════ -->
<div id="overlay-selector" class="selector-lugar-overlay" <?= $lugarIdParam ? 'style="display:none"' : '' ?>>
    <div class="selector-lugar-box">
        <i class="fas fa-map-marker-alt fa-2x text-primary mb-3"></i>
        <h2>Seleccione su estación</h2>
        <select id="sel-lugar-init" class="form-select mb-3">
            <option value="">— Elija un lugar —</option>
            <?php foreach ($lugares as $l): ?>
            <option value="<?= (int)$l['id'] ?>"><?= htmlspecialchars($l['nombre']) ?></option>
            <?php endforeach; ?>
        </select>
        <button class="btn btn-primary w-100" onclick="confirmarLugar()">
            <i class="fas fa-check me-1"></i>Confirmar
        </button>
        <button id="btn-cancelar-selector" class="btn btn-outline-secondary w-100 mt-2"
                onclick="document.getElementById('overlay-selector').style.display='none'"
                style="display:none">
            <i class="fas fa-times me-1"></i>Cancelar
        </button>
    </div>
</div>

<!-- ── Banner alerta toma progresiva ─────────────────────────────── -->
<div id="banner-toma-alerta" role="alert">
    <i class="fas fa-syringe fa-lg"></i>
    <span id="banner-toma-txt">¡Hora de la siguiente muestra!</span>
    <button class="btn-banner-pac" id="banner-toma-btn" onclick="verPacienteToma()">Ver paciente</button>
    <button class="btn-banner-x" onclick="cerrarBannerToma()" title="Cerrar"><i class="fas fa-times"></i></button>
</div>

<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;min-height:52px">
        <div class="d-flex align-items-center gap-2">
            <i class="fas fa-map-marker-alt text-primary"></i>
            <strong id="lbl-lugar-titulo"><?= htmlspecialchars($lugarNombre) ?></strong>
            <span id="badge-turno-activo" class="badge bg-primary ms-1 d-none"></span>
        </div>
        <div class="d-flex align-items-center gap-2">
            <span class="text-muted small d-none d-md-inline"><?= htmlspecialchars($adminNombre) ?></span>
            <button class="btn btn-sm <?= $adminFirmaSvg ? 'btn-outline-success' : 'btn-warning' ?>"
                    onclick="abrirModalMiFirma()" title="<?= $adminFirmaSvg ? 'Ver / cambiar mi firma' : 'Configurar mi firma' ?>">
                <i class="fas fa-signature me-1"></i><?= $adminFirmaSvg ? 'Mi firma' : 'Configurar firma' ?>
            </button>
            <?php if (!$lugarForzado): ?>
            <button class="btn btn-sm btn-outline-secondary" onclick="cambiarLugar()">
                <i class="fas fa-exchange-alt me-1"></i>Cambiar
            </button>
            <?php endif; ?>
        </div>
    </div>

    <div class="lugar-layout">

        <!-- ══ Cola ═══════════════════════════════════════════════ -->
        <div class="lugar-cola">
            <div class="lugar-cola-hdr">
                <div class="cola-hdr-row">
                    <span class="cola-hdr-title"><i class="fas fa-list-ol me-1"></i>Cola</span>
                    <div class="cola-counts">
                        <span class="cola-count-chip espera"   id="badge-count">0 espera</span>
                        <span class="cola-count-chip servicio d-none" id="badge-servicio">0 servicio</span>
                    </div>
                </div>
                <button class="btn-llamar-next" id="btn-llamar" onclick="llamarSiguiente()">
                    <i class="fas fa-bell"></i>Llamar siguiente
                </button>
            </div>
            <?php if ($especialidades): ?>
            <div class="esp-toplinks">
                <?php foreach ($especialidades as $_esp):
                    $_esGine = mb_stripos($_esp['nombre'], 'ginecol') !== false;
                    $_espC   = $_esGine ? '#ec4899' : '#0ea5e9';
                    $_espI   = $_esGine ? 'fa-venus'  : 'fa-child';
                ?>
                <a href="<?= BASE_URL ?>erp.php?m=turnero&v=lugar&lugar_id=<?= (int)$_esp['id'] ?>"
                   class="esp-toplink" style="--esp-c:<?= $_espC ?>">
                    <i class="fas <?= $_espI ?>"></i>
                    <?= htmlspecialchars($_esp['nombre']) ?>
                    <span class="esp-cnt" id="esp-cnt-<?= (int)$_esp['id'] ?>">—</span>
                </a>
                <?php endforeach; ?>
            </div>
            <div id="esp-panel" style="display:none"></div>
            <?php endif; ?>

            <div id="espera-muestras-panel" style="display:none"></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>

        <!-- ══ Ficha del turno ════════════════════════════════════ -->
        <div class="lugar-ficha" id="lugar-ficha">

            <!-- Barra back en móvil -->
            <div class="ficha-mobile-topbar" id="ficha-mobile-topbar">
                <button class="btn-back" onclick="volverACola()">
                    <i class="fas fa-arrow-left"></i> Cola
                </button>
                <span class="m-cod" id="ficha-mobile-cod"></span>
            </div>

            <!-- Estado vacío -->
            <div class="ficha-placeholder" id="ficha-placeholder">
                <i class="fas fa-stethoscope fa-3x mb-3" style="color:#cbd5e1"></i>
                <p class="fw-semibold mb-1">Sin turno activo</p>
                <small class="text-muted">Pulse "Llamar siguiente" o seleccione un turno de la cola</small>
            </div>

            <div id="ficha-turno" class="d-none" style="display:flex;flex-direction:column;flex:1">

                <div class="ficha-inner">

                    <!-- ── Header: paciente + turno ── -->
                    <div class="ficha-turno-hdr">
                        <div class="fth-top">
                            <div id="ficha-prio-dot" class="prio-dot-sm" style="background:#6366f1">—</div>
                            <div class="fth-meta">
                                <span class="fth-cod"  id="ficha-codigo">—</span>
                                <span class="fth-prio" id="ficha-prio-nombre"></span>
                                <span id="ficha-orden" class="d-none"
                                      style="font-size:.72rem;background:#eff6ff;color:#1d4ed8;border:1px solid #bfdbfe;
                                             border-radius:20px;padding:1px 10px;font-weight:700;white-space:nowrap">
                                    <i class="fas fa-hashtag" style="font-size:.63rem"></i>
                                    <span id="ficha-orden-val"></span>
                                </span>
                            </div>
                            <span class="badge bg-success-subtle text-success border border-success-subtle"
                                  id="ficha-estado-badge">en espera</span>
                            <span id="badge-solo-muestras" class="d-none"
                                  style="font-size:.7rem;background:#fff7ed;color:#c2410c;border:1px solid #fed7aa;
                                         border-radius:20px;padding:1px 10px;font-weight:700;white-space:nowrap">
                                <i class="fas fa-flask me-1"></i>Solo entrega de muestras
                            </span>
                        </div>
                        <div id="ficha-pac-nombre-hdr" class="fth-pac-nom loading">&nbsp;</div>
                    </div>

                    <!-- ── Paciente ── -->
                    <div class="ficha-sec">
                        <div class="ficha-sec-hdr">
                            <i class="fas fa-user"></i>Paciente
                            <button id="btn-ver-paciente" class="btn btn-sm btn-outline-primary ms-auto d-none"
                                    onclick="abrirModalPaciente()" style="font-size:.72rem;padding:2px 10px;border-radius:20px">
                                <i class="fas fa-eye me-1"></i>Ver
                            </button>
                        </div>
                        <div id="bloque-pac-info">
                            <div class="pac-dato"><span class="lbl">Nombre</span><span class="val" id="pac-nombre">—</span></div>
                            <div class="pac-dato"><span class="lbl">Documento</span><span class="val" id="pac-doc">—</span></div>
                            <div class="pac-dato d-none"><span class="lbl">Fecha nac.</span><span class="val" id="pac-fec">—</span></div>
                            <div class="pac-dato d-none"><span class="lbl">Celular</span><span class="val" id="pac-cel">—</span></div>
                        </div>
                        <div id="pac-embarazada" class="d-none mt-2">
                            <span class="badge text-bg-danger"><i class="fas fa-baby me-1"></i>Paciente embarazada</span>
                        </div>
                        <div id="pac-medico" class="d-none mt-2">
                            <div class="pac-dato">
                                <span class="lbl">Médico</span>
                                <span class="val" id="pac-medico-nombre" style="color:#4f46e5"></span>
                            </div>
                        </div>
                        <div id="pac-obs-recepcion" class="d-none mt-2">
                            <div style="background:#fffbeb;border-left:3px solid #f59e0b;border-radius:4px;padding:7px 10px;font-size:.8rem">
                                <div style="font-weight:600;color:#92400e;margin-bottom:2px"><i class="fas fa-comment-alt me-1"></i>Nota de recepción</div>
                                <div id="pac-obs-recepcion-texto" style="color:#78350f;white-space:pre-line"></div>
                            </div>
                        </div>
                        <div id="bloque-pac-sin" class="text-muted small">
                            <i class="fas fa-info-circle me-1"></i>Sin paciente vinculado
                        </div>
                    </div>

                    <!-- ── Exámenes ── -->
                    <div class="ficha-sec">
                        <div class="ficha-sec-hdr"><i class="fas fa-vial"></i>Exámenes solicitados</div>
                        <div id="lista-examenes-ficha">
                            <span class="text-muted small">Sin exámenes registrados</span>
                        </div>
                    </div>

                    <!-- ── Formulario embebido (iframe, modo link) ── -->
                    <div class="ficha-sec d-none" id="sec-form-embebido">
                        <div class="ficha-sec-hdr"><i class="fas fa-file-alt"></i>Formulario de consentimiento</div>
                        <div id="form-embebido-loading" class="text-muted small py-2">
                            <i class="fas fa-spinner fa-spin me-1"></i>Cargando formulario...
                        </div>
                        <iframe id="form-embebido-iframe" src="" frameborder="0"
                                style="width:100%;min-height:520px;border-radius:8px;border:1px solid #e2e8f0;display:none"
                                onload="this.style.display='block';document.getElementById('form-embebido-loading').style.display='none'">
                        </iframe>
                    </div>

                    <!-- ── Tomas progresivas pendientes de visita anterior ── -->
                    <div class="ficha-sec" id="sec-tomas-prev">
                        <div class="tomas-prev-hdr">
                            <i class="fas fa-hourglass-half"></i>
                            Tomas pendientes de visita anterior
                        </div>
                        <div class="tomas-prev-list" id="lista-tomas-prev"></div>
                    </div>

                    <!-- ── Consentimientos ── -->
                    <div class="ficha-sec" id="sec-consent">
                        <div class="ficha-sec-hdr"><i class="fas fa-file-signature"></i>Consentimientos informados</div>
                        <div id="bloqueo-banner" class="bloqueo-banner d-none">
                            <i class="fas fa-lock"></i>
                            <span>Hay consentimientos pendientes. No puede <strong>finalizar</strong> hasta que estén <strong>firmados</strong> o <strong>rechazados</strong>.</span>
                        </div>
                        <div id="lista-consent"></div>
                        <div id="sin-consent" class="text-muted small">
                            <i class="fas fa-check-circle text-success me-1"></i>No se requieren consentimientos
                        </div>
                        <div id="btn-anexar-wrap" class="d-none mt-2">
                            <button type="button" class="btn btn-outline-secondary btn-sm w-100" onclick="_abrirAnexarFormulario()">
                                <i class="fas fa-plus me-1"></i>Agregar formulario adicional
                            </button>
                        </div>
                    </div>

                    <!-- ── Muestras (solo estaciones tipo muestras) ── -->
                    <div class="ficha-sec d-none" id="sec-muestras">
                        <div class="ficha-sec-hdr">
                            <i class="fas fa-flask" style="color:#ea580c"></i>
                            Recepción de muestras
                        </div>
                        <div id="muestras-summary" class="muestras-summary"></div>
                        <div id="lista-muestras"></div>
                    </div>

                    <!-- ── Comentarios ── -->
                    <div class="ficha-sec" id="sec-comentarios">
                        <div class="ficha-sec-hdr"><i class="fas fa-comments" style="color:#8b5cf6"></i>Comentarios del seguimiento</div>
                        <div style="display:flex;gap:8px;margin-bottom:10px">
                            <textarea id="inp-comentario" class="form-control form-control-sm"
                                      rows="2" placeholder="Añade un comentario sobre este turno…"
                                      maxlength="500" style="resize:vertical"
                                      oninput="draftGuardar()"></textarea>
                            <button class="btn btn-sm btn-primary" onclick="guardarComentario()"
                                    style="height:fit-content;align-self:flex-end">
                                <i class="fas fa-paper-plane"></i>
                            </button>
                        </div>
                        <div id="lista-comentarios" class="text-muted small py-2">
                            <i class="fas fa-spinner fa-spin me-1"></i>Cargando comentarios…
                        </div>
                    </div>

                </div><!-- /ficha-inner -->

                <!-- ── Barra de acciones sticky ── -->
                <div class="ficha-acciones">

                    <!-- Aviso de consentimientos pendientes -->
                    <div id="accion-consent-warn" class="accion-consent-warn d-none">
                        <i class="fas fa-exclamation-triangle"></i>
                        <span id="accion-warn-txt">Consentimientos pendientes</span> — No puede finalizar la atención
                    </div>

                    <!-- Botón primario -->
                    <div class="accion-primary-row">
                        <button class="btn-accion-primary azul"  id="btn-iniciar"   onclick="iniciarAtencion()">
                            <i class="fas fa-volume-up"></i>Anunciar turno
                        </button>
                        <button class="btn-accion-primary verde d-none" id="btn-finalizar" onclick="finalizarAtencion()">
                            <i class="fas fa-flag-checkered"></i>Finalizar atención
                        </button>
                    </div>

                    <!-- Botones secundarios -->
                    <div class="accion-secondary-row">
                        <button class="btn-accion-sec info d-none"    id="btn-rellamar" onclick="rellamarTurno()">
                            <i class="fas fa-bullhorn"></i>Re-llamar
                        </button>
                        <button class="btn-accion-sec warning d-none" id="btn-regresar" onclick="regresarCola()">
                            <i class="fas fa-undo"></i>Regresar cola
                        </button>
                        <button class="btn-accion-sec warning d-none" id="btn-devolver" onclick="devolverRecepcion()">
                            <i class="fas fa-reply"></i>A recepción
                        </button>
                        <button class="btn-accion-sec d-none" id="btn-espera" onclick="_ponerEnEspera()"
                                style="color:#c2410c;border-color:#fed7aa">
                            <i class="fas fa-hourglass-half"></i>Mandar a espera
                        </button>
                        <button class="btn-accion-sec danger"         id="btn-ausente"  onclick="marcarAusente()">
                            <i class="fas fa-user-slash"></i>Ausente
                        </button>
                    </div>

                </div>

            </div><!-- /ficha-turno -->
        </div><!-- /lugar-ficha -->

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

<!-- ── Modal datos + historial del paciente ─────────────────────── -->
<div id="modal-pac-lugar" onclick="if(event.target===this)cerrarModalPaciente()">
    <div class="mpac-dialog">
        <div class="mpac-hdr">
            <span class="mpac-hdr-title"><i class="fas fa-user-circle text-primary"></i><span id="mpac-nombre-titulo">Paciente</span></span>
            <button class="mpac-close" onclick="cerrarModalPaciente()"><i class="fas fa-times"></i></button>
        </div>
        <div class="mpac-body">
            <!-- Datos básicos -->
            <div class="mpac-sec-title"><i class="fas fa-id-card"></i>Información del paciente</div>
            <div id="mpac-datos">
                <div class="mpac-dato"><span class="lbl">Nombre</span><span class="val" id="mpac-val-nombre">—</span></div>
                <div class="mpac-dato"><span class="lbl">Documento</span><span class="val" id="mpac-val-doc">—</span></div>
                <div class="mpac-dato"><span class="lbl">Fecha nac.</span><span class="val" id="mpac-val-fec">—</span></div>
                <div class="mpac-dato"><span class="lbl">Celular</span><span class="val" id="mpac-val-cel">—</span></div>
                <div class="mpac-dato" id="mpac-row-medico" style="display:none">
                    <span class="lbl">Médico</span><span class="val" id="mpac-val-medico" style="color:#4f46e5">—</span>
                </div>
                <div id="mpac-badge-emb" class="d-none mt-1">
                    <span class="badge text-bg-danger"><i class="fas fa-baby me-1"></i>Paciente embarazada</span>
                </div>
                <div class="mt-2">
                    <button class="btn btn-sm btn-outline-secondary" onclick="mpacEditar(true)"
                            id="mpac-btn-editar" style="font-size:.74rem">
                        <i class="fas fa-pen me-1"></i>Corregir datos
                    </button>
                </div>
            </div>

            <!-- ── Edición de la ficha ── -->
            <div id="mpac-form" class="d-none">
                <div class="mpac-aviso">
                    <i class="fas fa-info-circle me-1"></i>
                    Lo que corrija aquí cambia la ficha del paciente <b>en todo el sistema</b>.
                </div>

                <label class="mpac-lbl">Celular</label>
                <input type="text" class="form-control form-control-sm mb-2" id="mpac-in-tel" placeholder="3001234567">

                <label class="mpac-lbl">Dirección</label>
                <input type="text" class="form-control form-control-sm mb-2" id="mpac-in-dir">

                <label class="mpac-lbl">EPS</label>
                <input type="text" class="form-control form-control-sm mb-2" id="mpac-in-eps">

                <label class="mpac-lbl">Sexo</label>
                <select class="form-select form-select-sm mb-2" id="mpac-in-genero">
                    <option value="">— Sin registrar —</option>
                    <option value="M">Masculino</option>
                    <option value="F">Femenino</option>
                    <option value="O">Otro</option>
                </select>

                <!-- Datos de identidad: requieren un paso deliberado -->
                <div id="mpac-identidad-lock" class="mpac-lock">
                    <div class="mpac-lock-txt">
                        <i class="fas fa-lock me-1"></i>
                        Nombre, documento y fecha de nacimiento identifican al paciente en toda su
                        historia clínica.
                    </div>
                    <button class="btn btn-sm btn-outline-warning w-100" onclick="mpacDesbloquearIdentidad()"
                            style="font-size:.74rem">
                        <i class="fas fa-unlock me-1"></i>Corregir también estos datos
                    </button>
                </div>

                <div id="mpac-identidad" class="d-none">
                    <label class="mpac-lbl">Nombre completo</label>
                    <input type="text" class="form-control form-control-sm mb-2" id="mpac-in-nombre">

                    <div class="d-flex gap-2 mb-2">
                        <div style="width:90px">
                            <label class="mpac-lbl">Tipo</label>
                            <select class="form-select form-select-sm" id="mpac-in-tipodoc">
                                <option>CC</option><option>TI</option><option>RC</option>
                                <option>CE</option><option>PA</option><option>NIT</option>
                            </select>
                        </div>
                        <div class="flex-grow-1">
                            <label class="mpac-lbl">Nº documento</label>
                            <input type="text" class="form-control form-control-sm" id="mpac-in-doc">
                        </div>
                    </div>

                    <label class="mpac-lbl">Fecha de nacimiento</label>
                    <input type="date" class="form-control form-control-sm mb-2" id="mpac-in-fnac">
                </div>

                <div id="mpac-aviso-firmados" class="mpac-aviso-firmados d-none">
                    <i class="fas fa-exclamation-triangle me-1"></i>
                    Este turno ya tiene documentos firmados. Corregir la ficha
                    <b>no modifica lo que ya se firmó</b>: si un documento salió con datos
                    equivocados, hay que emitirlo de nuevo.
                </div>

                <div id="mpac-msg" class="small mb-2"></div>
                <div class="d-flex gap-2">
                    <button class="btn btn-sm btn-primary flex-grow-1" onclick="mpacGuardarFicha()" id="mpac-btn-guardar">
                        <i class="fas fa-save me-1"></i>Guardar
                    </button>
                    <button class="btn btn-sm btn-outline-secondary" onclick="mpacEditar(false)">Cancelar</button>
                </div>
            </div>
            <!-- Historial -->
            <div class="mpac-sec-title"><i class="fas fa-history" style="color:#6366f1"></i>Historial de visitas</div>
            <div id="mpac-historial-content">
                <div class="text-center text-muted py-3 small">
                    <i class="fas fa-spinner fa-spin me-1"></i>Cargando historial…
                </div>
            </div>
        </div>
    </div>
</div>

<!-- ── Modal: quitar consentimiento ───────────────────────────── -->
<div id="modal-quitar-consent" style="
    display:none;position:fixed;inset:0;z-index:9100;
    background:rgba(0,0,0,.55);align-items:center;justify-content:center;padding:16px">
    <div style="background:#fff;border-radius:14px;box-shadow:0 8px 40px rgba(0,0,0,.25);
                width:min(96vw,480px);padding:24px;display:flex;flex-direction:column;gap:14px">
        <div style="font-weight:700;font-size:.95rem;color:#1e293b">
            <i class="fas fa-trash me-2 text-danger"></i>Quitar consentimiento
        </div>
        <div style="font-size:.85rem;color:#475569">
            <strong id="mqc-nombre"></strong>
        </div>
        <div>
            <label style="font-size:.82rem;font-weight:600;color:#374151;display:block;margin-bottom:4px">
                Motivo <span style="color:#dc2626">*</span>
            </label>
            <textarea id="mqc-motivo" rows="3" placeholder="Explique por qué se quita este consentimiento…"
                style="width:100%;border:1px solid #d1d5db;border-radius:8px;padding:8px 10px;
                       font-size:.85rem;resize:vertical;font-family:inherit"></textarea>
            <div id="mqc-error" style="color:#dc2626;font-size:.78rem;margin-top:4px;display:none"></div>
        </div>
        <div style="display:flex;gap:8px;justify-content:flex-end">
            <button onclick="_cerrarModalQuitarConsent()"
                style="padding:7px 18px;border:1px solid #d1d5db;border-radius:8px;
                       background:#fff;cursor:pointer;font-size:.85rem">Cancelar</button>
            <button id="mqc-btn-confirmar" onclick="_confirmarQuitarConsent()"
                style="padding:7px 18px;border:none;border-radius:8px;
                       background:#dc2626;color:#fff;cursor:pointer;font-weight:600;font-size:.85rem">
                <i class="fas fa-trash me-1"></i>Quitar
            </button>
        </div>
    </div>
</div>

<!-- ── Bar encuesta post-finalizar ─────────────────────────────── -->
<div id="bar-encuesta" style="
    display:none;position:fixed;bottom:0;left:0;right:0;z-index:9100;
    background:#0f4c81;color:#fff;padding:14px 20px;
    display:none;align-items:center;gap:14px;flex-wrap:wrap;
    box-shadow:0 -4px 20px rgba(0,0,0,.25)">
    <i class="fas fa-star" style="font-size:1.2rem;color:#fbbf24;flex-shrink:0"></i>
    <span id="bar-encuesta-txt" style="flex:1;font-size:.95rem;font-weight:500"></span>
    <button onclick="_enviarEncuesta()" id="btn-enc-enviar"
            style="background:#22c55e;color:#fff;border:none;border-radius:8px;
                   padding:8px 18px;font-weight:600;cursor:pointer;white-space:nowrap">
        <i class="fas fa-paper-plane me-1"></i>Enviar encuesta
    </button>
    <button onclick="_cerrarEncuestaBar()"
            style="background:rgba(255,255,255,.15);color:#fff;border:none;border-radius:8px;
                   padding:8px 14px;cursor:pointer;white-space:nowrap">
        Omitir
    </button>
</div>

<!-- ── Modal de consentimiento embebido (modo embebido) ────────── -->
<div id="modal-consentimiento" style="
    display:none;position:fixed;inset:0;z-index:9000;
    background:rgba(0,0,0,.55);align-items:center;justify-content:center;padding:16px">
    <div style="
        background:#fff;border-radius:14px;box-shadow:0 8px 40px rgba(0,0,0,.25);
        width:min(96vw,860px);max-height:92vh;
        display:flex;flex-direction:column;overflow:hidden">
        <div style="display:flex;align-items:center;justify-content:space-between;
                    padding:12px 18px;border-bottom:1px solid #e2e8f0;flex-shrink:0">
            <span style="font-weight:700;font-size:.95rem;color:#1e293b">
                <i class="fas fa-file-signature me-2 text-primary"></i>Formulario de consentimiento
            </span>
            <button id="btn-cerrar-modal-consent" onclick="cerrarModalConsentimiento()"
                    style="background:none;border:none;font-size:1.2rem;color:#94a3b8;cursor:pointer;padding:2px 6px"
                    title="Cerrar">
                <i class="fas fa-times"></i>
            </button>
        </div>
        <div id="modal-consent-loading" style="padding:32px;text-align:center;color:#64748b;flex-shrink:0">
            <i class="fas fa-spinner fa-spin fa-2x mb-2 d-block"></i>Cargando formulario…
        </div>
        <iframe id="modal-consent-iframe" src="" frameborder="0"
                style="flex:1;border:none;display:none;min-height:60vh"
                onload="document.getElementById('modal-consent-loading').style.display='none';this.style.display='block'">
        </iframe>
    </div>
</div>


<script>
// ── Estado global ─────────────────────────────────────────────
const LUGAR_FORZADO  = <?= $lugarForzado ?: 0 ?>;
let lugarId          = <?= $lugarIdParam ?: 0 ?>;
let turnoActivo      = null;
let tieneConsent     = false;
let hayPendientes    = false;
let pollingColaId    = null;
let pollingConsentId = null;
let _consentTokenCache = null;
let _pacienteActivo  = null;
let _tomaProgresivaActiva  = false;
let hayMuestrasPendientes  = false;
let _solicitudActiva = null;
let _muestrasActivas = [];
const _formulariosList = <?= json_encode($formulariosList, JSON_UNESCAPED_UNICODE) ?>;

const API             = '<?= BASE_URL ?>modules/turnero/api/';
const BASE_WA         = '<?= BASE_URL ?>';
const LUGAR_NOMBRE    = document.getElementById('lbl-lugar-titulo')?.textContent || '<?= addslashes($lugarNombre) ?>';
const LUGAR_FORM_MODO = '<?= $lugarFormModo ?>';
const LUGAR_TIPO      = '<?= $lugarTipo ?>';
const ESP_LUGARES     = <?= json_encode(array_values($especialidades)) ?>;

// ── Arranque ──────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
    if (lugarId) iniciarPuesto();
});

function iniciarPuesto() {
    recuperarTurnoActivo();
    cargarCola();
    _cargarEspecialidades();
    pollingColaId = setInterval(cargarCola, 7000);
    setInterval(_cargarEspecialidades, 30000);

    document.addEventListener('visibilitychange', () => {
        if (document.hidden) {
            clearInterval(pollingColaId);
            clearInterval(pollingConsentId);
            pollingColaId = pollingConsentId = null;
        } else if (lugarId) {
            cargarCola();
            _cargarEspecialidades();
            pollingColaId = setInterval(cargarCola, 7000);
        }
    });

    document.addEventListener('keydown', e => {
        if (e.key === 'Escape' && lugarId &&
            document.getElementById('overlay-selector').style.display !== 'none') {
            document.getElementById('overlay-selector').style.display = 'none';
        }
    });
}

async function recuperarTurnoActivo() {
    try {
        const res  = await fetch(`${API}get_cola.php?area=lugar&lugar_id=${lugarId}`);
        const json = await res.json();
        if (json.ok && json.activo) await abrirFicha(json.activo);
    } catch (_) {}
}

// ── Selector de lugar ─────────────────────────────────────────
function confirmarLugar() {
    const sel = document.getElementById('sel-lugar-init');
    const id  = parseInt(sel.value);
    if (!id) return mostrarError('Seleccione un lugar.');
    if (LUGAR_FORZADO && id !== LUGAR_FORZADO) return mostrarError('No tiene acceso a esa estación.');
    lugarId = id;
    const txt = sel.options[sel.selectedIndex].text;
    document.getElementById('lbl-lugar-titulo').textContent = txt;
    document.getElementById('overlay-selector').style.display = 'none';
    document.title = txt + ' — Turnero';
    iniciarPuesto();
}

function cambiarLugar() {
    clearInterval(pollingColaId);
    clearInterval(pollingConsentId);
    turnoActivo = null;
    resetFicha();
    document.getElementById('btn-cancelar-selector').style.display = '';
    document.getElementById('overlay-selector').style.display = 'flex';
}

// ── Cola ──────────────────────────────────────────────────────
async function cargarCola() {
    if (!lugarId) return;
    try {
        const res  = await fetch(`${API}get_cola.php?area=lugar&lugar_id=${lugarId}`);
        const json = await res.json();
        if (!json.ok) return;
        renderCola(json);
    } catch (_) {}
}

let _colaMap = new Map();

function tiempoEspera(iso) {
    if (!iso) return null;
    const mins = Math.floor((Date.now() - new Date(iso).getTime()) / 60000);
    if (mins < 1)  return { txt: 'recién',  cls: 'ok' };
    if (mins < 10) return { txt: mins + ' min', cls: 'ok' };
    if (mins < 25) return { txt: mins + ' min', cls: 'warn' };
    return { txt: mins + ' min', cls: 'crit' };
}

function renderCola(snap) {
    _renderEsperaMuestras(snap.en_espera_muestra || []);
    const items    = snap.cola || [];
    const enEspera = items.filter(t => t.estado === 'en_espera_lugar');
    const enServ   = items.filter(t => t.estado === 'en_servicio');

    document.getElementById('badge-count').textContent = enEspera.length + ' espera';
    const badgeServ = document.getElementById('badge-servicio');
    if (enServ.length) {
        badgeServ.textContent = enServ.length + ' servicio';
        badgeServ.classList.remove('d-none');
    } else {
        badgeServ.classList.add('d-none');
    }

    _colaMap = new Map(items.map(t => [t.id, t]));

    const lista = document.getElementById('cola-items');
    if (!items.length) {
        lista.innerHTML = `<div class="cola-vacia">
            <i class="fas fa-hourglass-start fa-2x mb-2 d-block"></i>Cola vacía</div>`;
        return;
    }

    let html = '';
    if (enServ.length) {
        html += `<div class="cola-section-sep"><i class="fas fa-stethoscope me-1"></i>En servicio</div>`;
        html += enServ.map(t => renderColaCard(t)).join('');
    }
    if (enEspera.length) {
        if (enServ.length) html += `<div class="cola-section-sep" style="margin-top:.4rem"><i class="fas fa-clock me-1"></i>En espera</div>`;
        html += enEspera.map(t => renderColaCard(t)).join('');
    }
    lista.innerHTML = html;
}

function renderColaCard(t) {
    const enServicio  = t.estado === 'en_servicio';
    const esActivo    = turnoActivo?.id == t.id;
    const esMuestra   = t.solo_muestras == 1;
    const enTomaProg  = t.en_toma_progresiva == 1;
    const sigTomaAt   = t.siguiente_toma_at || null;

    const tiempo = tiempoEspera(t.creado_at);
    const tiempoBadge = tiempo
        ? `<span class="tiempo-chip ${tiempo.cls}">${escHtml(tiempo.txt)}</span>`
        : '';
    const muestraBadge = esMuestra
        ? `<span class="muestra-chip"><i class="fas fa-plus me-1"></i>MUESTRAS</span>`
        : '';
    const tomaBadge = enTomaProg
        ? `<span class="toma-prog-chip ok" data-toma-at="${escHtml(sigTomaAt || '')}" data-turno-id="${t.id}">
               <i class="fas fa-syringe me-1"></i><span class="toma-cd-txt">${sigTomaAt ? '...' : '¡Ahora!'}</span>
           </span>`
        : '';
    const badgeRow = (tiempoBadge || muestraBadge || tomaBadge)
        ? `<div class="t-badge-row">${tiempoBadge}${muestraBadge}${tomaBadge}</div>`
        : '';

    const rightEl = enServicio
        ? `<div class="card-en-servicio-pill"><i class="fas fa-stethoscope"></i>EN<br>SERV.</div>`
        : `<button onclick="event.stopPropagation();llamarTurnoEspecifico(${t.id})"
                   title="Anunciar turno ${escHtml(t.codigo)}" class="card-bell-btn">
               <i class="fas fa-bell"></i>
           </button>`;

    let bg = esMuestra ? 'border:2px solid #ea580c!important;background:#fff7ed!important' : '';
    const prioBg  = esMuestra ? '#ea580c' : (t.prioridad_color || '#6366f1');
    const prioLbl = esMuestra ? '<i class="fas fa-plus"></i>' : escHtml(t.prioridad_codigo || '?');
    const tomaClass = enTomaProg ? ' toma-prog' : '';

    return `<div class="cola-card ${enServicio ? 'en-servicio-card' : ''} ${esActivo ? 'activo' : ''}${tomaClass}"
                 style="${bg}" onclick="seleccionarSinLlamar(${t.id})">
        <div class="prio-dot" style="background:${prioBg}">${prioLbl}</div>
        <div class="turno-info">
            <div class="cod">${escHtml(t.codigo)}</div>
            <div class="pac">${escHtml(t.paciente_nombre || 'Paciente')}</div>
            ${badgeRow}
        </div>
        ${rightEl}
    </div>`;
}

// ── Seleccionar sin llamar ────────────────────────────────────
async function seleccionarSinLlamar(turnoId) {
    let t = _colaMap.get(turnoId);
    if (!t) {
        // Turno no está en cola (p.ej. en espera de siguiente toma) — cargar directamente
        try {
            const r = await fetch(`${API}get_turno.php?id=${turnoId}`);
            const j = await r.json();
            if (!j.ok || !j.turno) return;
            t = j.turno;
        } catch (_) { return; }
    }
    turnoActivo = t;
    mostrarCabeceraTurno(t);
    await cargarFichaSolicitud(t.id);
    clearInterval(pollingConsentId);
    // También para solo entrega de muestras: a esos turnos les corresponde el
    // formulario del puesto, así que la lista tiene que refrescarse igual o al
    // firmar no se vería el cambio.
    pollingConsentId = setInterval(() => actualizarConsentimientos(turnoActivo?.id), 5000);
    if (LUGAR_FORM_MODO === 'embebido' && lugarId)
        cargarFormEmbebido(t.id);
    mostrarFichaMobile();
}

// ── Llamar ────────────────────────────────────────────────────
async function llamarSiguiente()              { await _llamar({}); }
async function llamarTurnoEspecifico(turnoId) { await _llamar({ turno_id: turnoId }); }

async function _llamar(extra) {
    if (!lugarId) { mostrarError('Primero seleccione un lugar.'); return; }
    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: 'lugar', lugar_id: lugarId, ...extra }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        if (!json.turno) { mostrarToast('Cola vacía — no hay turnos en espera.', 'warn', 3000); return; }
        mostrarLlamando(json.turno.codigo);
        await abrirFicha(json.turno);
        cargarCola();
    } catch (err) {
        mostrarError(err.message);
    } finally {
        btn.disabled = false;
    }
}

// ── Abrir ficha ───────────────────────────────────────────────
function _esSoloEntrega(turno) {
    return turno.solo_muestras == 1 || turno.prioridad_codigo === 'F';
}

async function abrirFicha(turno) {
    turnoActivo = turno;
    mostrarCabeceraTurno(turno);
    await cargarFichaSolicitud(turno.id);
    clearInterval(pollingConsentId);
    pollingConsentId = setInterval(() => actualizarConsentimientos(turnoActivo?.id), 5000);
    if (LUGAR_FORM_MODO === 'embebido' && lugarId)
        cargarFormEmbebido(turno.id);
    mostrarFichaMobile();
}

function mostrarCabeceraTurno(turno) {
    document.getElementById('ficha-placeholder').classList.add('d-none');
    const fichaEl = document.getElementById('ficha-turno');
    fichaEl.classList.remove('d-none');
    fichaEl.style.display = 'flex';

    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  || '#6366f1';

    const badgeCod = document.getElementById('badge-turno-activo');
    badgeCod.textContent = turno.codigo;
    badgeCod.classList.remove('d-none');

    const nomHdr = document.getElementById('ficha-pac-nombre-hdr');
    nomHdr.textContent = '';
    nomHdr.classList.add('loading');

    document.getElementById('ficha-mobile-cod').textContent = turno.codigo;

    actualizarEstadoBadge(turno.estado);
}

// ── Cargar solicitud ──────────────────────────────────────────
async function cargarFichaSolicitud(turnoId) {
    try {
        const res  = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}&incluir_solicitud=1`);
        const json = await res.json();
        if (!json.ok) return;

        const sol   = json.solicitud;
        const pac   = json.paciente;
        _solicitudActiva = sol || null;

        // Número de orden (F-... azul, D-... verde)
        const ordenEl    = document.getElementById('ficha-orden');
        const ordenValEl = document.getElementById('ficha-orden-val');
        if (sol && sol.numero_orden) {
            ordenValEl.textContent = sol.numero_orden;
            const isDom = sol.numero_orden.startsWith('D-');
            ordenEl.style.background   = isDom ? '#f0fdf4' : '#eff6ff';
            ordenEl.style.color        = isDom ? '#15803d' : '#1d4ed8';
            ordenEl.style.borderColor  = isDom ? '#86efac' : '#bfdbfe';
            ordenEl.classList.remove('d-none');
        } else {
            ordenEl.classList.add('d-none');
        }
        const exams = json.examenes || [];
        const consts = json.consentimientos || [];

        // Nombre en el header
        const nomHdr = document.getElementById('ficha-pac-nombre-hdr');
        nomHdr.classList.remove('loading');
        nomHdr.textContent = pac ? (pac.nombre_completo || pac.full_name || '—') : '—';

        // Badge solo entrega de muestras
        const esSoloMuestras = !!(sol && sol.solo_muestras == 1);
        document.getElementById('badge-solo-muestras')?.classList.toggle('d-none', !esSoloMuestras);

        // La sección de formularios ya NO se esconde por ser solo entrega de
        // muestras. Esos turnos no traen exámenes, pero sí les corresponde el
        // formulario del puesto (F-LAB-08, Datos Toma de Muestras): el backend
        // se lo venía creando y la interfaz lo ocultaba, así que se acumulaban
        // creados y sin firmar. Quién se muestra lo decide renderConsentimientos
        // según lo que realmente haya que llenar.
        const secConsent = document.getElementById('sec-consent');
        const secForm    = document.getElementById('sec-form-embebido');
        if (secConsent) secConsent.classList.remove('d-none');
        if (secForm)    secForm.classList.add('d-none');

        // Embarazada
        const badgeEmb = document.getElementById('pac-embarazada');
        if (badgeEmb) badgeEmb.classList.toggle('d-none', !(sol && sol.embarazada == 1));

        // Médico
        const medDiv = document.getElementById('pac-medico');
        if (medDiv) {
            const tieneMedico = sol && sol.medico_nombre;
            medDiv.classList.toggle('d-none', !tieneMedico);
            if (tieneMedico) {
                const esp = sol.medico_especialidad ? ' · ' + sol.medico_especialidad : '';
                document.getElementById('pac-medico-nombre').textContent = sol.medico_nombre + esp;
            }
        }

        // Nota de recepción
        const obsEl = document.getElementById('pac-obs-recepcion');
        if (obsEl) {
            const obs = sol?.observaciones?.trim();
            obsEl.classList.toggle('d-none', !obs);
            if (obs) document.getElementById('pac-obs-recepcion-texto').textContent = obs;
        }

        if (pac) {
            _pacienteActivo = pac;
            document.getElementById('bloque-pac-info').style.display = '';
            document.getElementById('bloque-pac-sin').classList.add('d-none');
            document.getElementById('pac-nombre').textContent =
                pac.nombre_completo || pac.full_name || '—';
            document.getElementById('pac-doc').textContent =
                ((pac.tipo_documento || '') + ' ' + (pac.numero_documento || pac.documento || '')).trim() || '—';
            document.getElementById('pac-fec').textContent = pac.fecha_nacimiento || '—';
            document.getElementById('pac-cel').textContent = pac.telefono || pac.celular || '—';
            document.getElementById('btn-ver-paciente').classList.remove('d-none');
        } else {
            _pacienteActivo = null;
            document.getElementById('bloque-pac-info').style.display = 'none';
            document.getElementById('bloque-pac-sin').classList.remove('d-none');
            document.getElementById('btn-ver-paciente').classList.add('d-none');
        }

        // Exámenes
        const listaEx = document.getElementById('lista-examenes-ficha');
        if (exams.length) {
            listaEx.innerHTML = exams.map(e =>
                `<span class="exam-pill"><i class="fas fa-vial"></i>${escHtml(e.codigo)} ${escHtml(e.nombre)}</span>`
            ).join('');
        } else {
            listaEx.innerHTML = '<span class="text-muted small">Sin exámenes registrados</span>';
        }

        renderConsentimientos(consts);
        renderMuestras(json.muestras || []);
        cargarComentarios(turnoId);
        draftRestaurar(turnoId);
        cargarTomasPrevias(turnoId);

    } catch (_) {}
}

// ── Consentimientos ───────────────────────────────────────────
const CONSENT_IC = {
    firmado:'fa-check-circle', rechazado:'fa-ban',
    enviado:'fa-envelope', visto:'fa-eye', pendiente:'fa-clock',
    en_progreso:'fa-hourglass-half',
    cerrado_anticipado:'fa-exclamation-triangle',
};
const CONSENT_LBL = {
    firmado:'Firmado', rechazado:'Rechazado', enviado:'Enviado', visto:'Visto', pendiente:'Pendiente',
    en_progreso:'En progreso', cerrado_anticipado:'Cerrado anticipadamente',
};

// ── Countdown en tarjetas de cola (toma progresiva) ──────────
const _tomaAlertados = new Set();
let   _bannerTurnoId  = null;

function _playAlarmaLugar() {
    try {
        const ctx = new (window.AudioContext || window.webkitAudioContext)();
        // 3 pulsos: grave-agudo, gain máximo, 0.3s cada tono
        [440, 880, 440, 880, 440, 880].forEach(function(freq, i) {
            const osc = ctx.createOscillator(), gain = ctx.createGain();
            osc.connect(gain); gain.connect(ctx.destination);
            osc.frequency.value = freq;
            const t0 = ctx.currentTime + i * 0.32;
            gain.gain.setValueAtTime(1.0, t0);
            gain.gain.exponentialRampToValueAtTime(0.001, t0 + 0.28);
            osc.start(t0); osc.stop(t0 + 0.28);
        });
    } catch(e) {}
}

let _alarmaInterval = null;

function verPacienteToma() {
    cerrarBannerToma();
    if (_bannerTurnoId) seleccionarSinLlamar(_bannerTurnoId);
}
function cerrarBannerToma() {
    const b = document.getElementById('banner-toma-alerta');
    if (b) b.classList.remove('show');
    clearInterval(_alarmaInterval);
    _alarmaInterval = null;
}

setInterval(function() {
    const ahora = Date.now();
    document.querySelectorAll('.toma-prog-chip[data-toma-at]').forEach(function(chip) {
        const at      = chip.dataset.tomaAt;
        const turnoId = chip.dataset.turnoId ? parseInt(chip.dataset.turnoId) : null;
        const txt     = chip.querySelector('.toma-cd-txt');
        if (!at || !txt) return;
        const diff = Math.floor((new Date(at.replace(' ','T')).getTime() - ahora) / 1000);
        const card = chip.closest('.cola-card');
        if (diff <= 0) {
            txt.textContent = '¡Ahora!';
            chip.className = 'toma-prog-chip crit';
            if (card) card.classList.add('crit-card');
            // Alerta única por turno
            if (turnoId && !_tomaAlertados.has(turnoId)) {
                _tomaAlertados.add(turnoId);
                _bannerTurnoId = turnoId;
                const pacNombre = card?.querySelector('.pac')?.textContent || 'Paciente';
                const banner = document.getElementById('banner-toma-alerta');
                const bannerTxt = document.getElementById('banner-toma-txt');
                if (banner && bannerTxt) {
                    bannerTxt.textContent = '¡Hora de la siguiente muestra! — ' + pacNombre;
                    banner.classList.add('show');
                }
                _playAlarmaLugar();
                if (navigator.vibrate) navigator.vibrate([400, 150, 400, 150, 400]);
                clearInterval(_alarmaInterval);
                _alarmaInterval = setInterval(function() {
                    const b = document.getElementById('banner-toma-alerta');
                    if (b && b.classList.contains('show')) {
                        _playAlarmaLugar();
                        if (navigator.vibrate) navigator.vibrate([400, 150, 400, 150, 400]);
                    } else {
                        clearInterval(_alarmaInterval);
                        _alarmaInterval = null;
                    }
                }, 30000);
            }
        } else {
            // Si el tiempo se actualizó (nueva toma programada), resetear la alerta
            if (turnoId) _tomaAlertados.delete(turnoId);
            const m = Math.floor(diff / 60), s = diff % 60;
            txt.textContent = m + ':' + String(s).padStart(2,'0');
            chip.className = diff < 120 ? 'toma-prog-chip warn' : 'toma-prog-chip ok';
            if (card) card.classList.remove('crit-card');
        }
    });
}, 1000);

// ── Tomas progresivas: actualiza countdowns cada segundo ──────
let _tomaTimers = {};  // consent_id → { siguiente_toma_at, es_alerta }
setInterval(() => {
    const ahora = Date.now();
    for (const [cid, info] of Object.entries(_tomaTimers)) {
        const row = document.querySelector(`[data-consent-id="${cid}"]`);
        if (!row) continue;
        const cdEl = row.querySelector('.toma-countdown');
        if (!cdEl) continue;
        if (!info.siguiente_toma_at) { cdEl.textContent = ''; continue; }
        const diff = Math.floor((info.siguiente_toma_at - ahora) / 1000);
        if (diff <= 0) {
            cdEl.textContent = '¡Hora de toma!';
            row.classList.add('alerta');
            if (!info.alertado) {
                info.alertado = true;
                _playAlarmaLugar();
            }
        } else {
            row.classList.remove('alerta');
            const m = Math.floor(diff / 60), s = diff % 60;
            cdEl.textContent = `próx. toma en ${m}:${String(s).padStart(2,'0')}`;
        }
    }
}, 1000);

function _syncBtnFinalizar() {
    const btnFin    = document.getElementById('btn-finalizar');
    const warnStrip = document.getElementById('accion-consent-warn');
    const warnTxt   = document.getElementById('accion-warn-txt');
    const bloqueado = hayPendientes || hayMuestrasPendientes;
    if (btnFin) btnFin.disabled = bloqueado;
    if (!warnStrip || !warnTxt) return;
    if (bloqueado) {
        const msgs = [];
        if (hayPendientes)        msgs.push('consentimientos pendientes');
        if (hayMuestrasPendientes) msgs.push('muestras sin decisión');
        warnTxt.textContent = msgs.join(' · ');
        warnStrip.classList.remove('d-none');
    } else {
        warnStrip.classList.add('d-none');
    }
}

function renderConsentimientos(lista) {
    // Mostrar consentimientos de examen (origen null) + los de esta estación
    lista = lista.filter(c => !c.origen_lugar_id || c.origen_lugar_id == lugarId);
    tieneConsent  = lista.length > 0;
    hayPendientes = !_esSoloEntrega(turnoActivo) &&
                   lista.some(c => !['firmado','rechazado','cerrado_anticipado'].includes(c.estado));
    // en_progreso bloquea finalizar pero no muestra aviso de "pendiente sin acción"
    const pendCount = lista.filter(c => ['pendiente','enviado','visto'].includes(c.estado)).length;

    const listEl = document.getElementById('lista-consent');
    const sinEl  = document.getElementById('sin-consent');
    const banner = document.getElementById('bloqueo-banner');
    const btnFin = document.getElementById('btn-finalizar');

    _syncBtnFinalizar();

    if (!tieneConsent) {
        listEl.innerHTML = '';
        sinEl.classList.remove('d-none');
        banner.classList.add('d-none');
        return;
    }

    sinEl.classList.add('d-none');
    banner.classList.toggle('d-none', !hayPendientes);

    // Actualizar mapa de timers para tomas progresivas (preservar alertado si ya sonó)
    const _prevTimers = _tomaTimers;
    _tomaTimers = {};
    lista.forEach(c => {
        if (c.es_toma_progresiva && c.estado === 'en_progreso') {
            const prev = _prevTimers[c.id];
            const newAt = c.siguiente_toma_at ? new Date(c.siguiente_toma_at.replace(' ', 'T')).getTime() : null;
            // Si la siguiente_toma_at cambió (firmó una toma), resetear alertado para el nuevo tiempo
            const sameTime = prev && prev.siguiente_toma_at === newAt;
            _tomaTimers[c.id] = {
                siguiente_toma_at: newAt,
                alertado: sameTime ? (prev.alertado || false) : false,
            };
        }
    });
    // Mostrar botón "Mandar a espera" si hay toma progresiva activa y estado en_servicio
    const btnEsp = document.getElementById('btn-espera');
    if (btnEsp) {
        const hasProg = Object.keys(_tomaTimers).length > 0;
        btnEsp.classList.toggle('d-none', !(hasProg && turnoActivo?.estado === 'en_servicio'));
    }

    listEl.innerHTML = lista.map(c => {
        const ya    = ['firmado','rechazado','cerrado_anticipado'].includes(c.estado);
        const ico   = CONSENT_IC[c.estado]  || 'fa-clock';
        const label = CONSENT_LBL[c.estado] || c.estado;
        const token = escHtml(c.token || '');
        const nomJs = JSON.stringify(c.formulario_nombre || 'Consentimiento');
        const idJs  = parseInt(c.id) || 0;
        const tId   = parseInt(c.turno_id) || (turnoActivo?.id) || 0;
        const fId   = parseInt(c.formulario_id) || 0;

        // Badge de progreso para tomas progresivas
        let progresoBadge = '';
        if (c.es_toma_progresiva && c.tomas_total > 0) {
            progresoBadge = `<span class="toma-progreso">${c.tomas_firmadas}/${c.tomas_total}</span>`;
        }
        const countdownEl = (c.es_toma_progresiva && c.estado === 'en_progreso')
            ? `<span class="toma-countdown"></span>` : '';

        // Botón ver
        const btnVer = (ya && c.token)
            ? `<button class="btn btn-outline-secondary" title="Ver firmado"
                  onclick="_abrirModalConToken('${token}')">
                  <i class="fas fa-eye"></i> Ver
               </button>` : '';

        // Acción de firma según modo
        let btnAccion = '';
        const puedeFirmar = !ya || (c.es_toma_progresiva && c.estado === 'en_progreso');
        if (puedeFirmar && c.token) {
            if (c.es_toma_progresiva) {
                // Toma progresiva: siempre abre el modal embebido para firmar la siguiente toma
                btnAccion = `<button class="btn btn-primary" title="Registrar siguiente toma"
                               onclick="abrirTomaProgresiva('${token}', ${tId}, ${fId})">
                               <i class="fas fa-flask me-1"></i>Siguiente toma
                             </button>`;
            } else if (LUGAR_FORM_MODO === 'embebido') {
                const lblAccion = c.requiere_firma_paciente ? 'Firmar' : 'Completar';
                btnAccion = `<button class="btn btn-primary" title="Abrir formulario"
                               onclick="abrirModalConsentimientoPorToken('${token}')">
                               <i class="fas fa-pen me-1"></i>${lblAccion}
                             </button>`;
            } else {
                btnAccion = `<button class="btn btn-outline-primary" title="Firmar aquí"
                               onclick="abrirFirmaPresencial('${token}', ${idJs}, ${nomJs.replace(/"/g,'&quot;')})">
                               <i class="fas fa-signature"></i> Firmar
                             </button>
                             ${c.requiere_firma_paciente ? `<button class="btn btn-outline-success" title="Reenviar por WhatsApp"
                               onclick="reenviarConsentimiento(${tId})">
                               <i class="fab fa-whatsapp"></i> WA
                             </button>` : ''}`;
            }
        }

        const btnQuitar = `<button class="btn btn-outline-danger" title="Quitar consentimiento"
            onclick="_abrirModalQuitarConsent(${idJs}, ${nomJs.replace(/"/g,'&quot;')})">
            <i class="fas fa-trash"></i>
        </button>`;

        const btnOlvidar = (ya && c.token && c.estado !== 'rechazado')
            ? `<button class="btn btn-outline-warning" title="Olvidar firma — permite re-firmar"
                  onclick="_olvidarConsentimiento('${token}', ${nomJs.replace(/"/g,'&quot;')})">
                  <i class="fas fa-undo"></i>
               </button>` : '';

        const motivoRow = (c.estado === 'cerrado_anticipado' && c.cierre_anticipado?.motivo)
            ? `<div style="font-size:.75rem;color:#92400e;background:#fef3c7;border-radius:4px;padding:3px 8px;margin-top:3px;width:100%">
                   <i class="fas fa-comment-alt me-1"></i>${escHtml(c.cierre_anticipado.motivo)}
               </div>` : '';
        return `<div class="consent-row ${c.estado}" data-consent-id="${c.id}" style="flex-wrap:wrap">
            <div style="display:flex;align-items:center;gap:.4rem;width:100%">
                <i class="fas ${ico}"></i>
                <span class="nom-form">${escHtml(c.formulario_nombre || 'Consentimiento')}</span>
                ${progresoBadge}
                ${countdownEl}
                <span class="c-badge">${label}</span>
                <div class="acciones-consent">${btnAccion}${btnVer}${btnOlvidar}${btnQuitar}</div>
            </div>
            ${motivoRow}
        </div>`;
    }).join('');
}

// ── Olvidar (resetear) consentimiento ────────────────────────
async function _olvidarConsentimiento(token, nombre) {
    if (!confirm(`¿Seguro que deseas descartar la firma de "${nombre}"?\nEl paciente podrá volver a firmarlo.`)) return;
    try {
        const r = await fetch(API + 'resetear_consentimiento.php', {
            method: 'POST', headers: {'Content-Type':'application/json'},
            body: JSON.stringify({ token })
        });
        const j = await r.json();
        if (!j.ok) { mostrarError(j.error || 'Error al resetear'); return; }
        if (turnoActivo?.id) actualizarConsentimientos(turnoActivo.id);
    } catch(e) { mostrarError(e.message); }
}

// ── Quitar consentimiento ─────────────────────────────────────
let _mqcConsentId = null;
function _abrirModalQuitarConsent(consentId, formNombre) {
    _mqcConsentId = consentId;
    document.getElementById('mqc-nombre').textContent = formNombre;
    document.getElementById('mqc-motivo').value = '';
    document.getElementById('mqc-error').style.display = 'none';
    document.getElementById('modal-quitar-consent').style.display = 'flex';
    setTimeout(() => document.getElementById('mqc-motivo').focus(), 50);
}
function _cerrarModalQuitarConsent() {
    document.getElementById('modal-quitar-consent').style.display = 'none';
    _mqcConsentId = null;
}
async function _confirmarQuitarConsent() {
    const motivo = document.getElementById('mqc-motivo').value.trim();
    const errEl  = document.getElementById('mqc-error');
    if (!motivo) { errEl.textContent = 'El motivo es obligatorio.'; errEl.style.display = ''; return; }
    const btn = document.getElementById('mqc-btn-confirmar');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Quitando…';
    try {
        const res  = await fetch(`${API}quitar_consentimiento.php`, {
            method: 'POST',
            headers: {'Content-Type':'application/json'},
            body: JSON.stringify({consent_id: _mqcConsentId, motivo})
        });
        const json = await res.json();
        if (!json.ok) { errEl.textContent = json.error || 'Error al quitar.'; errEl.style.display = ''; }
        else {
            _cerrarModalQuitarConsent();
            if (turnoActivo?.id) actualizarConsentimientos(turnoActivo.id);
        }
    } catch(e) { errEl.textContent = 'Error de red.'; errEl.style.display = ''; }
    btn.disabled = false;
    btn.innerHTML = '<i class="fas fa-trash me-1"></i>Quitar';
}

async function actualizarConsentimientos(turnoId) {
    if (!turnoId) return;
    try {
        const res  = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (!json.ok) return;
        renderConsentimientos(json.consentimientos || []);
    } catch (_) {}
}

// ── Tomas progresivas pendientes de visita anterior ──────────
async function cargarTomasPrevias(turnoId) {
    const sec  = document.getElementById('sec-tomas-prev');
    const list = document.getElementById('lista-tomas-prev');
    sec.style.display = 'none';
    list.innerHTML    = '';
    if (!turnoId) return;
    try {
        const res  = await fetch(`${API}get_tomas_pendientes_paciente.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (!json.ok || !json.tomas?.length) return;
        list.innerHTML = json.tomas.map(t => {
            const token  = escHtml(t.token || '');
            const fNom   = escHtml(t.formulario_nombre || 'Toma');
            const turno  = escHtml(t.turno_codigo || '');
            const fecha  = t.turno_fecha ? escHtml(t.turno_fecha.slice(0,10)) : '';
            const prog   = t.tomas_total > 0
                ? `<span class="toma-progreso">${t.tomas_firmadas}/${t.tomas_total}</span>` : '';
            return `<div class="toma-prev-row" data-consent-id="${t.id}" data-turno-id="${t.turno_id}">
                <i class="fas fa-hourglass-half"></i>
                <span class="nom-form">${fNom}</span>
                ${prog}
                <span class="c-badge" style="font-size:.65rem;opacity:.7">Turno ${turno} · ${fecha}</span>
                <div class="acciones-consent">
                    <button class="btn btn-primary" onclick="abrirTomaProgresiva('${token}',${t.turno_id},0)">
                        <i class="fas fa-flask me-1"></i>Continuar
                    </button>
                    <button class="btn btn-outline-secondary" title="Paciente no quiere continuar"
                            onclick="cancelarTomaPrevia(${t.id}, this)">
                        <i class="fas fa-ban me-1"></i>Cancelar
                    </button>
                </div>
            </div>`;
        }).join('');
        sec.style.display = '';
    } catch (e) { mostrarError('No se pudieron cargar tomas previas: ' + e.message); }
}

async function cancelarTomaPrevia(consentId, btn) {
    if (!confirm('¿El paciente no quiere continuar la toma? Se marcará como cancelada.')) return;
    btn.disabled = true;
    const row     = document.querySelector(`.toma-prev-row[data-consent-id="${consentId}"]`);
    const oldTId  = row ? parseInt(row.dataset.turnoId) : 0;
    try {
        const res  = await fetch(`${API}cancelar_toma_pendiente.php`, {
            method:  'POST',
            headers: { 'Content-Type': 'application/json' },
            body:    JSON.stringify({ consentimiento_id: consentId, turno_id: turnoActivo?.id }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); btn.disabled = false; return; }
        if (oldTId) _tomaAlertados.delete(oldTId);
        if (row) row.remove();
        const list = document.getElementById('lista-tomas-prev');
        if (list && !list.children.length) document.getElementById('sec-tomas-prev').style.display = 'none';
    } catch (e) { mostrarError(e.message); btn.disabled = false; }
}

async function reenviarConsentimiento(turnoId) {
    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; }
        await actualizarConsentimientos(turnoId);
    } catch (err) {
        mostrarError(err.message);
    }
}

async function abrirFirmaPresencial(token, consentId, nombreForm) {
    try {
        const res = await fetch(API + 'crear_envio_presencial.php', {
            method:  'POST',
            headers: { 'Content-Type': 'application/json' },
            body:    JSON.stringify({ consent_token: token }),
        });
        const json = await res.json();
        if (!json.ok || !json.form_token) throw new Error(json.error || 'Error al crear envío');
        window.open(BASE_WA + 'form_cliente.php?t=' + encodeURIComponent(json.form_token), '_blank');
    } catch (err) {
        alert('No se pudo abrir el formulario: ' + err.message);
    }
}

// ── Modal de consentimiento embebido ─────────────────────────
function _abrirModalConToken(token) {
    const modal  = document.getElementById('modal-consentimiento');
    const iframe = document.getElementById('modal-consent-iframe');
    const load   = document.getElementById('modal-consent-loading');
    iframe.style.display = 'none';
    iframe.src   = '';
    load.style.display = '';
    modal.style.display = 'flex';
    setTimeout(() => {
        iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(token)}&embed=1&compact=1&zoom=1.1`;
    }, 80);
}

function abrirModalConsentimientoPorToken(token) {
    _abrirModalConToken(token);
}

// ── Toma progresiva: abre el modal con modo especial ──────────
function abrirTomaProgresiva(token, turnoId, formularioId) {
    cerrarBannerToma();
    _tomaAlertados.delete(turnoId);
    const modal  = document.getElementById('modal-consentimiento');
    const iframe = document.getElementById('modal-consent-iframe');
    const load   = document.getElementById('modal-consent-loading');
    iframe.style.display = 'none';
    iframe.src   = '';
    load.style.display = '';
    modal.style.display = 'flex';
    _tomaProgresivaActiva = true;
    _setBtnCerrarConsent(true);
    setTimeout(() => {
        iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(token)}&embed=1&compact=1&modo=toma_progresiva&zoom=1.1`;
    }, 80);
}

function _setBtnCerrarConsent(habilitado) {
    const btn = document.getElementById('btn-cerrar-modal-consent');
    if (!btn) return;
    btn.disabled      = !habilitado;
    btn.style.opacity = habilitado ? '' : '.25';
    btn.title         = habilitado ? 'Cerrar' : 'Cerrando...';
}

function cerrarModalConsentimiento(forzar) {
    _tomaProgresivaActiva = false;
    _setBtnCerrarConsent(true);
    const modal  = document.getElementById('modal-consentimiento');
    const iframe = document.getElementById('modal-consent-iframe');
    modal.style.display = 'none';
    iframe.src = '';
    iframe.style.display = 'none';
    document.getElementById('modal-consent-loading').style.display = '';
    if (turnoActivo) actualizarConsentimientos(turnoActivo.id);
}

var _mpParentCdTimer = null;
function _mpParentNotificar(lbl) {
    if ('Notification' in window && Notification.permission === 'granted') {
        new Notification('⏰ Toma de muestras', { body: lbl || '¡Siguiente muestra!', icon: '/favicon.ico', requireInteraction: true });
    }
}
function _mpParentCancelCd() {
    if (_mpParentCdTimer) { clearInterval(_mpParentCdTimer); _mpParentCdTimer = null; }
}

window.addEventListener('message', function(e) {
    // El formulario embebido pide corregir la ficha del paciente: se abre el
    // modal directamente en modo edición, sin cerrar el formulario.
    if (e.data && e.data.type === 'corregirPaciente') {
        if (!_pacienteActivo) return;
        abrirModalPaciente();
        mpacEditar(true);
        return;
    }
    if (e.data && e.data.type === 'tomaProgresivaIniciada') {
        _tomaProgresivaActiva = true;
        if ('Notification' in window && Notification.permission === 'default') Notification.requestPermission();
        // Countdown en el padre para que sobreviva si el modal se cierra
        _mpParentCancelCd();
        if (e.data.targetMs) {
            var _pTarget = e.data.targetMs, _pLabel = e.data.label || '';
            _mpParentCdTimer = setInterval(function() {
                if (Date.now() >= _pTarget) {
                    _mpParentCancelCd();
                    _mpParentNotificar(_pLabel);
                }
            }, 5000);
        }
    }
    if (e.data && e.data.type === 'tomaProgresivaAlerta') {
        // El iframe ya disparó la alerta — cancelar el del padre para no duplicar
        _mpParentCancelCd();
        _mpParentNotificar(e.data.label || '');
    }
    if (e.data && e.data.type === 'turneroFirmado') {
        _mpParentCancelCd();
        _tomaProgresivaActiva = false;
        _setBtnCerrarConsent(true);
        cerrarModalConsentimiento(true);
        cerrarBannerToma();
        _tomaAlertados.clear();
        mostrarToast('Tomas completadas ✓', 'success', 3000);
        if (turnoActivo) {
            actualizarConsentimientos(turnoActivo.id);
            cargarTomasPrevias(turnoActivo.id); // limpia fila completada del turno anterior
        }
    }
});

// ── Formulario embebido (iframe, modo link) ───────────────────
async function cargarFormEmbebido(turnoId) {
    if (LUGAR_FORM_MODO === 'embebido') return; // token llega vía renderConsentimientos → modal
    const sec    = document.getElementById('sec-form-embebido');
    const iframe = document.getElementById('form-embebido-iframe');
    const load   = document.getElementById('form-embebido-loading');
    if (!sec || !iframe) return;
    sec.classList.remove('d-none');
    iframe.style.display = 'none';
    load.style.display   = '';
    try {
        const res  = await fetch(`${API}get_consent_token.php?turno_id=${turnoId}&lugar_id=${lugarId}`);
        const json = await res.json();
        if (json.ok && json.token) {
            iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(json.token)}`;
        } else {
            load.innerHTML = '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>' + escHtml(json.error || 'No hay formulario configurado') + '</span>';
        }
    } catch (e) {
        load.innerHTML = '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>Error al cargar formulario</span>';
    }
}

// ── Acciones del turno ────────────────────────────────────────
async function iniciarAtencion() {
    if (!turnoActivo) return;
    await _llamar({ turno_id: turnoActivo.id });
    // Si _llamar no actualizó el estado (fallo silencioso), recuperar desde el servidor
    if (turnoActivo && turnoActivo.estado !== 'en_servicio') {
        await recuperarTurnoActivo();
    }
}

async function finalizarAtencion() {
    if (!turnoActivo) return;
    if (hayPendientes)        { mostrarError('Debe firmar todos los consentimientos antes de finalizar.'); return; }
    if (hayMuestrasPendientes) { mostrarError('Debe marcar cada muestra como recibida o pendiente antes de finalizar.'); return; }
    if (!confirm(`¿Finalizar atención del turno ${turnoActivo.codigo}?`)) return;
    const _t = { id: turnoActivo.id, paciente_nombre: turnoActivo.paciente_nombre };
    const ok = await cambiarEstadoTurno('finalizado');
    if (ok) _ofrecerEncuesta(_t);
}

async function marcarAusente() {
    if (!turnoActivo) return;
    if (!confirm(`¿Marcar turno ${turnoActivo.codigo} como AUSENTE?`)) return;
    await cambiarEstadoTurno('ausente');
}

async function regresarCola() {
    if (!turnoActivo) return;
    if (!confirm(`¿Regresar turno ${turnoActivo.codigo} a la cola?`)) return;
    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: lugarId }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        resetFicha();
        cargarCola();
    } catch (err) {
        mostrarError(err.message);
    }
}

async function devolverRecepcion() {
    if (!turnoActivo) return;
    if (!confirm(`¿Devolver turno ${turnoActivo.codigo} a recepción?`)) return;
    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_recepcion' }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        mostrarToast('Turno devuelto a recepción', 'info', 3000);
        resetFicha();
        cargarCola();
    } catch (err) {
        mostrarError(err.message);
    }
}

async function cambiarEstadoTurno(nuevoEstado) {
    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: nuevoEstado }),
        });
        const json = await res.json();
        if (!json.ok) {
            // Si el estado cambió por otro operador, refrescar UI en lugar de mostrar error técnico
            if (res.status === 422) {
                mostrarError('El estado del turno cambió desde otro puesto. Actualizando…');
                await cargarCola();
                await recuperarTurnoActivo();
            } else {
                mostrarError(json.error);
            }
            return false;
        }
        resetFicha();
        cargarCola();
        return true;
    } catch (err) {
        mostrarError(err.message);
        return false;
    }
}

// ── Encuesta post-finalizar ───────────────────────────────────
let _encuestaTurnoId = null, _encuestaTimer = null;

function _ofrecerEncuesta(turno) {
    _encuestaTurnoId = turno.id;
    const bar = document.getElementById('bar-encuesta');
    document.getElementById('bar-encuesta-txt').textContent =
        `¿Enviar encuesta de satisfacción a ${turno.paciente_nombre || 'el paciente'}?`;
    document.getElementById('btn-enc-enviar').disabled = false;
    document.getElementById('btn-enc-enviar').innerHTML = '<i class="fas fa-paper-plane me-1"></i>Enviar encuesta';
    bar.style.display = 'flex';
    clearTimeout(_encuestaTimer);
    _encuestaTimer = setTimeout(_cerrarEncuestaBar, 12000);
}

async function _enviarEncuesta() {
    if (!_encuestaTurnoId) return;
    const btn = document.getElementById('btn-enc-enviar');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Enviando…';
    try {
        const res  = await fetch(API + 'enviar_encuesta.php', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: _encuestaTurnoId }),
        });
        const json = await res.json();
        _cerrarEncuestaBar();
        if (json.ok) mostrarToast('Encuesta enviada ✓', 'success', 3000);
        else         mostrarToast('No se pudo enviar: ' + (json.error || 'error'), 'warning', 4000);
    } catch (e) {
        _cerrarEncuestaBar();
        mostrarToast('Error al enviar encuesta', 'warning', 3000);
    }
}

function _cerrarEncuestaBar() {
    clearTimeout(_encuestaTimer);
    document.getElementById('bar-encuesta').style.display = 'none';
    _encuestaTurnoId = null;
}

// ── Reset ficha ───────────────────────────────────────────────
function resetFicha() {
    clearInterval(pollingConsentId);
    turnoActivo        = null;
    tieneConsent          = false;
    hayPendientes         = false;
    hayMuestrasPendientes = false;
    _consentTokenCache    = null;
    _pacienteActivo       = null;
    _solicitudActiva      = null;
    _muestrasActivas      = [];
    const secMuestras = document.getElementById('sec-muestras');
    if (secMuestras) secMuestras.classList.add('d-none');
    // Dejar la sección visible para la siguiente ficha
    document.getElementById('sec-consent')?.classList.remove('d-none');
    document.getElementById('badge-solo-muestras')?.classList.add('d-none');
    document.getElementById('ficha-orden').classList.add('d-none');
    const obsRec = document.getElementById('pac-obs-recepcion');
    if (obsRec) obsRec.classList.add('d-none');
    cerrarModalPaciente();
    document.getElementById('btn-ver-paciente').classList.add('d-none');

    cerrarModalConsentimiento();

    const iframe = document.getElementById('form-embebido-iframe');
    const sec    = document.getElementById('sec-form-embebido');
    const load   = document.getElementById('form-embebido-loading');
    if (iframe) { iframe.src = ''; iframe.style.display = 'none'; }
    if (sec)    { sec.classList.add('d-none'); }
    if (load)   { load.style.display = ''; load.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Cargando formulario...'; }

    const fichaEl = document.getElementById('ficha-turno');
    fichaEl.classList.add('d-none');
    fichaEl.style.display = 'none';
    document.getElementById('ficha-placeholder').classList.remove('d-none');
    document.getElementById('badge-turno-activo').classList.add('d-none');

    const nomHdr = document.getElementById('ficha-pac-nombre-hdr');
    if (nomHdr) { nomHdr.textContent = ''; nomHdr.classList.remove('loading'); }

    const warn = document.getElementById('accion-consent-warn');
    if (warn) warn.classList.add('d-none');

    const inpCom = document.getElementById('inp-comentario');
    if (inpCom) { inpCom.value = ''; inpCom.style.borderColor = ''; inpCom.title = ''; }

    document.getElementById('btn-iniciar').classList.remove('d-none');
    document.getElementById('btn-iniciar').disabled = false;
    document.getElementById('btn-finalizar').classList.add('d-none');
    document.getElementById('btn-regresar').classList.add('d-none');
    document.getElementById('btn-rellamar').classList.add('d-none');
    document.getElementById('btn-devolver').classList.add('d-none');
    document.getElementById('btn-anexar-wrap')?.classList.add('d-none');

    volverACola();
}

// ── Anexar formulario ─────────────────────────────────────────
function _abrirAnexarFormulario() {
    const sel = document.getElementById('sel-anexar-form');
    sel.innerHTML = '<option value="">— Seleccionar formulario —</option>';
    _formulariosList.forEach(f => {
        const o = document.createElement('option');
        o.value = f.id; o.textContent = f.nombre;
        sel.appendChild(o);
    });
    document.getElementById('anexar-form-msg').style.display = 'none';
    document.getElementById('btn-guardar-anexar').disabled = false;
    document.getElementById('modal-anexar-form').style.display = 'flex';
}
function _cerrarAnexarFormulario() {
    document.getElementById('modal-anexar-form').style.display = 'none';
}
async function _guardarAnexarFormulario() {
    const fId = parseInt(document.getElementById('sel-anexar-form').value);
    const msg  = document.getElementById('anexar-form-msg');
    if (!fId) { msg.textContent = 'Selecciona un formulario.'; msg.style.display=''; return; }
    const btn = document.getElementById('btn-guardar-anexar');
    btn.disabled = true;
    try {
        const r = await fetch('modules/turnero/api/anexar_formulario.php', {
            method: 'POST', headers: {'Content-Type':'application/json'},
            body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: fId })
        });
        const j = await r.json();
        if (!j.ok) { msg.textContent = j.error || 'Error al agregar.'; msg.style.display=''; btn.disabled=false; return; }
        _cerrarAnexarFormulario();
        actualizarConsentimientos(turnoActivo.id);
    } catch(e) { msg.textContent = e.message; msg.style.display=''; btn.disabled=false; }
}

// ── Mobile ────────────────────────────────────────────────────
function esMobile() { return window.innerWidth <= 680; }

function mostrarFichaMobile() {
    if (!esMobile()) return;
    document.getElementById('lugar-ficha').classList.add('mobile-visible');
    document.querySelector('.lugar-cola').classList.add('mobile-oculta');
}

function volverACola() {
    document.getElementById('lugar-ficha').classList.remove('mobile-visible');
    document.querySelector('.lugar-cola').classList.remove('mobile-oculta');
}

// ── Estado badge + botones ────────────────────────────────────
function actualizarEstadoBadge(estado) {
    const el   = document.getElementById('ficha-estado-badge');
    const mapa = {
        'en_espera_lugar': ['bg-warning-subtle text-warning border border-warning-subtle',  'En espera'],
        'en_servicio':     ['bg-success-subtle text-success border border-success-subtle',  'En servicio'],
        'finalizado':      ['bg-secondary-subtle text-secondary border',                    'Finalizado'],
        'ausente':         ['bg-danger-subtle text-danger border border-danger-subtle',      'Ausente'],
    };
    const [cls, lbl] = mapa[estado] || ['bg-secondary-subtle text-secondary border', estado];
    el.className   = 'badge ' + cls;
    el.textContent = lbl;

    const btnIni      = document.getElementById('btn-iniciar');
    const btnFin      = document.getElementById('btn-finalizar');
    const btnReg      = document.getElementById('btn-regresar');
    const btnRellamar = document.getElementById('btn-rellamar');
    const btnDev      = document.getElementById('btn-devolver');

    const btnEsp = document.getElementById('btn-espera');
    const btnAnexar = document.getElementById('btn-anexar-wrap');
    if (estado === 'en_espera_lugar') {
        btnIni.classList.remove('d-none'); btnIni.disabled = false;
        btnFin.classList.add('d-none');
        btnReg.classList.add('d-none');
        btnRellamar.classList.add('d-none');
        btnDev.classList.remove('d-none');
        if (btnEsp) btnEsp.classList.add('d-none');
        if (btnAnexar) btnAnexar.classList.add('d-none');
    } else if (estado === 'en_servicio') {
        btnIni.classList.add('d-none');
        btnFin.classList.remove('d-none');
        btnReg.classList.remove('d-none');
        btnRellamar.classList.remove('d-none');
        btnDev.classList.remove('d-none');
        // btn-espera: solo si hay toma progresiva activa (sincronizado desde renderConsentimientos)
        if (btnEsp) btnEsp.classList.add('d-none');
        if (btnAnexar) btnAnexar.classList.remove('d-none');
    }
}

async function rellamarTurno() {
    if (!turnoActivo) return;
    const btn = document.getElementById('btn-rellamar');
    btn.disabled = true;
    try {
        const res  = await fetch(API + 'llamar_turno.php', {
            method:  'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ area: 'lugar', lugar_id: lugarId, turno_id: turnoActivo.id }),
        });
        const json = await res.json();
        if (!json.ok) mostrarError(json.error);
        else if (json.turno) mostrarLlamando(json.turno.codigo);
    } catch (err) {
        mostrarError(err.message);
    } finally {
        btn.disabled = false;
    }
}

// ── Comentarios ───────────────────────────────────────────────
async function cargarComentarios(turnoId) {
    if (!turnoId) return;
    const cont = document.getElementById('lista-comentarios');
    cont.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Cargando…';
    try {
        const res  = await fetch(`${API}comentarios.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (!json.ok || !json.comentarios) { cont.innerHTML = '<small class="text-muted">Sin comentarios</small>'; return; }
        if (!json.comentarios.length)      { cont.innerHTML = '<small class="text-muted">Sin comentarios aún</small>'; return; }
        cont.innerHTML = json.comentarios.map(c => `
            <div style="background:#f8fafc;border-left:3px solid #8b5cf6;padding:8px 10px;margin-bottom:8px;border-radius:4px">
                <div style="font-size:.7rem;color:#94a3b8;margin-bottom:2px">${escHtml(c.usuario_nombre)} • ${new Date(c.creado_at).toLocaleString()}</div>
                <div style="font-size:.82rem;color:#334155">${escHtml(c.comentario)}</div>
            </div>
        `).join('');
    } catch (_) {
        cont.innerHTML = '<small class="text-danger">Error al cargar comentarios</small>';
    }
}

async function guardarComentario() {
    if (!turnoActivo) return;
    const inp = document.getElementById('inp-comentario');
    const txt = (inp.value || '').trim();
    if (!txt) { mostrarError('El comentario no puede estar vacío'); return; }
    try {
        const res  = await fetch(API + 'comentarios.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id, comentario: txt, tipo: 'muestras' }),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error || 'Error al guardar'); return; }
        inp.value = '';
        draftBorrar();
        await cargarComentarios(turnoActivo.id);
        mostrarToast('Comentario guardado', 'success', 2000);
    } catch (err) {
        mostrarError(err.message);
    }
}

// ── Borrador de comentario (localStorage) ─────────────────────
function _draftKey() { return turnoActivo ? 'toma_draft_' + turnoActivo.id : null; }

function draftGuardar() {
    const key = _draftKey();
    if (!key) return;
    const val = (document.getElementById('inp-comentario')?.value || '').trim();
    if (val) localStorage.setItem(key, val);
    else     localStorage.removeItem(key);
}

function draftRestaurar(turnoId) {
    const key = 'toma_draft_' + turnoId;
    const val = localStorage.getItem(key);
    const inp = document.getElementById('inp-comentario');
    if (!inp) return;
    if (val) {
        inp.value = val;
        inp.style.borderColor = '#f59e0b';
        inp.title = 'Borrador restaurado — no guardado aún';
    } else {
        inp.value = '';
        inp.style.borderColor = '';
        inp.title = '';
    }
}

function draftBorrar() {
    const key = _draftKey();
    if (key) localStorage.removeItem(key);
    const inp = document.getElementById('inp-comentario');
    if (inp) { inp.style.borderColor = ''; inp.title = ''; }
}

// ── Modal paciente ────────────────────────────────────────────
function abrirModalPaciente() {
    if (!_pacienteActivo) return;
    const pac = _pacienteActivo;
    const sol = _solicitudActiva;

    document.getElementById('mpac-nombre-titulo').textContent =
        pac.nombre_completo || pac.full_name || 'Paciente';
    document.getElementById('mpac-val-nombre').textContent =
        pac.nombre_completo || pac.full_name || '—';
    document.getElementById('mpac-val-doc').textContent =
        ((pac.tipo_documento || '') + ' ' + (pac.numero_documento || pac.documento || '')).trim() || '—';
    document.getElementById('mpac-val-fec').textContent = pac.fecha_nacimiento || '—';
    document.getElementById('mpac-val-cel').textContent = pac.telefono || pac.celular || '—';

    const rowMed = document.getElementById('mpac-row-medico');
    if (sol && sol.medico_nombre) {
        rowMed.style.display = '';
        const esp = sol.medico_especialidad ? ' · ' + sol.medico_especialidad : '';
        document.getElementById('mpac-val-medico').textContent = sol.medico_nombre + esp;
    } else {
        rowMed.style.display = 'none';
    }

    const badgeEmb = document.getElementById('mpac-badge-emb');
    badgeEmb.classList.toggle('d-none', !(sol && sol.embarazada == 1));

    document.getElementById('mpac-historial-content').innerHTML =
        '<div class="text-center text-muted py-3 small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando historial…</div>';
    document.getElementById('modal-pac-lugar').classList.add('show');

    cargarHistorialModal(pac.id);
}

function cerrarModalPaciente() {
    document.getElementById('modal-pac-lugar').classList.remove('show');
    mpacEditar(false);
}

/* ── Corrección de la ficha del paciente desde la estación ──
   Los campos del formulario son vinculados: leen de la ficha. Por eso se
   corrige la ficha y no el documento — así el dato queda bien en el turnero,
   los domicilios y las órdenes, no solo en la hoja que se está llenando. */

function mpacEditar(abrir) {
    document.getElementById('mpac-form').classList.toggle('d-none', !abrir);
    document.getElementById('mpac-datos').classList.toggle('d-none', abrir);
    document.getElementById('mpac-msg').textContent = '';

    if (!abrir) { mpacBloquearIdentidad(); return; }

    const p = _pacienteActivo || {};
    document.getElementById('mpac-in-tel').value    = p.telefono || p.celular || '';
    document.getElementById('mpac-in-dir').value    = p.direccion || '';
    document.getElementById('mpac-in-eps').value    = p.eps || '';
    document.getElementById('mpac-in-genero').value = p.genero || '';
    document.getElementById('mpac-in-nombre').value = p.nombre_completo || '';
    document.getElementById('mpac-in-tipodoc').value = p.tipo_documento || 'CC';
    document.getElementById('mpac-in-doc').value    = p.numero_documento || p.documento || '';
    document.getElementById('mpac-in-fnac').value   = (p.fecha_nacimiento || '').slice(0, 10);

    mpacBloquearIdentidad();

    // Si ya hay documentos firmados, advertir que corregir no los modifica.
    // El botón "Ver firmado" solo se renderiza para consentimientos ya firmados.
    const firmados = document.querySelectorAll('#lista-consent button[title="Ver firmado"]').length > 0;
    document.getElementById('mpac-aviso-firmados').classList.toggle('d-none', !firmados);
}

function mpacBloquearIdentidad() {
    document.getElementById('mpac-identidad').classList.add('d-none');
    document.getElementById('mpac-identidad-lock').classList.remove('d-none');
}

function mpacDesbloquearIdentidad() {
    if (!confirm('Nombre, documento y fecha de nacimiento identifican al paciente en toda su '
               + 'historia clínica.\n\n¿Confirma que quiere corregirlos?')) return;
    document.getElementById('mpac-identidad').classList.remove('d-none');
    document.getElementById('mpac-identidad-lock').classList.add('d-none');
}

async function mpacGuardarFicha() {
    if (!_pacienteActivo?.id) return;
    const msg = document.getElementById('mpac-msg');
    const btn = document.getElementById('mpac-btn-guardar');
    const val = id => document.getElementById(id).value.trim();

    const cuerpo = {
        id: _pacienteActivo.id,
        telefono:  val('mpac-in-tel'),
        direccion: val('mpac-in-dir'),
        eps:       val('mpac-in-eps'),
        genero:    val('mpac-in-genero'),
    };
    // Los datos de identidad solo se envían si se desbloquearon
    if (!document.getElementById('mpac-identidad').classList.contains('d-none')) {
        cuerpo.nombre_completo  = val('mpac-in-nombre');
        cuerpo.tipo_documento   = val('mpac-in-tipodoc');
        cuerpo.numero_documento = val('mpac-in-doc');
        cuerpo.fecha_nacimiento = val('mpac-in-fnac') || null;
    }

    btn.disabled = true;
    msg.className = 'small mb-2 text-muted';
    msg.textContent = 'Guardando…';

    try {
        const r = await fetch(`${BASE_WA}api/lab/save_paciente.php`, {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(cuerpo),
        });
        const d = await r.json();
        if (!d.ok) {
            msg.className = 'small mb-2 text-danger';
            msg.textContent = d.error || 'No se pudo guardar.';
            btn.disabled = false;
            return;
        }
        // Reflejar el cambio sin recargar: ficha del modal, tarjeta del turno
        // y el formulario abierto, cuyos campos vinculados leen de la ficha.
        Object.assign(_pacienteActivo, cuerpo);
        msg.className = 'small mb-2 text-success';
        msg.textContent = 'Ficha actualizada.';
        setTimeout(() => {
            mpacEditar(false);
            abrirModalPaciente();
            if (turnoActivo?.id) actualizarConsentimientos(turnoActivo.id);
            // Recargar el formulario abierto para que sus campos vinculados
            // tomen el dato corregido. Puede estar en el modal o embebido.
            ['modal-consent-iframe', 'form-embebido-iframe'].forEach(function (id) {
                const marco = document.getElementById(id);
                if (marco && marco.src) marco.src = marco.src;
            });
        }, 700);
    } catch (_) {
        msg.className = 'small mb-2 text-danger';
        msg.textContent = 'Error de conexión.';
        btn.disabled = false;
    }
}

async function cargarHistorialModal(pacienteId) {
    const cont = document.getElementById('mpac-historial-content');
    try {
        const res  = await fetch(`${API}get_historial.php?paciente_id=${pacienteId}&per_page=10&page=1`);
        const json = await res.json();
        if (!json.ok || !json.turnos || !json.turnos.length) {
            cont.innerHTML = '<div class="text-center text-muted py-3 small"><i class="fas fa-inbox me-1"></i>Sin visitas anteriores registradas</div>';
            return;
        }
        cont.innerHTML = renderHistorialTimeline(json.turnos, json.total);
    } catch(_) {
        cont.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 totalLabel = total > turnos.length
        ? `<div style="font-size:.67rem;color:#94a3b8;text-align:right;padding:4px 0">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 = escHtml(t.fecha_sesion || '—');
        const est   = t.estado || '';
        const eStyle = ESTADO_STYLE[est] || 'background:#f1f5f9;color:#334155';
        const eLbl  = escHtml(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>` : '';

        let examStr = '';
        if (t.examenes && t.examenes.length) {
            examStr = `<div style="margin-top:5px;font-size:.74rem">
                <strong style="color:#64748b">Exámenes:</strong>
                <span style="color:#475569">${t.examenes.map(e => escHtml(e.nombre)).join(', ')}</span>
            </div>`;
        }
        let comStr = '';
        if (t.comentarios && t.comentarios.length) {
            comStr = `<div style="margin-top:5px;font-size:.71rem;border-top:1px solid #e2e8f0;padding-top:5px">
                <strong style="color:#64748b">📝 Comentarios:</strong>
                <div style="color:#475569;margin-top:3px">${t.comentarios.map(c =>
                    `<div style="margin-bottom:2px"><strong>${escHtml(c.usuario_nombre)}</strong>: ${escHtml(c.comentario)}</div>`
                ).join('')}</div>
            </div>`;
        }

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

    return `<div class="mpac-timeline">${items}</div>${totalLabel}`;
}

// ── Muestras ──────────────────────────────────────────────────
function renderMuestras(lista) {
    _muestrasActivas = lista || [];
    const sec     = document.getElementById('sec-muestras');
    const cont    = document.getElementById('lista-muestras');
    const summary = document.getElementById('muestras-summary');
    if (!sec) return;

    // Solo mostrar en estaciones tipo "muestras"
    if (LUGAR_TIPO !== 'muestras' || !lista.length) {
        sec.classList.add('d-none');
        return;
    }

    sec.classList.remove('d-none');

    const nPend = lista.filter(m => m.estado === 'pendiente').length;
    const nRec  = lista.filter(m => m.estado === 'recibida').length;
    const nRech = lista.filter(m => m.estado === 'rechazada').length;

    hayMuestrasPendientes = nPend > 0;
    _syncBtnFinalizar();

    let chips = '';
    if (nPend)  chips += `<span class="mc pend">${nPend} pendiente${nPend > 1 ? 's' : ''}</span>`;
    if (nRec)   chips += `<span class="mc rec">${nRec} recibida${nRec > 1 ? 's' : ''}</span>`;
    if (nRech)  chips += `<span class="mc rech">${nRech} pendiente${nRech > 1 ? 's' : ''}</span>`;
    summary.innerHTML = chips;

    cont.innerHTML = lista.map(m => {
        const esPrevio  = !!m.es_pendiente_anterior;
        // Rechazadas de una visita anterior también se pueden recibir directo (el paciente trae muestra nueva)
        const esPend    = m.estado === 'pendiente' || (esPrevio && m.estado === 'rechazada');
        const label     = escHtml(m.label || m.tipo_muestra || 'MUESTRA');
        const origenTag = esPrevio
            ? `<span style="font-size:.68rem;background:#fef3c7;color:#92400e;border:1px solid #fde68a;
                            border-radius:10px;padding:1px 7px;margin-left:5px;white-space:nowrap">
                   <i class="fas fa-history me-1"></i>visita anterior${m.solicitud_orden_anterior ? ' · ' + escHtml(m.solicitud_orden_anterior) : ''}
               </span>`
            : '';
        const examAntHtml = (esPrevio && m.examenes_anteriores && m.examenes_anteriores.length)
            ? `<div class="muestra-examenes"><i class="fas fa-vials me-1"></i>${m.examenes_anteriores.map(e => escHtml(e.nombre)).join(', ')}</div>`
            : '';
        const tsHtml = m.recibida_at
            ? `<span class="muestra-ts">${formatHora(m.recibida_at)}</span>`
            : '';
        const motivoHtml = m.motivo_rechazo
            ? `<div class="muestra-motivo">${escHtml(m.motivo_rechazo)}</div>` : '';

        const acciones = esPend
            ? `<div style="display:flex;gap:5px;flex-shrink:0">
                   <button class="btn-muestra-accion recibir"
                           onclick="marcarMuestra(${m.id},'recibida')">
                       <i class="fas fa-check"></i> Recibida
                   </button>
                   <button class="btn-muestra-accion rechazar"
                           onclick="pedirRechazo(${m.id},'${label.replace(/'/g,'\\\'')}')" >
                       <i class="fas fa-clock"></i> Pendiente
                   </button>
               </div>`
            : `${tsHtml}
               <button class="btn-muestra-accion"
                       style="background:#f1f5f9;color:#64748b;border:1px solid #e2e8f0"
                       onclick="marcarMuestra(${m.id},'pendiente')" title="Revertir a pendiente">
                   <i class="fas fa-undo"></i>
               </button>`;

        const ico = m.estado === 'recibida'
            ? '<i class="fas fa-check-circle" style="color:#16a34a;flex-shrink:0"></i>'
            : m.estado === 'rechazada'
            ? '<i class="fas fa-hourglass-half" style="color:#c2410c;flex-shrink:0"></i>'
            : '<i class="fas fa-clock" style="color:#d97706;flex-shrink:0"></i>';

        return `<div class="muestra-row ${m.estado}" data-muestra-id="${m.id}">
            ${ico}
            <div class="muestra-info">
                <span class="muestra-label">${label}</span>${origenTag}
                ${examAntHtml}
                ${motivoHtml}
            </div>
            ${acciones}
        </div>`;
    }).join('');
}

async function marcarMuestra(muestraId, estado, motivo = null) {
    try {
        const body = { muestra_id: muestraId, estado };
        if (motivo) body.motivo_rechazo = motivo;
        if (turnoActivo?.id) body.turno_id = turnoActivo.id;
        const res  = await fetch(API + 'update_muestra_estado.php', {
            method:  'POST',
            headers: { 'Content-Type': 'application/json' },
            body:    JSON.stringify(body),
        });
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error); return; }
        // Actualizar estado local sin re-fetch
        const m = _muestrasActivas.find(x => x.id == muestraId);
        if (m) {
            m.estado         = estado;
            m.motivo_rechazo = motivo;
            m.recibida_at    = estado !== 'pendiente' ? new Date().toISOString() : null;
        }
        renderMuestras(_muestrasActivas);
        const msg = estado === 'recibida'
            ? 'Muestra recibida ✓'
            : estado === 'rechazada' ? 'Pendiente' : 'Revertida a pendiente';
        mostrarToast(msg, estado === 'recibida' ? 'success' : estado === 'rechazada' ? 'warn' : 'info', 2000);
    } catch (err) {
        mostrarError(err.message);
    }
}

function pedirRechazo(muestraId, tipoMuestra) {
    const motivo = prompt(`Nota para "${tipoMuestra}" (opcional):\n(ej: paciente la trae mañana, volumen insuficiente…)`);
    if (motivo === null) return;
    marcarMuestra(muestraId, 'rechazada', motivo.trim() || null);
}

function formatHora(isoStr) {
    if (!isoStr) return '';
    try {
        return new Date(isoStr).toLocaleTimeString('es-CO', { hour: '2-digit', minute: '2-digit' });
    } catch (_) { return ''; }
}

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

let _toastTimer = null;
function mostrarToast(msg, type = 'info', duration = 2500) {
    const el  = document.getElementById('lug-toast');
    const ico = document.getElementById('lug-toast-ico');
    const txt = document.getElementById('lug-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);
}
function mostrarError(msg)    { mostrarToast(msg, 'error', 4000); }
function mostrarLlamando(cod) { mostrarToast('Llamando turno ' + cod + '…', 'info', 2000); }

function _renderEsperaMuestras(items) {
    const panel = document.getElementById('espera-muestras-panel');
    if (!panel) return;
    if (!items.length) { panel.style.display = 'none'; panel.innerHTML = ''; return; }
    const ahora = Date.now();
    let html = `<div class="espera-m-hdr">
        <i class="fas fa-hourglass-half" style="color:#f97316"></i>
        Esperando siguiente muestra
        <span class="espera-m-count">${items.length}</span>
    </div>`;
    for (const p of items) {
        let cdHtml = '';
        if (p.siguiente_toma_at) {
            const ms   = new Date(p.siguiente_toma_at.replace(' ', 'T')).getTime() - ahora;
            const mins = Math.ceil(ms / 60000);
            if (ms <= 0) {
                cdHtml = `<span class="espera-m-cd crit">¡Lista ya!</span>`;
            } else if (mins <= 5) {
                cdHtml = `<span class="espera-m-cd warn">en ${mins} min</span>`;
            } else {
                cdHtml = `<span class="espera-m-cd ok">en ${mins} min</span>`;
            }
        }
        const chipOculto = p.siguiente_toma_at
            ? `<span class="toma-prog-chip" data-toma-at="${escHtml(p.siguiente_toma_at)}" data-turno-id="${p.id}" style="display:none"><span class="toma-cd-txt"></span></span>`
            : '';
        html += `<div class="espera-m-row">
            ${chipOculto}
            <span class="espera-m-orden">#${escHtml(String(p.numero_orden))}</span>
            <span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtml(p.paciente_nombre)}</span>
            ${cdHtml}
            <button class="btn-llamar-espera" onclick="_llamarDesdeEspera(${(int = p.id, int)})">
                <i class="fas fa-bell fa-xs me-1"></i>Llamar
            </button>
        </div>`;
    }
    panel.innerHTML = html;
    panel.style.display = '';
}

async function _ponerEnEspera() {
    if (!turnoActivo) return;
    const btn = document.getElementById('btn-espera');
    if (btn) btn.disabled = true;
    try {
        const res = await fetch(API + 'poner_en_espera_muestra.php', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoActivo.id }),
        });
        const j = await res.json();
        if (!j.ok) { mostrarError(j.error); return; }
        resetFicha();
        cargarCola();
    } catch (e) { mostrarError(e.message); }
    finally { if (btn) btn.disabled = false; }
}

async function _llamarDesdeEspera(turnoId) {
    try {
        const res = await fetch(API + 'llamar_desde_espera.php', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ turno_id: turnoId, lugar_id: lugarId }),
        });
        const j = await res.json();
        if (!j.ok) { mostrarError(j.error); return; }
        mostrarLlamando(j.turno.codigo);
        await abrirFicha(j.turno);
        cargarCola();
    } catch (e) { mostrarError(e.message); }
}

async function _cargarEspecialidades() {
    if (!ESP_LUGARES.length) return;
    try {
        const qs  = ESP_LUGARES.map(l => `ids[]=${l.id}`).join('&');
        const res = await fetch(`${API}get_especialidades.php?${qs}`);
        const j   = await res.json();
        if (j.ok) _renderEspecialidades(j.grupos);
    } catch {}
}

function _renderEspecialidades(grupos) {
    const panel = document.getElementById('esp-panel');
    if (!panel) return;
    let html = '';
    for (const g of grupos) {
        const esGine = g.lugar_nombre.toLowerCase().includes('ginecol');
        const color  = esGine ? '#ec4899' : '#0ea5e9';
        const icon   = esGine ? 'fa-venus' : 'fa-child';
        const url    = `${BASE_WA}erp.php?m=turnero&v=lugar&lugar_id=${g.lugar_id}`;
        const cnt    = document.getElementById(`esp-cnt-${g.lugar_id}`);
        if (cnt) cnt.textContent = g.pacientes.length;
        if (!g.pacientes.length) continue;
        html += `<div class="esp-grupo" style="--esp-gc:${color}">
            <div class="esp-grupo-hdr">
                <i class="fas ${icon}" style="color:${color}"></i>
                ${escHtml(g.lugar_nombre)}
                <span class="esp-grupo-count">${g.pacientes.length}</span>
                <a href="${url}" class="esp-grupo-ir">Ir <i class="fas fa-arrow-right fa-xs"></i></a>
            </div>
            ${g.pacientes.map(p => `
            <a href="${url}" class="esp-pac-row">
                <span class="esp-pac-orden">#${p.numero_orden}</span>
                <span>${escHtml(p.paciente_nombre)}</span>
                <span class="esp-pac-hora">${formatHora(p.inicio_lugar_at)}</span>
            </a>`).join('')}
        </div>`;
    }
    panel.innerHTML = html;
    panel.style.display = html ? '' : 'none';
}

/* ── Ocupación exclusiva del puesto ──────────────────────────── */
(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';
        }
    }

    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 puesto 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>';
    }

    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('✅ Puesto 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;
        }
    };

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

    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 puesto.</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(() => {});
        };
    }

    async function _iniciar() {
        try {
            const j = await _post({ action: 'claim' });
            if (!j.ok) return;
            if (!j.disponible) { _mostrarBloqueado(j.ocupado_por); return; }
            setInterval(() => _post({ action: 'ping' }).catch(() => {}), 60000);
            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();
})(lugarId, LUGAR_NOMBRE, 'lugar', 'lugar_id');
</script>

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

<!-- ── Modal Mi Firma ─────────────────────────────────────── -->
<div id="modal-mi-firma" style="display:none;position:fixed;inset:0;z-index:9500;
     background:rgba(0,0,0,.55);align-items:center;justify-content:center;padding:16px">
    <div style="background:#fff;border-radius:14px;box-shadow:0 8px 40px rgba(0,0,0,.25);
                width:min(96vw,480px);display:flex;flex-direction:column;overflow:hidden">
        <div style="display:flex;align-items:center;justify-content:space-between;
                    padding:12px 18px;border-bottom:1px solid #e2e8f0">
            <span style="font-weight:700;font-size:.95rem;color:#1e293b">
                <i class="fas fa-signature me-2 text-success"></i>Mi firma pre-guardada
            </span>
            <button onclick="cerrarModalMiFirma()"
                    style="background:none;border:none;font-size:1.2rem;color:#94a3b8;cursor:pointer;padding:2px 6px">
                <i class="fas fa-times"></i>
            </button>
        </div>
        <div style="padding:16px">
            <?php if ($adminFirmaSvg): ?>
            <div id="mf-preview" style="text-align:center;margin-bottom:12px">
                <p class="small text-success mb-1"><i class="fas fa-check-circle me-1"></i>Firma guardada</p>
                <img src="<?= htmlspecialchars($adminFirmaSvg) ?>" alt="Mi firma"
                     style="max-height:80px;max-width:100%;border:1px solid #c9d8ff;border-radius:8px;padding:6px">
                <br><a href="#" class="small text-muted mt-1 d-inline-block" onclick="document.getElementById('mf-preview').style.display='none';document.getElementById('mf-canvas-wrap').style.display='';return false">✎ Dibujar nueva</a>
            </div>
            <div id="mf-canvas-wrap" style="display:none">
            <?php else: ?>
            <div id="mf-canvas-wrap">
            <?php endif; ?>
                <p class="small text-muted mb-2">Dibuje su firma en el recuadro:</p>
                <canvas id="mf-canvas" width="420" height="140"
                        style="border:2px solid #198754;border-radius:8px;background:#f8fff9;
                               cursor:crosshair;display:block;width:100%;touch-action:none"></canvas>
                <div class="mt-2 d-flex gap-2">
                    <button class="btn btn-outline-secondary btn-sm" onclick="mfLimpiar()">
                        <i class="fas fa-eraser me-1"></i>Limpiar
                    </button>
                    <button class="btn btn-success btn-sm ms-auto" id="mf-btn-save" onclick="mfGuardar()">
                        <i class="fas fa-save me-1"></i>Guardar firma
                    </button>
                </div>
            </div>
            <div id="mf-msg" class="mt-2 small"></div>
        </div>
    </div>
</div>

<script>
// ── Modal Mi Firma ────────────────────────────────────────────
(function() {
    var canvas, ctx, drawing = false;

    function init() {
        canvas = document.getElementById('mf-canvas');
        if (!canvas) return;
        const ratio = window.devicePixelRatio || 1;
        const w = canvas.offsetWidth || 420, h = canvas.offsetHeight || 140;
        canvas.width = w * ratio; canvas.height = h * ratio;
        canvas.style.width = w + 'px'; canvas.style.height = h + 'px';
        ctx = canvas.getContext('2d');
        ctx.scale(ratio, ratio);
        ctx.strokeStyle = '#000'; ctx.lineWidth = 2.5; ctx.lineCap = 'round'; ctx.lineJoin = 'round';

        function pos(e) { const r = canvas.getBoundingClientRect(), s = e.touches?e.touches[0]:e; return {x:s.clientX-r.left, y:s.clientY-r.top}; }
        canvas.addEventListener('mousedown',  e => { drawing=true; ctx.beginPath(); const p=pos(e); ctx.moveTo(p.x,p.y); });
        canvas.addEventListener('mousemove',  e => { if(!drawing) return; const p=pos(e); ctx.lineTo(p.x,p.y); ctx.stroke(); });
        canvas.addEventListener('mouseup',    () => drawing=false);
        canvas.addEventListener('mouseleave', () => drawing=false);
        canvas.addEventListener('touchstart', e => { e.preventDefault(); drawing=true; ctx.beginPath(); const p=pos(e); ctx.moveTo(p.x,p.y); }, {passive:false});
        canvas.addEventListener('touchmove',  e => { e.preventDefault(); if(!drawing) return; const p=pos(e); ctx.lineTo(p.x,p.y); ctx.stroke(); }, {passive:false});
        canvas.addEventListener('touchend',   () => drawing=false);
    }

    window.abrirModalMiFirma = function() {
        document.getElementById('modal-mi-firma').style.display = 'flex';
        if (!ctx) init();
    };
    window.cerrarModalMiFirma = function() {
        document.getElementById('modal-mi-firma').style.display = 'none';
    };
    window.mfLimpiar = function() {
        if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
    };
    window.mfGuardar = function() {
        const png = canvas.toDataURL('image/png');
        if (png.length < 1000) { document.getElementById('mf-msg').innerHTML = '<span class="text-danger">Dibuje su firma primero.</span>'; return; }
        const btn = document.getElementById('mf-btn-save');
        btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando...';
        fetch('<?= BASE_URL ?>modules/turnero/api/save_firma_profesional.php', {
            method: 'POST', headers: {'Content-Type':'application/json'},
            body: JSON.stringify({ firma_svg: png })
        })
        .then(r => r.json())
        .then(d => {
            if (d.ok) {
                window._fpwPreFirma = png;
                document.getElementById('mf-msg').innerHTML = '<span class="text-success"><i class="fas fa-check me-1"></i>Firma guardada. Se usará en el próximo consentimiento.</span>';
                btn.innerHTML = '<i class="fas fa-check me-1"></i>Guardado';
                // Actualizar preview si existe
                var prev = document.getElementById('mf-preview');
                if (prev) { prev.querySelector('img').src = png; prev.style.display=''; document.getElementById('mf-canvas-wrap').style.display='none'; }
            } else {
                document.getElementById('mf-msg').innerHTML = '<span class="text-danger">' + (d.error||'Error') + '</span>';
                btn.disabled = false; btn.innerHTML = '<i class="fas fa-save me-1"></i>Guardar firma';
            }
        })
        .catch(() => {
            document.getElementById('mf-msg').innerHTML = '<span class="text-danger">Error de conexión.</span>';
            btn.disabled = false; btn.innerHTML = '<i class="fas fa-save me-1"></i>Guardar firma';
        });
    };
})();
</script>

<!-- ── Modal: Anexar formulario ──────────────────────────────── -->
<div id="modal-anexar-form" style="display:none;position:fixed;inset:0;z-index:9000;background:rgba(0,0,0,.5);align-items:center;justify-content:center;">
    <div style="background:var(--bs-body-bg,#fff);border-radius:10px;padding:1.25rem;width:min(380px,92vw);box-shadow:0 8px 32px rgba(0,0,0,.25)">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;">
            <strong><i class="fas fa-file-plus me-2"></i>Agregar formulario adicional</strong>
            <button type="button" onclick="_cerrarAnexarFormulario()" style="background:none;border:none;font-size:1.2rem;cursor:pointer;opacity:.6">&times;</button>
        </div>
        <select id="sel-anexar-form" class="form-select mb-3">
            <option value="">— Seleccionar formulario —</option>
        </select>
        <div id="anexar-form-msg" class="small text-danger mb-2" style="display:none"></div>
        <div style="display:flex;gap:.5rem;justify-content:flex-end">
            <button type="button" class="btn btn-secondary btn-sm" onclick="_cerrarAnexarFormulario()">Cancelar</button>
            <button type="button" class="btn btn-primary btn-sm" id="btn-guardar-anexar" onclick="_guardarAnexarFormulario()">
                <i class="fas fa-plus me-1"></i>Agregar
            </button>
        </div>
    </div>
</div>

<script src="<?= defined('APP_URL') ? rtrim(APP_URL,'/') : '' ?>/assets/js/lab-sidebar.js"></script>
</body>
</html>
