<?php
declare(strict_types=1);

error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');

require_once __DIR__ . '/../../config/database.php';
$conn = function_exists('getAppConnection') ? getAppConnection() : getConnection();

if (!function_exists('e')) {
    function e($v): string { return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }
}

function lbk_exec(mysqli $conn, string $sql): void { try { $conn->query($sql); } catch (Throwable $e) { /* silent */ } }
function lbk_one(mysqli $conn, string $sql, array $params = [], string $types = ''): ?array {
    $stmt = $conn->prepare($sql); if (!$stmt) return null;
    if ($params) { $stmt->bind_param($types, ...$params); }
    $stmt->execute(); $res = $stmt->get_result(); $row = $res ? $res->fetch_assoc() : null; $stmt->close();
    return $row ?: null;
}
function lbk_all(mysqli $conn, string $sql, array $params = [], string $types = ''): array {
    $stmt = $conn->prepare($sql); if (!$stmt) return [];
    if ($params) { $stmt->bind_param($types, ...$params); }
    $stmt->execute(); $res = $stmt->get_result(); $rows = [];
    if ($res) { while ($r = $res->fetch_assoc()) $rows[] = $r; }
    $stmt->close(); return $rows;
}
function lbk_current_user(): array {
    $u = $_SESSION['user'] ?? [];
    return [
        'id'      => (int)($_SESSION['user_id'] ?? $u['id'] ?? $u['user_id'] ?? 0),
        'name'    => (string)($_SESSION['full_name'] ?? $u['full_name'] ?? $u['name'] ?? 'User'),
        'role'    => strtolower((string)($_SESSION['user_role'] ?? $u['role'] ?? 'user')),
        'nik'     => (string)($_SESSION['nik'] ?? $u['nik'] ?? ''),
        'unit'    => (string)($_SESSION['unit'] ?? $u['unit'] ?? ''),
        'jabatan' => (string)($_SESSION['jabatan'] ?? ''),
    ];
}
function lbk_level_from_text(string $text, string $systemRole = ''): string {
    $t = strtolower($text . ' ' . $systemRole);
    if (str_contains($t, 'kadiv') || str_contains($t, 'kepala divisi') || str_contains($t, 'divisi keperawatan')) return 'kadiv';
    if (str_contains($t, 'kasub') || str_contains($t, 'sub divisi') || str_contains($t, 'subdiv')) {
        if (str_contains($t, 'rajal') || str_contains($t, 'rawat jalan') || str_contains($t, 'igd') || str_contains($t, 'poliklinik') || str_contains($t, 'kamar operasi') || str_contains($t, 'vk')) return 'kasubdiv_rajal';
        if (str_contains($t, 'ranap') || str_contains($t, 'rawat inap') || str_contains($t, 'icu') || str_contains($t, 'nicu') || str_contains($t, 'ruang bayi')) return 'kasubdiv_ranap';
        return 'kasubdiv';
    }
    if (str_contains($t, 'ka unit') || str_contains($t, 'kepala unit') || str_contains($t, 'karu')) return 'kaunit';
    if (str_contains($t, 'katim') || str_contains($t, 'ketua tim') || str_contains($t, 'pj shift')) return 'katim';
    return 'pelaksana';
}
function lbk_level_label(string $level): string {
    return [
        'pelaksana'       => 'Perawat Pelaksana',
        'katim'           => 'Katim / PJ Shift',
        'kaunit'          => 'Kepala Unit',
        'kasubdiv'        => 'Kepala Sub Divisi Keperawatan',
        'kasubdiv_rajal'  => 'Kasubdiv Keperawatan Rawat Jalan',
        'kasubdiv_ranap'  => 'Kasubdiv Keperawatan Rawat Inap',
        'kadiv'           => 'Kepala Divisi Keperawatan',
    ][$level] ?? $level;
}
function lbk_master_role_level(string $level): string {
    return in_array($level, ['kasubdiv_rajal','kasubdiv_ranap'], true) ? 'kasubdiv' : $level;
}
function lbk_unit_options(): array {
    return [
        'UMUM'          => 'Umum / Semua Unit',
        'IGD'           => 'IGD',
        'KAMAR_BERSALIN'=> 'Kamar Bersalin',
        'HD'            => 'HD',
        'OK'            => 'OK / Kamar Operasi',
        'POLIKLINIK'    => 'Poliklinik',
        'RAWAT_INAP'    => 'Rawat Inap',
        'RUANG_BAYI'    => 'Ruang Bayi',
        'NICU'          => 'NICU',
        'ICU'           => 'ICU',
    ];
}
function lbk_unit_label(?string $code): string {
    $opts = lbk_unit_options();
    $code = strtoupper(trim((string)$code));
    return $opts[$code] ?? ($code !== '' ? $code : 'Umum / Semua Unit');
}
function lbk_unit_from_text(string $text): string {
    $t = strtolower($text);
    if (str_contains($t, 'igd') || str_contains($t, 'emergency') || str_contains($t, 'gawat darurat')) return 'IGD';
    if (str_contains($t, 'bersalin') || str_contains($t, 'vk') || str_contains($t, 'kamar bersalin')) return 'KAMAR_BERSALIN';
    if (str_contains($t, 'hd') || str_contains($t, 'hemodialisa') || str_contains($t, 'hemodialisis')) return 'HD';
    if (str_contains($t, 'ok') || str_contains($t, 'operasi') || str_contains($t, 'kamar operasi') || str_contains($t, 'bedah sentral')) return 'OK';
    if (str_contains($t, 'poli') || str_contains($t, 'rawat jalan') || str_contains($t, 'rajal')) return 'POLIKLINIK';
    if (str_contains($t, 'rawat inap') || str_contains($t, 'ranap') || str_contains($t, 'canigara') || str_contains($t, 'cempaka') || str_contains($t, 'cendana')) return 'RAWAT_INAP';
    if (str_contains($t, 'ruang bayi') || str_contains($t, 'bayi')) return 'RUANG_BAYI';
    if (str_contains($t, 'nicu')) return 'NICU';
    if (str_contains($t, 'icu') || str_contains($t, 'intensive')) return 'ICU';
    return 'UMUM';
}
function lbk_role_uses_unit_activity(string $role): bool {
    return in_array($role, ['pelaksana','kaunit'], true);
}
function lbk_role_uses_workload_adjustment(string $role): bool {
    return lbk_master_role_level($role) === 'pelaksana';
}
function lbk_can_verify(string $level, bool $isAdmin): bool {
    return $isAdmin || in_array($level, ['katim','kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true);
}
function lbk_status_badge(string $status): string {
    $map = [
        'draft'     => 'bg-slate-100 text-slate-700 border-slate-200',
        'submitted' => 'bg-blue-50 text-blue-700 border-blue-200',
        'verified'  => 'bg-emerald-50 text-emerald-700 border-emerald-200',
        'rejected'  => 'bg-rose-50 text-rose-700 border-rose-200',
    ];
    return $map[$status] ?? $map['draft'];
}
function lbk_kpi_category(float $score): array {
    if ($score >= 90) return ['Sangat Baik',    'text-emerald-700 bg-emerald-50 border-emerald-200'];
    if ($score >= 80) return ['Baik',            'text-blue-700 bg-blue-50 border-blue-200'];
    if ($score >= 70) return ['Cukup',           'text-amber-700 bg-amber-50 border-amber-200'];
    if ($score >= 60) return ['Perlu Pembinaan', 'text-orange-700 bg-orange-50 border-orange-200'];
    return             ['Evaluasi Khusus',        'text-rose-700 bg-rose-50 border-rose-200'];
}
function lbk_domain_weights(string $roleLevel): array {
    $roleLevel = lbk_master_role_level($roleLevel);
    $sets = [
        'pelaksana' => ['produktivitas'=>35,'dokumentasi'=>20,'patient_safety'=>20,'disiplin'=>10,'leadership'=>5,'kompetensi'=>10,'mutu'=>0,'kolaborasi'=>0],
        'katim'     => ['produktivitas'=>25,'dokumentasi'=>20,'patient_safety'=>20,'disiplin'=>10,'leadership'=>15,'kompetensi'=>10,'mutu'=>0,'kolaborasi'=>0],
        'kaunit'    => ['produktivitas'=>20,'dokumentasi'=>15,'patient_safety'=>20,'disiplin'=>10,'leadership'=>20,'kompetensi'=>10,'mutu'=>5,'kolaborasi'=>0],
        'kasubdiv'  => ['produktivitas'=>20,'dokumentasi'=>15,'patient_safety'=>20,'disiplin'=>10,'leadership'=>20,'kompetensi'=>15,'mutu'=>0,'kolaborasi'=>0],
        'kadiv'     => ['produktivitas'=>15,'dokumentasi'=>10,'patient_safety'=>20,'disiplin'=>10,'leadership'=>25,'kompetensi'=>20,'mutu'=>0,'kolaborasi'=>0],
    ];
    return $sets[$roleLevel] ?? $sets['pelaksana'];
}
function lbk_domain_to_weight_bucket(string $domain): string {
    if ($domain === 'mutu') return 'dokumentasi';
    if ($domain === 'kolaborasi') return 'leadership';
    return $domain;
}
function lbk_calculate_domain_kpi(array $domainRows, string $roleLevel, float $verifiedRate): float {
    $weights      = lbk_domain_weights($roleLevel);
    $bucketScores = [];
    foreach ($domainRows as $r) {
        $bucket = lbk_domain_to_weight_bucket((string)($r['kpi_domain'] ?? 'produktivitas'));
        $ideal  = (float)($r['ideal_score'] ?? 0);
        $real   = (float)($r['real_score']  ?? 0);
        $score  = $ideal > 0 ? min(100, ($real / $ideal) * 100) : 0;
        if (!isset($bucketScores[$bucket])) $bucketScores[$bucket] = [];
        $bucketScores[$bucket][] = $score;
    }
    $final = 0.0;
    foreach ($weights as $bucket => $weight) {
        if ($weight <= 0) continue;
        if ($bucket === 'disiplin') {
            $bucketScore = $verifiedRate;
        } elseif (!empty($bucketScores[$bucket])) {
            $bucketScore = array_sum($bucketScores[$bucket]) / count($bucketScores[$bucket]);
        } else {
            $bucketScore = 0;
        }
        $final += ($bucketScore * $weight / 100);
    }
    return round(min(100, max(0, $final)), 2);
}
function lbk_workload_unit_key(string $text): string {
    $t = strtolower(trim($text));
    $t = str_replace(['.', '-', '/', '_'], ' ', $t);
    $t = preg_replace('/\s+/', ' ', $t) ?: '';
    if ($t === '') return 'UMUM';
    if (str_contains($t, 'cempaka')) return 'CEMPAKA';
    if (str_contains($t, 'canigara')) return 'CANIGARA';
    if (str_contains($t, 'cendana')) return 'CENDANA';
    if (str_contains($t, 'igd') || str_contains($t, 'emergency') || str_contains($t, 'gawat darurat')) return 'IGD';
    if (str_contains($t, 'bersalin') || preg_match('/\bvk\b/', $t)) return 'KAMAR_BERSALIN';
    if (preg_match('/\bhd\b/', $t) || str_contains($t, 'hemodialisa') || str_contains($t, 'hemodialisis')) return 'HD';
    if (preg_match('/\bok\b/', $t) || str_contains($t, 'operasi') || str_contains($t, 'bedah sentral')) return 'OK';
    if (str_contains($t, 'poli') || str_contains($t, 'rawat jalan') || str_contains($t, 'rajal')) return 'POLIKLINIK';
    if (str_contains($t, 'ruang bayi') || str_contains($t, 'perinatologi')) return 'RUANG_BAYI';
    if (str_contains($t, 'nicu')) return 'NICU';
    if (str_contains($t, 'icu') || str_contains($t, 'intensive')) return 'ICU';
    if (str_contains($t, 'rawat inap') || str_contains($t, 'ranap')) return 'RAWAT_INAP';
    if (str_contains($t, 'keperawatan') || str_contains($t, 'divisi')) return 'KEPERAWATAN';
    return strtoupper(preg_replace('/[^A-Z0-9]+/', '_', trim(strtoupper($text)), -1) ?: 'UMUM');
}
function lbk_workload_unit_label(string $key): string {
    $labels = [
        'UMUM'=>'Umum / Semua Unit','KEPERAWATAN'=>'Keperawatan','IGD'=>'IGD',
        'KAMAR_BERSALIN'=>'Kamar Bersalin','HD'=>'HD / Hemodialisa','OK'=>'OK / Kamar Operasi',
        'POLIKLINIK'=>'Poliklinik','RAWAT_INAP'=>'Rawat Inap','CANIGARA'=>'Canigara',
        'CEMPAKA'=>'Pav. Cempaka','CENDANA'=>'Cendana','RUANG_BAYI'=>'Ruang Bayi',
        'NICU'=>'NICU','ICU'=>'ICU',
    ];
    return $labels[$key] ?? ucwords(strtolower(str_replace('_',' ', $key)));
}
function lbk_workload_level_from_occupancy(float $occupancy): array {
    if ($occupancy < 50) return ['Rendah',        0.90, 'text-slate-700 bg-slate-50 border-slate-200'];
    if ($occupancy < 70) return ['Sedang',         1.00, 'text-blue-700 bg-blue-50 border-blue-200'];
    if ($occupancy < 90) return ['Tinggi',         1.15, 'text-amber-700 bg-amber-50 border-amber-200'];
    return                      ['Sangat Tinggi',  1.30, 'text-rose-700 bg-rose-50 border-rose-200'];
}
function lbk_workload_options(array $units): array {
    $opts = [
        'IGD'=>'IGD','KAMAR_BERSALIN'=>'Kamar Bersalin','HD'=>'HD / Hemodialisa',
        'OK'=>'OK / Kamar Operasi','POLIKLINIK'=>'Poliklinik','RAWAT_INAP'=>'Rawat Inap',
        'CANIGARA'=>'Canigara','CEMPAKA'=>'Pav. Cempaka','CENDANA'=>'Cendana',
        'RUANG_BAYI'=>'Ruang Bayi','NICU'=>'NICU','ICU'=>'ICU','KEPERAWATAN'=>'Keperawatan',
    ];
    foreach ($units as $u) {
        $name = (string)($u['name'] ?? '');
        if ($name === '') continue;
        $key = lbk_workload_unit_key($name);
        if (!isset($opts[$key])) $opts[$key] = $name;
    }
    return $opts;
}
function lbk_entry_unit_key_case_sql(string $column = 'le.unit_name'): string {
    return "CASE
        WHEN LOWER(COALESCE($column,'')) LIKE '%cempaka%' THEN 'CEMPAKA'
        WHEN LOWER(COALESCE($column,'')) LIKE '%canigara%' THEN 'CANIGARA'
        WHEN LOWER(COALESCE($column,'')) LIKE '%cendana%' THEN 'CENDANA'
        WHEN LOWER(COALESCE($column,'')) LIKE '%igd%' THEN 'IGD'
        WHEN LOWER(COALESCE($column,'')) LIKE '%bersalin%' OR LOWER(COALESCE($column,'')) LIKE '%vk%' THEN 'KAMAR_BERSALIN'
        WHEN LOWER(COALESCE($column,'')) LIKE '%hemodialisa%' OR LOWER(COALESCE($column,'')) LIKE '%hemodialisis%' OR LOWER(COALESCE($column,'')) = 'hd' THEN 'HD'
        WHEN LOWER(COALESCE($column,'')) LIKE '%operasi%' OR LOWER(COALESCE($column,'')) = 'ok' THEN 'OK'
        WHEN LOWER(COALESCE($column,'')) LIKE '%poli%' OR LOWER(COALESCE($column,'')) LIKE '%rawat jalan%' THEN 'POLIKLINIK'
        WHEN LOWER(COALESCE($column,'')) LIKE '%ruang bayi%' THEN 'RUANG_BAYI'
        WHEN LOWER(COALESCE($column,'')) LIKE '%nicu%' THEN 'NICU'
        WHEN LOWER(COALESCE($column,'')) LIKE '%icu%' THEN 'ICU'
        WHEN LOWER(COALESCE($column,'')) LIKE '%rawat inap%' THEN 'RAWAT_INAP'
        WHEN LOWER(COALESCE($column,'')) LIKE '%keperawatan%' THEN 'KEPERAWATAN'
        ELSE UPPER(REPLACE(REPLACE(REPLACE(TRIM(COALESCE($column,'UMUM')),'.',''),'/','_'),' ','_'))
    END";
}


function lbk_nursing_canonical_seed(): array {
    return [
        ['IGD',1,'IGD',1],
        ['KAMAR_BERSALIN',2,'VK / Kamar Bersalin',2],
        ['HD',3,'HD / Hemodialisa',3],
        ['POLIKLINIK',4,'Poliklinik',4],
        ['OK',5,'OK / Kamar Operasi',5],
        ['CANIGARA',6,'Pav. Canigara',6],
        ['CEMPAKA',7,'Pav. Cempaka',7],
        ['CENDANA',8,'Pav. Cendana',8],
        ['ICU',11,'ICU',9],
        ['NICU',10,'NICU',10],
        ['RUANG_BAYI',9,'Ruang Bayi',11],
    ];
}
function lbk_nursing_mapping_seed(): array {
    return [
        [1,1,'IGD'], [25,1,'UGD'],
        [2,2,'VK / Kamar Bersalin'], [27,2,'VK (BERSALIN)'], [77,2,'Kamar Bersalin (VK)'], [84,2,'VK / Kamar Bersalin'],
        [3,3,'HD / Hemodialisa'], [20,3,'HEMODIALISA'], [71,3,'Hemodialisis (HD)'], [87,3,'HD / Hemodialisa'],
        [4,4,'Poliklinik'], [86,4,'Poliklinik'],
        [5,5,'OK / Kamar Operasi'], [22,5,'KAMAR OPERASI (OK)'], [85,5,'OK / Kamar Operasi'],
        [6,6,'Pav. Canigara'], [21,6,'Pav. Canigara'],
        [7,7,'Pav. Cempaka'], [24,7,'Pav. Cempaka'],
        [8,8,'Pav. Cendana'], [23,8,'Pav. Cendana'], [88,8,'Pav. Cendana'],
        [11,11,'ICU'], [10,10,'NICU'],
        [9,9,'Ruang Bayi'], [92,9,'Ruang Bayi'],
    ];
}
function lbk_canonical_unit_id(mysqli $conn, int $unitId): int {
    if ($unitId <= 0) return 0;
    $r = lbk_one($conn, "SELECT canonical_unit_id FROM logbook_kpi_unit_mapping WHERE source_unit_id=? AND is_active=1 LIMIT 1", [$unitId], 'i');
    return (int)($r['canonical_unit_id'] ?? $unitId);
}
function lbk_can_manage_nursing_staff(string $level, bool $isAdmin): bool {
    return $isAdmin || in_array($level, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true);
}
function lbk_can_manage_target_unit(mysqli $conn, string $level, bool $isAdmin, int $ownUnitId, int $targetUnitId): bool {
    if ($isAdmin || in_array($level, ['kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true)) return true;
    if ($level !== 'kaunit') return false;
    return lbk_canonical_unit_id($conn, $ownUnitId) === lbk_canonical_unit_id($conn, $targetUnitId);
}


function lbk_schedule_normalize_name(string $name): string {
    $name = strtoupper(trim($name));
    $name = preg_replace('/\b(NS|NURSE|S\s*KEP|S\.KEP|A\.MD\.KEP|AMK|S\.TR\.KEP|SKM|M\.KEP)\b\.?/iu', ' ', $name) ?? $name;
    $name = preg_replace('/[^A-Z0-9]+/u', ' ', $name) ?? $name;
    return trim(preg_replace('/\s+/', ' ', $name) ?? $name);
}
function lbk_xlsx_col_index(string $letters): int {
    $n=0; foreach(str_split(strtoupper($letters)) as $ch){ $n=$n*26+(ord($ch)-64); } return $n;
}
function lbk_read_simple_xlsx(string $file): array {
    if (!class_exists('ZipArchive')) {
        throw new RuntimeException('Ekstensi PHP ZipArchive belum aktif di hosting.');
    }

    $zip = new ZipArchive();
    if ($zip->open($file) !== true) {
        throw new RuntimeException('File Excel tidak dapat dibuka.');
    }

    libxml_use_internal_errors(true);
    $shared = [];
    $ss = $zip->getFromName('xl/sharedStrings.xml');
    if ($ss !== false) {
        $sharedXml = simplexml_load_string($ss);
        if ($sharedXml !== false) {
            // Gunakan local-name() agar aman pada file XLSX dengan namespace/default prefix berbeda.
            foreach (($sharedXml->xpath('//*[local-name()="si"]') ?: []) as $si) {
                $txt = '';
                foreach (($si->xpath('.//*[local-name()="t"]') ?: []) as $t) {
                    $txt .= (string)$t;
                }
                $shared[] = $txt;
            }
        }
    }

    // Ambil worksheet pertama yang benar-benar tersedia.
    $sheet = $zip->getFromName('xl/worksheets/sheet1.xml');
    if ($sheet === false) {
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $name = (string)$zip->getNameIndex($i);
            if (preg_match('#^xl/worksheets/sheet\d+\.xml$#', $name)) {
                $sheet = $zip->getFromIndex($i);
                break;
            }
        }
    }
    $zip->close();

    if ($sheet === false) {
        throw new RuntimeException('Sheet Excel tidak ditemukan.');
    }

    $sheetXml = simplexml_load_string($sheet);
    if ($sheetXml === false) {
        throw new RuntimeException('Struktur Excel tidak valid.');
    }

    $rows = [];
    foreach (($sheetXml->xpath('//*[local-name()="sheetData"]/*[local-name()="row"]') ?: []) as $row) {
        $ri = (int)$row['r'];
        if ($ri <= 0) {
            $ri = count($rows) + 1;
        }
        $vals = [];

        foreach (($row->xpath('./*[local-name()="c"]') ?: []) as $c) {
            $ref = (string)$c['r'];
            preg_match('/([A-Z]+)(\d+)/i', $ref, $m);
            $ci = lbk_xlsx_col_index($m[1] ?? 'A');
            $type = (string)$c['t'];
            $valueNodes = $c->xpath('./*[local-name()="v"]') ?: [];
            $v = isset($valueNodes[0]) ? (string)$valueNodes[0] : '';

            if ($type === 's' && $v !== '') {
                $v = $shared[(int)$v] ?? '';
            } elseif ($type === 'inlineStr') {
                $v = '';
                foreach (($c->xpath('.//*[local-name()="is"]//*[local-name()="t"]') ?: []) as $t) {
                    $v .= (string)$t;
                }
            }

            $vals[$ci] = trim($v);
        }
        $rows[$ri] = $vals;
    }

    libxml_clear_errors();
    return $rows;
}
function lbk_schedule_shift_defaults(): array {
    return [
        ['P1','Pagi','07:00:00','14:00:00',1,0],['P','Pagi','07:00:00','14:00:00',1,0],
        ['S1','Sore','14:00:00','21:00:00',1,0],['S','Sore','14:00:00','21:00:00',1,0],
        ['M','Malam','21:00:00','07:00:00',1,1],['M2X','Malam','21:00:00','07:00:00',1,1],
        ['PS1','Pagi-Sore','07:00:00','21:00:00',1,0],['PSE1','Pagi-Sore','07:00:00','21:00:00',1,0],
        ['BO1','Back Office','08:00:00','16:00:00',1,0],['BO2','Back Office','08:00:00','16:00:00',1,0],
        ['L','Libur',null,null,0,0],['CUTI','Cuti',null,null,0,0],['OFF','Libur',null,null,0,0]
    ];
}


function lbk_shift_duration_policy(string $shift): array {
    return match ($shift) {
        'Pagi'  => ['max_minutes'=>420, 'break_minutes'=>60, 'label'=>'Maksimal 7 jam kegiatan + 1 jam istirahat'],
        'Sore'  => ['max_minutes'=>420, 'break_minutes'=>60, 'label'=>'Maksimal 7 jam kegiatan + 1 jam istirahat'],
        'Malam' => ['max_minutes'=>720, 'break_minutes'=>60, 'label'=>'Maksimal 12 jam kegiatan + 1 jam istirahat'],
        default => ['max_minutes'=>0, 'break_minutes'=>0, 'label'=>'Tidak dibatasi'],
    };
}
function lbk_shift_used_minutes(mysqli $conn, int $userId, int $employeeId, string $logDate, string $shift, int $excludeId=0): int {
    $sql = "SELECT COALESCE(SUM(duration_minutes),0) total_minutes
            FROM logbook_kpi_entries
            WHERE log_date=? AND shift=? AND status<>'rejected'
              AND ((? > 0 AND employee_id=?) OR user_id=?)";
    $params = [$logDate,$shift,$employeeId,$employeeId,$userId];
    $types = 'ssiii';
    if ($excludeId > 0) {
        $sql .= " AND id<>?";
        $params[] = $excludeId;
        $types .= 'i';
    }
    $row = lbk_one($conn,$sql,$params,$types);
    return max(0,(int)($row['total_minutes']??0));
}
function lbk_format_minutes(int $minutes): string {
    $minutes=max(0,$minutes);
    $h=intdiv($minutes,60); $m=$minutes%60;
    if($h>0 && $m>0) return $h.' jam '.$m.' menit';
    if($h>0) return $h.' jam';
    return $m.' menit';
}

function lbk_ensure_schema(mysqli $conn): void {
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_categories (
        id INT AUTO_INCREMENT PRIMARY KEY,
        code VARCHAR(10) NOT NULL UNIQUE,
        name VARCHAR(120) NOT NULL,
        description TEXT NULL,
        color VARCHAR(40) DEFAULT '#2563eb',
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_activity_master (
        id INT AUTO_INCREMENT PRIMARY KEY,
        role_level ENUM('pelaksana','katim','kaunit','kasubdiv','kadiv') NOT NULL,
        unit_group VARCHAR(60) NOT NULL DEFAULT 'UMUM',
        category_code VARCHAR(10) NOT NULL,
        activity_name VARCHAR(220) NOT NULL,
        description TEXT NULL,
        ideal_frequency_type ENUM('per_shift','daily','weekly','monthly','event') NOT NULL DEFAULT 'daily',
        ideal_frequency_value DECIMAL(10,2) NOT NULL DEFAULT 1,
        unit_measure VARCHAR(60) DEFAULT 'kegiatan',
        weight DECIMAL(10,2) NOT NULL DEFAULT 1,
        kpi_domain ENUM('produktivitas','dokumentasi','patient_safety','disiplin','leadership','kompetensi','mutu','kolaborasi') NOT NULL DEFAULT 'produktivitas',
        evidence_required TINYINT(1) NOT NULL DEFAULT 0,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX idx_role(role_level), INDEX idx_unit_group(unit_group), INDEX idx_cat(category_code), INDEX idx_active(is_active)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_entries (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
        employee_id BIGINT UNSIGNED NULL,
        employee_name VARCHAR(160) NOT NULL,
        role_level ENUM('pelaksana','katim','kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv') NOT NULL,
        unit_id BIGINT UNSIGNED NULL,
        unit_name VARCHAR(160) NULL,
        log_date DATE NOT NULL,
        shift ENUM('Pagi','Sore','Malam','Non Shift','Libur') NOT NULL DEFAULT 'Pagi',
        activity_time TIME NULL,
        patient_room VARCHAR(80) NULL,
        activity_id INT NOT NULL,
        activity_name VARCHAR(220) NOT NULL,
        category_code VARCHAR(10) NOT NULL,
        kpi_domain VARCHAR(40) NOT NULL,
        ideal_count DECIMAL(10,2) NOT NULL DEFAULT 1,
        real_count DECIMAL(10,2) NOT NULL DEFAULT 0,
        weight DECIMAL(10,2) NOT NULL DEFAULT 1,
        duration_minutes INT NOT NULL DEFAULT 0,
        patients_count INT NOT NULL DEFAULT 0,
        quality_score DECIMAL(5,2) NULL,
        notes TEXT NULL,
        evidence_note VARCHAR(255) NULL,
        status ENUM('draft','submitted','verified','rejected') NOT NULL DEFAULT 'submitted',
        verified_by BIGINT UNSIGNED NULL,
        verified_by_name VARCHAR(160) NULL,
        verified_at DATETIME NULL,
        verifier_note TEXT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX idx_user_date(user_id, log_date), INDEX idx_unit_date(unit_id, log_date), INDEX idx_status(status), INDEX idx_role(role_level)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_entries MODIFY role_level ENUM('pelaksana','katim','kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv') NOT NULL");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_entries ADD COLUMN activity_time TIME NULL AFTER shift");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_entries ADD COLUMN patient_room VARCHAR(80) NULL AFTER activity_time");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_entries ADD INDEX idx_activity_time(activity_time)");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_entries ADD INDEX idx_patient_room(patient_room)");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_activity_master MODIFY role_level ENUM('pelaksana','katim','kaunit','kasubdiv','kadiv') NOT NULL");
    lbk_exec($conn, "UPDATE logbook_kpi_activity_master SET role_level='kaunit' WHERE role_level='kasubdiv' AND unit_group <> 'UMUM'");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_activity_master ADD COLUMN unit_group VARCHAR(60) NOT NULL DEFAULT 'UMUM' AFTER role_level");
    lbk_exec($conn, "ALTER TABLE logbook_kpi_activity_master ADD INDEX idx_unit_group(unit_group)");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_salary_refs (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT UNSIGNED NOT NULL,
        month TINYINT NOT NULL,
        year SMALLINT NOT NULL,
        salary_amount DECIMAL(15,2) NOT NULL DEFAULT 0,
        note VARCHAR(255) NULL,
        created_by BIGINT UNSIGNED NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_salary(user_id, month, year)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_unit_workload_daily (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        workload_date DATE NOT NULL,
        unit_key VARCHAR(80) NOT NULL,
        unit_label VARCHAR(160) NOT NULL,
        patient_count DECIMAL(10,2) NOT NULL DEFAULT 0,
        los_count DECIMAL(10,2) NOT NULL DEFAULT 0,
        bed_capacity INT NOT NULL DEFAULT 0,
        nurses_per_shift INT NOT NULL DEFAULT 0,
        nurse_count INT NOT NULL DEFAULT 0,
        occupancy_percent DECIMAL(8,2) NOT NULL DEFAULT 0,
        patient_per_nurse_shift DECIMAL(8,2) NOT NULL DEFAULT 0,
        los_per_nurse DECIMAL(8,2) NOT NULL DEFAULT 0,
        workload_level VARCHAR(40) NOT NULL DEFAULT 'Rendah',
        multiplier DECIMAL(5,2) NOT NULL DEFAULT 1.00,
        note VARCHAR(255) NULL,
        created_by BIGINT UNSIGNED NULL,
        created_by_name VARCHAR(160) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_unit_date(unit_key, workload_date),
        INDEX idx_workload_date(workload_date),
        INDEX idx_unit_key(unit_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_unit_workload_monthly (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        unit_key VARCHAR(80) NOT NULL,
        unit_label VARCHAR(160) NOT NULL,
        month TINYINT NOT NULL,
        year SMALLINT NOT NULL,
        total_patients DECIMAL(12,2) NOT NULL DEFAULT 0,
        total_staff INT NOT NULL DEFAULT 0,
        avg_staff_per_shift DECIMAL(10,2) NOT NULL DEFAULT 0,
        bed_capacity INT NOT NULL DEFAULT 0,
        independent_patients DECIMAL(12,2) NOT NULL DEFAULT 0,
        partial_care_patients DECIMAL(12,2) NOT NULL DEFAULT 0,
        total_care_patients DECIMAL(12,2) NOT NULL DEFAULT 0,
        standard_independent DECIMAL(10,2) NOT NULL DEFAULT 5,
        standard_partial DECIMAL(10,2) NOT NULL DEFAULT 10,
        standard_total_care DECIMAL(10,2) NOT NULL DEFAULT 15,
        ideal_unit_activities DECIMAL(14,2) NOT NULL DEFAULT 0,
        ideal_staff_activities DECIMAL(14,2) NOT NULL DEFAULT 0,
        note TEXT NULL,
        created_by BIGINT UNSIGNED NULL,
        created_by_name VARCHAR(160) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_unit_month(unit_key, month, year),
        INDEX idx_period(year, month),
        INDEX idx_unit_key(unit_key)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_patient_assignments (
        id BIGINT AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
        employee_id BIGINT UNSIGNED NULL,
        employee_name VARCHAR(160) NOT NULL,
        unit_id BIGINT UNSIGNED NULL,
        unit_name VARCHAR(160) NULL,
        assign_date DATE NOT NULL,
        shift ENUM('Pagi','Sore','Malam','Non Shift','Libur') NOT NULL DEFAULT 'Pagi',
        patient_count INT NOT NULL DEFAULT 0,
        room_list TEXT NULL,
        note VARCHAR(255) NULL,
        created_by BIGINT UNSIGNED NULL,
        created_by_name VARCHAR(160) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_assignment(user_id, assign_date, shift),
        INDEX idx_assign_date(assign_date),
        INDEX idx_user_shift(user_id, assign_date, shift)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");


    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_nursing_units (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        unit_key VARCHAR(50) NOT NULL,
        unit_id BIGINT UNSIGNED NOT NULL,
        display_name VARCHAR(150) NOT NULL,
        sort_order INT NOT NULL DEFAULT 0,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_nursing_key(unit_key),
        UNIQUE KEY uniq_nursing_unit(unit_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_unit_mapping (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        source_unit_id BIGINT UNSIGNED NOT NULL,
        canonical_unit_id BIGINT UNSIGNED NOT NULL,
        source_unit_name VARCHAR(150) NULL,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_mapping_source(source_unit_id),
        INDEX idx_mapping_canonical(canonical_unit_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_staff_unit_audit (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        employee_id BIGINT UNSIGNED NOT NULL,
        action_type VARCHAR(40) NOT NULL,
        old_unit_id BIGINT UNSIGNED NULL,
        new_unit_id BIGINT UNSIGNED NULL,
        old_status VARCHAR(40) NULL,
        new_status VARCHAR(40) NULL,
        note VARCHAR(255) NULL,
        acted_by BIGINT UNSIGNED NULL,
        acted_by_name VARCHAR(160) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_staff_audit_employee(employee_id),
        INDEX idx_staff_audit_created(created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    foreach (lbk_nursing_canonical_seed() as $nu) {
        [$key,$uid,$label,$sort] = $nu;
        $st = $conn->prepare("INSERT INTO logbook_kpi_nursing_units(unit_key,unit_id,display_name,sort_order,is_active) VALUES(?,?,?,?,1) ON DUPLICATE KEY UPDATE unit_id=VALUES(unit_id),display_name=VALUES(display_name),sort_order=VALUES(sort_order),is_active=1");
        if ($st) { $st->bind_param('sisi',$key,$uid,$label,$sort); $st->execute(); $st->close(); }
    }
    foreach (lbk_nursing_mapping_seed() as $mp) {
        [$source,$canonical,$sourceName] = $mp;
        $st = $conn->prepare("INSERT INTO logbook_kpi_unit_mapping(source_unit_id,canonical_unit_id,source_unit_name,is_active) VALUES(?,?,?,1) ON DUPLICATE KEY UPDATE canonical_unit_id=VALUES(canonical_unit_id),source_unit_name=VALUES(source_unit_name),is_active=1");
        if ($st) { $st->bind_param('iis',$source,$canonical,$sourceName); $st->execute(); $st->close(); }
    }


    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_shift_codes (
        code VARCHAR(30) PRIMARY KEY, shift_name VARCHAR(80) NOT NULL,
        start_time TIME NULL, end_time TIME NULL, requires_logbook TINYINT(1) NOT NULL DEFAULT 1,
        crosses_midnight TINYINT(1) NOT NULL DEFAULT 0, is_active TINYINT(1) NOT NULL DEFAULT 1,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_schedule_uploads (
        id BIGINT AUTO_INCREMENT PRIMARY KEY, unit_id BIGINT UNSIGNED NOT NULL,
        month TINYINT NOT NULL, year SMALLINT NOT NULL, original_filename VARCHAR(255) NULL,
        total_rows INT NOT NULL DEFAULT 0, matched_rows INT NOT NULL DEFAULT 0, unmatched_rows INT NOT NULL DEFAULT 0,
        uploaded_by BIGINT UNSIGNED NULL, uploaded_by_name VARCHAR(160) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_period(unit_id,year,month)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    lbk_exec($conn, "CREATE TABLE IF NOT EXISTS logbook_kpi_staff_schedules (
        id BIGINT AUTO_INCREMENT PRIMARY KEY, upload_id BIGINT NULL, unit_id BIGINT UNSIGNED NOT NULL,
        employee_id BIGINT UNSIGNED NULL, employee_name_excel VARCHAR(180) NOT NULL,
        normalized_name VARCHAR(180) NOT NULL, schedule_date DATE NOT NULL, shift_code VARCHAR(30) NOT NULL,
        requires_logbook TINYINT(1) NOT NULL DEFAULT 1, match_status ENUM('matched','unmatched','manual') NOT NULL DEFAULT 'matched',
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY uniq_schedule(unit_id,schedule_date,employee_name_excel),
        INDEX idx_schedule_date(schedule_date), INDEX idx_schedule_employee(employee_id,schedule_date), INDEX idx_schedule_unit(unit_id,schedule_date)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    foreach (lbk_schedule_shift_defaults() as $sd) {
        [$sc,$sn,$st,$et,$req,$cross]=$sd;
        $q=$conn->prepare("INSERT INTO logbook_kpi_shift_codes(code,shift_name,start_time,end_time,requires_logbook,crosses_midnight,is_active) VALUES(?,?,?,?,?,?,1) ON DUPLICATE KEY UPDATE shift_name=VALUES(shift_name),start_time=VALUES(start_time),end_time=VALUES(end_time),requires_logbook=VALUES(requires_logbook),crosses_midnight=VALUES(crosses_midnight),is_active=1");
        if($q){$q->bind_param('ssssii',$sc,$sn,$st,$et,$req,$cross);$q->execute();$q->close();}
    }

    $row = lbk_one($conn, "SELECT COUNT(*) c FROM logbook_kpi_categories");
    if ((int)($row['c'] ?? 0) === 0) {
        $cats = [
            ['A','Asuhan Keperawatan Langsung','#0ea5e9'],
            ['B','Dokumentasi Keperawatan','#6366f1'],
            ['C','Edukasi Pasien/Keluarga','#22c55e'],
            ['D','Keselamatan Pasien','#ef4444'],
            ['E','Kolaborasi Interprofesional','#14b8a6'],
            ['F','Manajemen Shift/Tim','#f97316'],
            ['G','Mutu dan Audit','#8b5cf6'],
            ['H','Pendidikan dan Pelatihan','#06b6d4'],
            ['I','Administrasi dan Laporan','#64748b'],
            ['J','Pengembangan Profesional','#ec4899'],
        ];
        foreach ($cats as $c) {
            $stmt = $conn->prepare("INSERT IGNORE INTO logbook_kpi_categories(code,name,color) VALUES(?,?,?)");
            if ($stmt) { $stmt->bind_param('sss', $c[0], $c[1], $c[2]); $stmt->execute(); $stmt->close(); }
        }
    }
    lbk_seed_core_activity_master($conn);
    lbk_seed_unit_activity_master($conn);
}

function lbk_seed_unit_activity_master(mysqli $conn): void {
    $items = lbk_seed_unit_items();
    $stmt  = $conn->prepare("INSERT INTO logbook_kpi_activity_master(role_level,unit_group,category_code,activity_name,description,ideal_frequency_type,ideal_frequency_value,unit_measure,weight,kpi_domain,evidence_required,is_active) SELECT ?,?,?,?,?,?,?,?,?,?,?,1 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM logbook_kpi_activity_master WHERE role_level=? AND unit_group=? AND activity_name=? LIMIT 1)");
    if (!$stmt) return;
    foreach ($items as $it) {
        [$role,$unitGroup,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence] = $it;
        $stmt->bind_param('ssssssdsdsisss', $role,$unitGroup,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence,$role,$unitGroup,$name);
        $stmt->execute();
    }
    $stmt->close();
}
function lbk_seed_core_activity_master(mysqli $conn): void {
    $items = lbk_seed_items();
    $stmt  = $conn->prepare("INSERT INTO logbook_kpi_activity_master(role_level,unit_group,category_code,activity_name,description,ideal_frequency_type,ideal_frequency_value,unit_measure,weight,kpi_domain,evidence_required,is_active) SELECT ?,'UMUM',?,?,?,?,?,?,?,?,?,1 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM logbook_kpi_activity_master WHERE role_level=? AND unit_group='UMUM' AND activity_name=? LIMIT 1)");
    if (!$stmt) return;
    foreach ($items as $it) {
        [$role,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence] = $it;
        $stmt->bind_param('sssssdsdsiss', $role,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence,$role,$name);
        $stmt->execute();
    }
    $stmt->close();
}
function lbk_seed_items(): array {
    return [
        ['pelaksana','F','Operan pasien awal shift','Menerima/melakukan timbang terima pasien dengan SBAR','per_shift',1,'kegiatan',3,'kolaborasi',0],
        ['pelaksana','D','Identifikasi pasien sebelum tindakan','Kepatuhan identifikasi 2 identitas sebelum tindakan','per_shift',10,'tindakan',5,'patient_safety',0],
        ['pelaksana','A','Pengkajian awal/lanjutan pasien','Pengkajian awal atau lanjutan sesuai pasien kelolaan','per_shift',5,'pasien',5,'produktivitas',1],
        ['pelaksana','B','Menyusun atau memperbarui diagnosa keperawatan','Diagnosa keperawatan SDKI/NANDA sesuai prioritas pasien','daily',1,'diagnosa',4,'dokumentasi',1],
        ['pelaksana','A','Melaksanakan intervensi keperawatan','Implementasi intervensi sesuai rencana asuhan dan kondisi pasien','per_shift',8,'tindakan',5,'produktivitas',0],
        ['pelaksana','A','Monitoring tanda vital','Monitoring TTV, nyeri, dan respons terapi sesuai kondisi pasien','per_shift',10,'observasi',4,'patient_safety',0],
        ['pelaksana','D','Pemberian obat sesuai delegasi/SOP','Pemberian obat dengan prinsip benar obat dan dokumentasi pemberian','per_shift',6,'pemberian',5,'patient_safety',1],
        ['pelaksana','C','Edukasi pasien dan keluarga','Edukasi obat, diet, mobilisasi, kontrol, dan tanda bahaya','per_shift',2,'edukasi',3,'kompetensi',1],
        ['pelaksana','D','Pencegahan risiko jatuh','Assessment risiko jatuh dan intervensi pencegahan','per_shift',3,'pasien',4,'patient_safety',1],
        ['pelaksana','D','Pencegahan luka tekan','Reposisi, Braden, proteksi kulit, dan evaluasi risiko luka tekan','per_shift',3,'pasien',4,'patient_safety',1],
        ['pelaksana','B','Dokumentasi CPPT/SOAP','Dokumentasi CPPT/SOAP lengkap dan tepat waktu','per_shift',5,'dokumen',5,'dokumentasi',1],
        ['pelaksana','E','Melaporkan perubahan kondisi pasien','Pelaporan perubahan kondisi pasien menggunakan SBAR/komunikasi efektif','event',1,'laporan',5,'kolaborasi',1],
        ['pelaksana','I','Discharge planning','Persiapan pulang, edukasi, obat, kontrol, dan kebutuhan rumah','event',1,'pasien',4,'mutu',1],
        ['pelaksana','F','Mengikuti briefing atau meeting unit','Kehadiran dan partisipasi pada briefing/meeting unit','daily',1,'kegiatan',2,'disiplin',0],
        ['pelaksana','D','Melaporkan insiden atau near miss','Pelaporan IKP/near miss sesuai alur keselamatan pasien','event',1,'laporan',5,'patient_safety',1],
        ['pelaksana','I','Menjaga kebersihan area kerja dan alat','Kerapian area kerja, alat siap pakai, dan pengembalian alat','per_shift',1,'checklist',2,'disiplin',0],
        ['pelaksana','D','Hand hygiene sesuai 5 moment','Kepatuhan hand hygiene pada 5 moment pelayanan pasien','per_shift',10,'momen',5,'patient_safety',0],
        ['pelaksana','H','Mengikuti pelatihan/in house training','Mengikuti kegiatan diklat, refreshment, sosialisasi, atau kompetensi unit','event',1,'kegiatan',3,'kompetensi',1],
        ['pelaksana','C','Komunikasi terapeutik','Komunikasi terapeutik, empati, dan caring behavior kepada pasien/keluarga','per_shift',5,'interaksi',3,'kompetensi',0],
        ['pelaksana','I','Pengisian logbook harian','Submit logbook harian dengan catatan jelas dan jujur','daily',1,'laporan',3,'disiplin',0],
        ['katim','F','Menerima dan memimpin operan shift','Memimpin timbang terima, pembacaan risiko, dan rencana shift','per_shift',1,'kegiatan',4,'leadership',0],
        ['katim','F','Membagi pasien kepada perawat pelaksana','Assignment pasien sesuai kompleksitas dan kompetensi staf','per_shift',1,'assignment',5,'leadership',1],
        ['katim','D','Menentukan prioritas pasien risiko tinggi','Menentukan prioritas pasien kritis, jatuh, luka tekan, dan risiko klinis','per_shift',1,'daftar',5,'patient_safety',1],
        ['katim','B','Validasi askep perawat pelaksana','Review CPPT, askep, diagnosa, intervensi, dan evaluasi staf','per_shift',5,'dokumen',5,'dokumentasi',1],
        ['katim','A','Supervisi tindakan keperawatan berisiko','Pendampingan tindakan invasif atau tindakan berisiko tinggi','event',1,'supervisi',5,'patient_safety',1],
        ['katim','D','Memastikan kepatuhan identifikasi pasien','Audit singkat identifikasi pasien di area shift','per_shift',3,'audit',4,'patient_safety',1],
        ['katim','B','Memastikan CPPT terisi lengkap','Review kelengkapan CPPT/rekam dokumentasi pada shift berjalan','per_shift',5,'dokumen',5,'dokumentasi',1],
        ['katim','E','Memfasilitasi komunikasi dengan dokter','Koordinasi DPJP/dokter jaga menggunakan SBAR bila diperlukan','event',1,'koordinasi',4,'kolaborasi',1],
        ['katim','E','Mengelola konflik atau keluhan pasien awal','Respons awal keluhan pasien/keluarga dan eskalasi bila perlu','event',1,'kasus',4,'kolaborasi',1],
        ['katim','H','Coaching staf baru atau junior','Pembinaan klinis singkat berbasis kasus dan kompetensi','weekly',2,'sesi',4,'kompetensi',1],
        ['katim','I','Monitoring ketersediaan alat dan obat penting','Cek alat emergensi, obat high alert, dan kesiapan layanan','per_shift',1,'checklist',3,'mutu',1],
        ['katim','G','Mini audit hand hygiene/PPI','Audit singkat hand hygiene, APD, isolasi, dan kepatuhan PPI','weekly',3,'audit',4,'mutu',1],
        ['katim','D','Mengawal pasien risiko jatuh/luka tekan','Monitoring daftar pasien risiko dan tindak lanjut pencegahan','per_shift',1,'daftar',5,'patient_safety',1],
        ['katim','I','Membuat laporan situasi shift','Laporan kondisi pasien, SDM, alat, dan masalah unit','per_shift',1,'laporan',4,'dokumentasi',1],
        ['katim','F','Verifikasi logbook perawat pelaksana','Validasi aktivitas staf di bawah koordinasi shift','daily',5,'verifikasi',5,'leadership',0],
        ['katim','E','Melaporkan masalah unit ke Karu/Kasubdiv','Eskalasi masalah signifikan ke Kepala Unit/Kasubdiv','event',1,'laporan',4,'kolaborasi',1],
        ['katim','C','Memastikan edukasi pasien berjalan','Sampling edukasi pasien/keluarga dan kelengkapan form edukasi','per_shift',2,'edukasi',3,'kompetensi',1],
        ['katim','I','Mengisi logbook Katim/PJ Shift','Submit logbook Katim/PJ shift secara lengkap','daily',1,'laporan',3,'disiplin',0],
        ['kaunit','I','Monitoring laporan harian unit','Review laporan shift, masalah, SDM, alat, dan kondisi unit','daily',1,'dashboard',5,'leadership',0],
        ['kaunit','F','Validasi masalah unit dan tindak lanjut','Memastikan masalah unit memiliki PIC, target waktu, dan tindak lanjut','daily',1,'validasi',5,'leadership',1],
        ['kaunit','I','Monitoring kecukupan SDM per shift','Analisis rasio pasien-perawat dan gap SDM unit','daily',1,'analisis',5,'mutu',1],
        ['kaunit','G','Supervisi lapangan ke unit','Supervisi pelayanan, dokumentasi, dan kepatuhan SOP di unit','weekly',3,'kunjungan',5,'mutu',1],
        ['kaunit','G','Review indikator mutu unit','Review indikator mutu, insiden, dan trend capaian unit','weekly',1,'review',4,'mutu',1],
        ['kaunit','D','Review insiden keselamatan pasien unit','Telaah IKP/near miss dan tindak lanjut awal di unit','event',1,'kasus',5,'patient_safety',1],
        ['kaunit','E','Menindaklanjuti keluhan pasien/keluarga','Follow up keluhan pasien/keluarga yang berkaitan dengan unit','event',1,'kasus',4,'kolaborasi',1],
        ['kaunit','B','Monitoring kepatuhan dokumentasi askep','Audit kelengkapan CPPT/askep unit secara sampling','weekly',5,'dokumen',5,'dokumentasi',1],
        ['kaunit','G','Monitoring pelaksanaan program PPI','Audit PPI, hand hygiene, APD, dan kepatuhan isolasi di unit','weekly',1,'audit',4,'mutu',1],
        ['kaunit','H','Pembinaan Katim dan staf','Coaching leadership dan pembinaan staf unit','weekly',2,'sesi',4,'kompetensi',1],
        ['kaunit','I','Menyusun laporan bulanan unit','Konsolidasi capaian, masalah, SDM, dan rencana perbaikan unit','monthly',1,'laporan',5,'dokumentasi',1],
        ['kaunit','I','Monitoring absensi, keterlambatan, cuti, sakit','Rekap disiplin dan kehadiran staf unit','daily',1,'rekap',4,'disiplin',1],
        ['kaunit','H','Mengusulkan kebutuhan pelatihan staf','Identifikasi kebutuhan diklat/TNA berdasarkan gap kompetensi unit','monthly',1,'usulan',4,'kompetensi',1],
        ['kaunit','G','Mengevaluasi logbook unit','Analisis real vs ideal aktivitas unit dan validitas data','monthly',1,'rekap',5,'produktivitas',1],
        ['kaunit','E','Koordinasi lintas unit','Koordinasi masalah pelayanan lintas unit/divisi','event',1,'koordinasi',4,'kolaborasi',1],
        ['kaunit','I','Monitoring BOR/kunjungan/tindakan unit','Review beban kerja unit berbasis data layanan','daily',1,'data',4,'mutu',1],
        ['kaunit','J','Mengawal program peningkatan mutu unit','PDSA/project improvement dan tindak lanjut temuan unit','monthly',1,'project',5,'mutu',1],
        ['kaunit','I','Verifikasi KPI Katim/staf unit','Review dan approval KPI awal staf unit','monthly',1,'approval',5,'leadership',1],
        ['kasubdiv','I','Monitoring laporan harian unit di bawah sub divisi','Review laporan unit di bawah sub divisi','daily',1,'dashboard',5,'leadership',0],
        ['kasubdiv','F','Validasi masalah unit dan tindak lanjut','Memastikan masalah unit mendapat PIC dan deadline','daily',1,'validasi',5,'leadership',1],
        ['kasubdiv','I','Monitoring kecukupan SDM per shift','Analisis rasio pasien-perawat dan gap SDM sub divisi','daily',1,'analisis',5,'mutu',1],
        ['kasubdiv','G','Supervisi lapangan ke unit','Supervisi pelayanan, dokumentasi, dan kepatuhan SOP','weekly',3,'kunjungan',5,'mutu',1],
        ['kasubdiv','G','Review indikator mutu unit','Review indikator mutu, insiden, dan trend capaian','weekly',1,'review',4,'mutu',1],
        ['kasubdiv','D','Review insiden keselamatan pasien','Telaah IKP/near miss dan tindak lanjut awal','event',1,'kasus',5,'patient_safety',1],
        ['kasubdiv','E','Menindaklanjuti keluhan pasien/keluarga','Follow up keluhan pasien/keluarga lintas unit sub divisi','event',1,'kasus',4,'kolaborasi',1],
        ['kasubdiv','B','Monitoring kepatuhan dokumentasi askep','Audit dokumentasi askep/CPPT pada unit binaan','weekly',5,'dokumen',5,'dokumentasi',1],
        ['kasubdiv','G','Monitoring pelaksanaan program PPI','Monitoring PPI, hand hygiene, APD, dan kepatuhan isolasi','weekly',1,'audit',4,'mutu',1],
        ['kasubdiv','H','Melakukan pembinaan Katim/Karu','Coaching leadership dan manajemen unit','weekly',2,'sesi',4,'kompetensi',1],
        ['kasubdiv','I','Menyusun laporan bulanan sub divisi','Konsolidasi capaian, masalah, SDM, dan rencana perbaikan','monthly',1,'laporan',5,'dokumentasi',1],
        ['kasubdiv','I','Monitoring absensi, keterlambatan, cuti, sakit','Rekap disiplin dan kehadiran staf sub divisi','daily',1,'rekap',4,'disiplin',1],
        ['kasubdiv','H','Mengusulkan kebutuhan pelatihan staf','TNA/unit need dan rencana pengembangan kompetensi','monthly',1,'usulan',4,'kompetensi',1],
        ['kasubdiv','G','Mengevaluasi logbook unit','Analisis real vs ideal aktivitas unit','monthly',1,'rekap',5,'produktivitas',1],
        ['kasubdiv','E','Melakukan koordinasi lintas unit','Koordinasi masalah pelayanan lintas unit/divisi','event',1,'koordinasi',4,'kolaborasi',1],
        ['kasubdiv','I','Monitoring BOR/kunjungan/tindakan unit','Review beban kerja unit berdasarkan BOR/kunjungan/tindakan','daily',1,'data',4,'mutu',1],
        ['kasubdiv','J','Mengawal program peningkatan mutu','PDSA/project improvement dan tindak lanjut temuan','monthly',1,'project',5,'mutu',1],
        ['kasubdiv','I','Verifikasi KPI Katim/Karu/unit','Review dan approval KPI unit/sub divisi','monthly',1,'approval',5,'leadership',1],
        ['kadiv','I','Monitoring dashboard seluruh sub divisi keperawatan','Pemantauan capaian seluruh sub divisi keperawatan','daily',1,'dashboard',5,'leadership',0],
        ['kadiv','F','Review masalah prioritas keperawatan','Penetapan isu strategis harian/mingguan','weekly',2,'review',5,'leadership',1],
        ['kadiv','G','Menetapkan prioritas perbaikan mutu','Menentukan fokus mutu dan program PDSA','monthly',1,'program',5,'mutu',1],
        ['kadiv','G','Monitoring indikator mutu keperawatan','Review grafik indikator mutu keperawatan dan trend capaian','monthly',1,'review',5,'mutu',1],
        ['kadiv','I','Evaluasi kecukupan SDM dan beban kerja','Analisis workload, kebutuhan SDM, dan distribusi tenaga','monthly',1,'analisis',5,'mutu',1],
        ['kadiv','G','Evaluasi produktivitas logbook seluruh unit','Komparasi skor real, ideal, overload, dan kinerja unit','monthly',1,'rekap',5,'produktivitas',1],
        ['kadiv','E','Koordinasi dengan direksi/manajemen','Koordinasi strategis dengan direksi/manajemen rumah sakit','event',1,'notulen',4,'kolaborasi',1],
        ['kadiv','H','Monitoring pelaksanaan jenjang karir perawat','Evaluasi PK, kredensial, dan rencana jenjang karir','monthly',1,'review',5,'kompetensi',1],
        ['kadiv','H','Evaluasi pelatihan dan kompetensi staf','Evaluasi diklat, kompetensi, kredensial, dan kebutuhan pelatihan','monthly',1,'review',5,'kompetensi',1],
        ['kadiv','I','Menyetujui KPI final keperawatan','Approval KPI bulanan berbasis data','monthly',1,'approval',5,'leadership',1],
        ['kadiv','D','Telaah insiden mayor/risiko tinggi','RCA dan tindak lanjut insiden signifikan','event',1,'kasus',5,'patient_safety',1],
        ['kadiv','I','Menyusun kebijakan/SPO keperawatan','Penyusunan/review kebijakan dan SPO keperawatan','event',1,'dokumen',4,'dokumentasi',1],
        ['kadiv','G','Monitoring kepuasan pasien terkait keperawatan','Review survei kepuasan pasien dan tindak lanjut','monthly',1,'data',4,'mutu',1],
        ['kadiv','H','Monitoring kepuasan/retensi staf','Review retensi, kepuasan, dan kebutuhan pembinaan staf','monthly',1,'data',4,'kompetensi',1],
        ['kadiv','I','Evaluasi remunerasi berbasis kinerja','Analisis kewajaran beban kerja, KPI, dan remunerasi','monthly',1,'rekap',5,'produktivitas',1],
        ['kadiv','I','Membuat laporan divisi keperawatan','Laporan resmi untuk direksi/manajemen','monthly',1,'laporan',5,'dokumentasi',1],
        ['kadiv','J','Mengawal inovasi keperawatan digital','Pengembangan sistem, SOP digital, dan dashboard kinerja','monthly',1,'project',4,'kompetensi',1],
        ['kadiv','I','Evaluasi capaian seluruh sub divisi','Executive scorecard dan evaluasi capaian organisasi keperawatan','monthly',1,'scorecard',5,'leadership',1],
    ];
}
function lbk_seed_unit_items(): array {
    $commonPelaksana = [
        ['D','Identifikasi pasien sesuai unit','Validasi minimal 2 identitas sebelum tindakan/unit pelayanan','per_shift',10,'tindakan',5,'patient_safety',0],
        ['B','Dokumentasi pelayanan sesuai unit','Pendokumentasian CPPT/form layanan sesuai area kerja','per_shift',5,'dokumen',5,'dokumentasi',1],
        ['C','Edukasi pasien/keluarga sesuai kebutuhan unit','Edukasi singkat sesuai risiko dan kebutuhan pasien di unit','per_shift',2,'edukasi',3,'kompetensi',1],
    ];
    $unitSpecific = [
        'IGD' => [
            ['A','Triase pasien masuk IGD','Melakukan triase, identifikasi kegawatan, dan prioritas pelayanan','per_shift',5,'pasien',5,'produktivitas',1],
            ['A','Monitoring pasien observasi IGD','Monitoring TTV, nyeri, respons terapi, dan perubahan kondisi','per_shift',8,'observasi',5,'patient_safety',1],
            ['E','Koordinasi admisi/rujuk/pulang IGD','Koordinasi DPJP, ranap, penunjang, rujukan, atau pemulangan','per_shift',3,'koordinasi',4,'kolaborasi',1],
        ],
        'KAMAR_BERSALIN' => [
            ['A','Monitoring kala persalinan','Pemantauan his, DJJ, kemajuan persalinan, dan kondisi ibu','per_shift',4,'observasi',5,'patient_safety',1],
            ['A','Asuhan ibu nifas awal','Monitoring perdarahan, kontraksi uterus, nyeri, dan edukasi awal','per_shift',3,'pasien',4,'produktivitas',1],
            ['D','Persiapan emergensi maternal/neonatal','Kesiapan alat emergensi, obat, dan eskalasi risiko','per_shift',1,'checklist',5,'patient_safety',1],
        ],
        'HD' => [
            ['A','Persiapan pasien hemodialisis','Assessment pra HD, akses vaskular, BB, TTV, dan edukasi','per_shift',4,'pasien',5,'produktivitas',1],
            ['A','Monitoring intradialisis','Monitoring TTV, keluhan, UF, komplikasi, dan respons pasien','per_shift',8,'observasi',5,'patient_safety',1],
            ['B','Dokumentasi tindakan HD','Pencatatan parameter HD, cairan, komplikasi, dan evaluasi akhir','per_shift',4,'dokumen',5,'dokumentasi',1],
        ],
        'OK' => [
            ['D','Checklist keselamatan operasi','Sign in, time out, sign out, dan validasi identitas/prosedur/lokasi','per_shift',3,'checklist',5,'patient_safety',1],
            ['A','Persiapan pasien pre operasi','Validasi instruksi, informed consent, area operasi, dan kesiapan pasien','per_shift',3,'pasien',5,'produktivitas',1],
            ['A','Monitoring pasien intra/pasca operasi awal','Pemantauan kondisi, alat, specimen, dan transfer pasien aman','per_shift',3,'pasien',5,'patient_safety',1],
        ],
        'POLIKLINIK' => [
            ['A','Asesmen awal pasien poliklinik','Skrining keluhan, TTV, riwayat singkat, dan kebutuhan layanan','per_shift',20,'pasien',4,'produktivitas',0],
            ['E','Pendampingan layanan dokter poliklinik','Koordinasi pasien, dokter, tindakan, resep, dan penunjang','per_shift',20,'pasien',4,'kolaborasi',0],
            ['C','Edukasi jadwal kontrol dan terapi','Edukasi kontrol, obat, pemeriksaan lanjutan, dan tanda bahaya','per_shift',10,'edukasi',3,'kompetensi',1],
        ],
        'RAWAT_INAP' => [
            ['A','Asuhan keperawatan pasien rawat inap','Pengkajian, implementasi, evaluasi, dan monitoring pasien kelolaan','per_shift',6,'pasien',5,'produktivitas',1],
            ['B','CPPT dan evaluasi SOAP rawat inap','Dokumentasi perkembangan pasien dan respons intervensi','per_shift',6,'dokumen',5,'dokumentasi',1],
            ['I','Discharge planning pasien rawat inap','Persiapan pulang, edukasi, obat, kontrol, dan kebutuhan rumah','event',1,'pasien',4,'mutu',1],
        ],
        'RUANG_BAYI' => [
            ['A','Monitoring bayi rawat gabung/perinatologi','Monitoring suhu, minum, eliminasi, ikterik, dan tanda bahaya','per_shift',6,'bayi',5,'patient_safety',1],
            ['C','Edukasi perawatan bayi kepada keluarga','Edukasi ASI, kebersihan tali pusat, tanda bahaya, dan kontrol','per_shift',3,'edukasi',4,'kompetensi',1],
            ['D','Pencegahan hipotermi dan infeksi bayi','Pengawasan suhu, kebersihan tangan, dan lingkungan bayi','per_shift',6,'observasi',5,'patient_safety',1],
        ],
        'NICU' => [
            ['A','Monitoring bayi risiko tinggi/NICU','Monitoring respirasi, suhu, saturasi, cairan, nutrisi, dan alat bantu','per_shift',8,'observasi',5,'patient_safety',1],
            ['D','Perawatan inkubator dan alat bantu NICU','Cek keamanan inkubator, CPAP/O2, infus, dan alarm alat','per_shift',4,'checklist',5,'patient_safety',1],
            ['B','Dokumentasi intensif neonatal','Catatan intake-output, grafik, CPPT, dan evaluasi terapi','per_shift',6,'dokumen',5,'dokumentasi',1],
        ],
        'ICU' => [
            ['A','Monitoring pasien kritis ICU','Monitoring hemodinamik, respirasi, neurologis, cairan, dan respons terapi','per_shift',8,'observasi',5,'patient_safety',1],
            ['D','Bundle keselamatan pasien ICU','VAP bundle, CLABSI/CAUTI prevention, pressure injury, dan delirium care','per_shift',4,'bundle',5,'patient_safety',1],
            ['B','Dokumentasi flow sheet ICU','Dokumentasi intensif TTV, balance cairan, alat, obat, dan CPPT','per_shift',6,'dokumen',5,'dokumentasi',1],
        ],
    ];
    $rows = [];
    foreach ($unitSpecific as $unitCode => $activities) {
        foreach ($commonPelaksana as $a) { $rows[] = array_merge(['pelaksana',$unitCode], $a); }
        foreach ($activities as $a)       { $rows[] = array_merge(['pelaksana',$unitCode], $a); }
        $rows[] = ['kaunit',$unitCode,'F','Monitoring operasional unit '.lbk_unit_label($unitCode),'Review beban kerja, risiko, kendala, dan kebutuhan SDM unit','daily',1,'monitoring',5,'leadership',1];
        $rows[] = ['kaunit',$unitCode,'G','Supervisi mutu dan dokumentasi unit '.lbk_unit_label($unitCode),'Supervisi lapangan, audit ringkas, tindak lanjut temuan, dan coaching staf','weekly',3,'supervisi',5,'mutu',1];
        $rows[] = ['kaunit',$unitCode,'I','Laporan kinerja unit '.lbk_unit_label($unitCode),'Rekap kegiatan, masalah, indikator, dan rencana perbaikan unit','monthly',1,'laporan',5,'dokumentasi',1];
    }
    return $rows;
}

// ── Bootstrap schema & session ──────────────────────────────
lbk_ensure_schema($conn);
$user       = lbk_current_user();
$isAdmin    = in_array($user['role'], ['admin','superadmin'], true);
$currentLevel = lbk_level_from_text($user['jabatan'], $user['role']);

$emp = null;
if ($user['nik'] !== '') {
    $emp = lbk_one($conn, "SELECT e.*, u.name unit_name FROM employees e LEFT JOIN units u ON u.id=e.unit_id WHERE e.nik=? LIMIT 1", [$user['nik']], 's');
}
if (!$emp && $user['id'] > 0) {
    $emp = lbk_one($conn, "SELECT e.*, u.name unit_name FROM users us LEFT JOIN employees e ON e.id=us.employee_id LEFT JOIN units u ON u.id=e.unit_id WHERE us.id=? LIMIT 1", [$user['id']], 'i');
}
$employeeId   = (int)($emp['id'] ?? 0);
$employeeName = (string)($emp['full_name'] ?? $user['name']);
$unitId       = (int)($emp['unit_id'] ?? 0);
$unitName     = (string)($emp['unit_name'] ?? $user['unit']);
if (($emp['position_name'] ?? '') !== '') $currentLevel = lbk_level_from_text((string)$emp['position_name'], $user['role']);

// ── POST handlers ────────────────────────────────────────────
$notice = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = (string)($_POST['action'] ?? '');


    if ($action === 'upload_staff_schedule') {
        $scheduleUnit=(int)($_POST['schedule_unit_id']??0); $scheduleMonth=max(1,min(12,(int)($_POST['schedule_month']??date('n')))); $scheduleYear=max(2020,min(2100,(int)($_POST['schedule_year']??date('Y'))));
        $canSchedule = lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,$scheduleUnit);
        $validUnit=lbk_one($conn,"SELECT unit_id,display_name FROM logbook_kpi_nursing_units WHERE unit_id=? AND is_active=1",[$scheduleUnit],'i');
        if(!$canSchedule || !$validUnit){ $notice='Anda tidak memiliki akses mengunggah jadwal unit tersebut.'; }
        elseif(empty($_FILES['schedule_file']['tmp_name']) || !is_uploaded_file($_FILES['schedule_file']['tmp_name'])){ $notice='File jadwal Excel wajib dipilih.'; }
        else {
            try {
                $rows=lbk_read_simple_xlsx($_FILES['schedule_file']['tmp_name']);
                $dayCols=[]; foreach(($rows[2]??[]) as $ci=>$v){$d=(int)$v;if($d>=1&&$d<=31)$dayCols[$ci]=$d;}
                if(!$dayCols) throw new RuntimeException('Baris tanggal tidak ditemukan. Format harus seperti contoh: nama di kolom A dan tanggal di baris 2.');
                $staffDb=lbk_all($conn,"SELECT e.id,e.full_name,e.unit_id FROM employees e LEFT JOIN logbook_kpi_unit_mapping mp ON mp.source_unit_id=e.unit_id AND mp.is_active=1 WHERE e.is_active=1 AND COALESCE(mp.canonical_unit_id,e.unit_id)=?",[$scheduleUnit],'i');
                $nameMap=[]; foreach($staffDb as $ed){$nameMap[lbk_schedule_normalize_name((string)$ed['full_name'])][]=$ed;}
                $shiftMap=[]; foreach(lbk_all($conn,"SELECT code,requires_logbook FROM logbook_kpi_shift_codes WHERE is_active=1") as $sh)$shiftMap[strtoupper((string)$sh['code'])]=(int)$sh['requires_logbook'];
                $conn->begin_transaction();
                $stmt=$conn->prepare("INSERT INTO logbook_kpi_schedule_uploads(unit_id,month,year,original_filename,uploaded_by,uploaded_by_name) VALUES(?,?,?,?,?,?)");
                $fn=(string)($_FILES['schedule_file']['name']??'jadwal.xlsx'); $stmt->bind_param('iiisis',$scheduleUnit,$scheduleMonth,$scheduleYear,$fn,$user['id'],$user['name']);$stmt->execute();$uploadId=(int)$stmt->insert_id;$stmt->close();
                $total=0;$matched=0;$unmatched=0;$unknownCodes=[];
                $ins=$conn->prepare("INSERT INTO logbook_kpi_staff_schedules(upload_id,unit_id,employee_id,employee_name_excel,normalized_name,schedule_date,shift_code,requires_logbook,match_status) VALUES(?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE upload_id=VALUES(upload_id),employee_id=VALUES(employee_id),normalized_name=VALUES(normalized_name),shift_code=VALUES(shift_code),requires_logbook=VALUES(requires_logbook),match_status=VALUES(match_status)");
                foreach($rows as $ri=>$rv){ if($ri<3)continue; $excelName=trim((string)($rv[1]??'')); if($excelName==='')continue; $norm=lbk_schedule_normalize_name($excelName); $empId=null;$status='unmatched';
                    if(isset($nameMap[$norm])&&count($nameMap[$norm])===1){$empId=(int)$nameMap[$norm][0]['id'];$status='matched';$matched++;}else{$unmatched++;}
                    $total++;
                    foreach($dayCols as $ci=>$day){ if(!checkdate($scheduleMonth,$day,$scheduleYear))continue; $code=strtoupper(trim((string)($rv[$ci]??''))); if($code==='')continue; $req=$shiftMap[$code]??1; if(!array_key_exists($code,$shiftMap))$unknownCodes[$code]=true; $date=sprintf('%04d-%02d-%02d',$scheduleYear,$scheduleMonth,$day); $empBind=$empId; $ins->bind_param('iiissssis',$uploadId,$scheduleUnit,$empBind,$excelName,$norm,$date,$code,$req,$status);$ins->execute(); }
                }
                $ins->close(); $up=$conn->prepare("UPDATE logbook_kpi_schedule_uploads SET total_rows=?,matched_rows=?,unmatched_rows=? WHERE id=?");$up->bind_param('iiii',$total,$matched,$unmatched,$uploadId);$up->execute();$up->close(); $conn->commit();
                $notice="Jadwal berhasil diimpor: $total staf, $matched cocok, $unmatched belum cocok.".($unknownCodes?' Kode baru: '.implode(', ',array_keys($unknownCodes)).' (sementara dianggap wajib logbook).':'');
            } catch(Throwable $ex){ try{$conn->rollback();}catch(Throwable $x){} $notice='Gagal impor jadwal: '.$ex->getMessage(); }
        }
        $_GET['tab']='schedule';
    }
    if ($action === 'map_schedule_employee') {
        $scheduleName=trim((string)($_POST['schedule_name']??''));$mapEmployee=(int)($_POST['map_employee_id']??0);$mapUnit=(int)($_POST['map_unit_id']??0);
        if(lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,$mapUnit) && $scheduleName!=='' && $mapEmployee>0){
            $st=$conn->prepare("UPDATE logbook_kpi_staff_schedules SET employee_id=?,match_status='manual' WHERE unit_id=? AND employee_name_excel=?");$st->bind_param('iis',$mapEmployee,$mapUnit,$scheduleName);$st->execute();$st->close();$notice='Nama jadwal berhasil dipetakan ke staf database.';
        }
        $_GET['tab']='schedule';
    }
    if ($action === 'save_shift_code') {
        $code=strtoupper(trim((string)($_POST['shift_code']??'')));$shiftName=trim((string)($_POST['shift_name']??''));$req=isset($_POST['requires_logbook'])?1:0;$cross=isset($_POST['crosses_midnight'])?1:0;$start=$_POST['start_time']?:null;$end=$_POST['end_time']?:null;
        if(($isAdmin||in_array($currentLevel,['kadiv','kasubdiv','kasubdiv_rajal','kasubdiv_ranap'],true))&&$code!==''&&$shiftName!==''){$st=$conn->prepare("INSERT INTO logbook_kpi_shift_codes(code,shift_name,start_time,end_time,requires_logbook,crosses_midnight,is_active) VALUES(?,?,?,?,?,?,1) ON DUPLICATE KEY UPDATE shift_name=VALUES(shift_name),start_time=VALUES(start_time),end_time=VALUES(end_time),requires_logbook=VALUES(requires_logbook),crosses_midnight=VALUES(crosses_midnight),is_active=1");$st->bind_param('ssssii',$code,$shiftName,$start,$end,$req,$cross);$st->execute();$st->close();$notice='Master kode jadwal disimpan.';}
        $_GET['tab']='schedule';
    }

    // ── save_patient_assignment ──
    if ($action === 'save_patient_assignment') {
        $assignDate   = $_POST['assign_date'] ?: date('Y-m-d');
        $assignShift  = in_array($_POST['assign_shift'] ?? '', ['Pagi','Sore','Malam','Non Shift','Libur'], true) ? $_POST['assign_shift'] : 'Pagi';
        $patientCount = max(0, (int)($_POST['assign_patient_count'] ?? 0));
        $roomRaw      = trim((string)($_POST['assign_room_list'] ?? ''));
        $assignNote   = trim((string)($_POST['assign_note'] ?? ''));
        $rooms        = array_values(array_unique(array_filter(array_map('trim', preg_split('/[\r\n,;]+/', $roomRaw) ?: []), static fn($v) => $v !== '')));
        if ($patientCount <= 0 && count($rooms) > 0) { $patientCount = count($rooms); }
        if ($patientCount <= 0) {
            $notice = 'Jumlah pasien yang dirawat wajib diisi minimal 1.';
        } elseif (count($rooms) === 0) {
            $notice = 'Daftar kamar/bed pasien wajib diisi agar saat input kegiatan bisa dipilih.';
        } else {
            $roomList = implode("\n", $rooms);
            $stmt = $conn->prepare("INSERT INTO logbook_kpi_patient_assignments(user_id,employee_id,employee_name,unit_id,unit_name,assign_date,shift,patient_count,room_list,note,created_by,created_by_name) VALUES(?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE employee_id=VALUES(employee_id), employee_name=VALUES(employee_name), unit_id=VALUES(unit_id), unit_name=VALUES(unit_name), patient_count=VALUES(patient_count), room_list=VALUES(room_list), note=VALUES(note), updated_at=NOW()");
            if ($stmt) {
                $stmt->bind_param('iisisssissis', $user['id'],$employeeId,$employeeName,$unitId,$unitName,$assignDate,$assignShift,$patientCount,$roomList,$assignNote,$user['id'],$user['name']);
                $stmt->execute(); $stmt->close();
                $notice = 'Daftar pasien/kamar berhasil disimpan.';
                $_GET['log_date'] = $assignDate;
                $_GET['shift']    = $assignShift;
                $_GET['tab']      = 'input';
            }
        }
    }

    // ── save_log ──
    if ($action === 'save_log') {
        $logDate    = $_POST['log_date'] ?: date('Y-m-d');
        $shift      = in_array($_POST['shift'] ?? '', ['Pagi','Sore','Malam','Non Shift','Libur'], true) ? $_POST['shift'] : 'Pagi';
        $activityId = (int)($_POST['activity_id'] ?? 0);
        $real       = max(0, (float)($_POST['real_count'] ?? 0));
        $duration   = max(0, (int)($_POST['duration_minutes'] ?? 0));
        $patients   = max(0, (int)($_POST['patients_count'] ?? 0));
        $quality    = ($_POST['quality_score'] ?? '') === '' ? null : min(100, max(0, (float)$_POST['quality_score']));
        $notes      = trim((string)($_POST['notes'] ?? ''));
        $evidence   = trim((string)($_POST['evidence_note'] ?? ''));
        $actTime    = trim((string)($_POST['activity_time'] ?? ''));
        $postedRooms = $_POST['patient_rooms'] ?? [];
        if (!is_array($postedRooms)) { $postedRooms = []; }
        $postedRooms = array_values(array_unique(array_filter(array_map(
            static fn($v) => trim((string)$v),
            $postedRooms
        ), static fn($v) => $v !== '')));
        $patRoom = $postedRooms
            ? implode(', ', $postedRooms)
            : trim((string)($_POST['patient_room'] ?? ''));
        $selectedRoomCount = count($postedRooms);
        if ($selectedRoomCount > 0) {
            // Satu kegiatan pada beberapa kamar dihitung sesuai jumlah kamar yang dipilih.
            $patients = max($patients, $selectedRoomCount);
            $real     = max($real, (float)$selectedRoomCount);
        }
        if ($actTime === '') { $actTime = date('H:i'); }
        if (preg_match('/^\d{2}:\d{2}$/', $actTime)) { $actTime .= ':00'; }
        if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $actTime)) { $actTime = date('H:i:s'); }
        $formRole         = (string)($_POST['input_role'] ?? '');
        $validRolesForLog = ['pelaksana','katim','kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'];

        $shiftPolicy = lbk_shift_duration_policy($shift);
        $usedMinutes = lbk_shift_used_minutes($conn,$user['id'],$employeeId,$logDate,$shift);
        $remainingMinutes = $shiftPolicy['max_minutes'] > 0 ? max(0,(int)$shiftPolicy['max_minutes']-$usedMinutes) : PHP_INT_MAX;

        if ($shiftPolicy['max_minutes'] > 0 && ($usedMinutes + $duration) > (int)$shiftPolicy['max_minutes']) {
            $notice = 'Durasi tidak dapat disimpan. Shift '.$shift.' maksimal '.
                lbk_format_minutes((int)$shiftPolicy['max_minutes']).'. Sudah tercatat '.
                lbk_format_minutes($usedMinutes).', sisa '.lbk_format_minutes($remainingMinutes).'.';
            $act = null;
        } else {
            $act = lbk_one($conn, "SELECT * FROM logbook_kpi_activity_master WHERE id=? AND is_active=1", [$activityId], 'i');
        }
        if ($act) {
            $roleLevel    = in_array($formRole, $validRolesForLog, true) ? $formRole : (string)$act['role_level'];
            $activityName = (string)$act['activity_name'];
            $cat          = (string)$act['category_code'];
            $domain       = (string)$act['kpi_domain'];
            $ideal        = (float)$act['ideal_frequency_value'];
            $weight       = (float)$act['weight'];
            $entryUnitId   = $unitId;
            $entryUnitName = $unitName !== '' ? $unitName : (string)($user['unit'] ?? '');
            if ($roleLevel === 'pelaksana' && $patRoom === '') {
                $notice = 'Nomor kamar/bed/pasien wajib diisi untuk aktivitas perawat pelaksana.';
            } else {
                $stmt = $conn->prepare("INSERT INTO logbook_kpi_entries(user_id,employee_id,employee_name,role_level,unit_id,unit_name,log_date,shift,activity_time,patient_room,activity_id,activity_name,category_code,kpi_domain,ideal_count,real_count,weight,duration_minutes,patients_count,quality_score,notes,evidence_note,status) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'submitted')");
                if ($stmt) {
                    $stmt->bind_param('iississsssisssdddiidss', $user['id'],$employeeId,$employeeName,$roleLevel,$entryUnitId,$entryUnitName,$logDate,$shift,$actTime,$patRoom,$activityId,$activityName,$cat,$domain,$ideal,$real,$weight,$duration,$patients,$quality,$notes,$evidence);
                    $stmt->execute(); $stmt->close();
                    $notice = 'Logbook berhasil disimpan.';
                }
            }
        } elseif ($notice === '') { $notice = 'Aktivitas tidak ditemukan.'; }
    }

    // ── edit_log (BARU) ──
    if ($action === 'edit_log') {
        $editId     = (int)($_POST['edit_entry_id'] ?? 0);
        $logDate    = $_POST['log_date'] ?: date('Y-m-d');
        $shift      = in_array($_POST['shift'] ?? '', ['Pagi','Sore','Malam','Non Shift','Libur'], true) ? $_POST['shift'] : 'Pagi';
        $activityId = (int)($_POST['activity_id'] ?? 0);
        $real       = max(0, (float)($_POST['real_count'] ?? 0));
        $duration   = max(0, (int)($_POST['duration_minutes'] ?? 0));
        $patients   = max(0, (int)($_POST['patients_count'] ?? 0));
        $quality    = ($_POST['quality_score'] ?? '') === '' ? null : min(100, max(0, (float)$_POST['quality_score']));
        $notes      = trim((string)($_POST['notes'] ?? ''));
        $evidence   = trim((string)($_POST['evidence_note'] ?? ''));
        $actTime    = trim((string)($_POST['activity_time'] ?? ''));
        $postedRooms = $_POST['patient_rooms'] ?? [];
        if (!is_array($postedRooms)) { $postedRooms = []; }
        $postedRooms = array_values(array_unique(array_filter(array_map(
            static fn($v) => trim((string)$v),
            $postedRooms
        ), static fn($v) => $v !== '')));
        $patRoom = $postedRooms
            ? implode(', ', $postedRooms)
            : trim((string)($_POST['patient_room'] ?? ''));
        $selectedRoomCount = count($postedRooms);
        if ($selectedRoomCount > 0) {
            // Satu kegiatan pada beberapa kamar dihitung sesuai jumlah kamar yang dipilih.
            $patients = max($patients, $selectedRoomCount);
            $real     = max($real, (float)$selectedRoomCount);
        }
        if ($actTime === '') { $actTime = date('H:i'); }
        if (preg_match('/^\d{2}:\d{2}$/', $actTime)) { $actTime .= ':00'; }
        if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $actTime)) { $actTime = date('H:i:s'); }
        $formRole         = (string)($_POST['input_role'] ?? '');
        $validRolesForLog = ['pelaksana','katim','kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'];
        if ($editId <= 0) {
            $notice = 'ID entri tidak valid.';
        } else {
            $existing = lbk_one($conn, "SELECT * FROM logbook_kpi_entries WHERE id=? LIMIT 1", [$editId], 'i');
            if (!$existing) {
                $notice = 'Entri logbook tidak ditemukan.';
            } elseif (!$isAdmin && (int)$existing['user_id'] !== $user['id']) {
                $notice = 'Anda tidak memiliki akses untuk mengedit entri ini.';
            } else {
                $shiftPolicy = lbk_shift_duration_policy($shift);
                $usedMinutes = lbk_shift_used_minutes($conn,$user['id'],$employeeId,$logDate,$shift,$editId);
                $remainingMinutes = $shiftPolicy['max_minutes'] > 0 ? max(0,(int)$shiftPolicy['max_minutes']-$usedMinutes) : PHP_INT_MAX;

                if ($shiftPolicy['max_minutes'] > 0 && ($usedMinutes + $duration) > (int)$shiftPolicy['max_minutes']) {
                    $notice = 'Perubahan tidak dapat disimpan. Shift '.$shift.' maksimal '.
                        lbk_format_minutes((int)$shiftPolicy['max_minutes']).'. Durasi entri lain '.
                        lbk_format_minutes($usedMinutes).', sisa '.lbk_format_minutes($remainingMinutes).'.';
                    $act = null;
                } else {
                    $act = lbk_one($conn, "SELECT * FROM logbook_kpi_activity_master WHERE id=? AND is_active=1", [$activityId], 'i');
                }
                if (!$act) {
                    if ($notice === '') $notice = 'Aktivitas tidak ditemukan.';
                } else {
                    $roleLevel    = in_array($formRole, $validRolesForLog, true) ? $formRole : (string)$act['role_level'];
                    $activityName = (string)$act['activity_name'];
                    $cat          = (string)$act['category_code'];
                    $domain       = (string)$act['kpi_domain'];
                    $ideal        = (float)$act['ideal_frequency_value'];
                    $weight       = (float)$act['weight'];
                    if ($roleLevel === 'pelaksana' && $patRoom === '') {
                        $notice = 'Nomor kamar/bed/pasien wajib diisi untuk aktivitas perawat pelaksana.';
                    } else {
                        $stmt = $conn->prepare("UPDATE logbook_kpi_entries SET
                            log_date=?, shift=?, activity_time=?, patient_room=?,
                            activity_id=?, activity_name=?, category_code=?, kpi_domain=?,
                            ideal_count=?, real_count=?, weight=?,
                            duration_minutes=?, patients_count=?, quality_score=?,
                            notes=?, evidence_note=?,
                            role_level=?,
                            status='submitted',
                            verified_by=NULL, verified_by_name=NULL, verified_at=NULL, verifier_note=NULL,
                            updated_at=NOW()
                        WHERE id=?");
                        if ($stmt) {
                            $stmt->bind_param('ssssisssdddiidsssi',
                                $logDate, $shift, $actTime, $patRoom,
                                $activityId, $activityName, $cat, $domain,
                                $ideal, $real, $weight,
                                $duration, $patients, $quality,
                                $notes, $evidence,
                                $roleLevel,
                                $editId
                            );
                            $stmt->execute(); $stmt->close();
                            $notice = 'Logbook #'.$editId.' berhasil diperbarui. Status dikembalikan ke submitted untuk verifikasi ulang.';
                        }
                    }
                }
            }
        }
        $tab = 'detail';
        $_GET['tab'] = 'detail';
    }

    // ── verify ──
    if ($action === 'verify' && lbk_can_verify($currentLevel, $isAdmin)) {
        $id     = (int)($_POST['entry_id'] ?? 0);
        $status = ($_POST['status'] ?? '') === 'rejected' ? 'rejected' : 'verified';
        $note   = trim((string)($_POST['verifier_note'] ?? ''));
        $stmt   = $conn->prepare("UPDATE logbook_kpi_entries SET status=?, verified_by=?, verified_by_name=?, verified_at=NOW(), verifier_note=? WHERE id=?");
        if ($stmt) { $stmt->bind_param('sissi', $status, $user['id'], $user['name'], $note, $id); $stmt->execute(); $stmt->close(); $notice = 'Status logbook berhasil diperbarui.'; }
    }

    // ── bulk_verify ──
    if ($action === 'bulk_verify' && lbk_can_verify($currentLevel, $isAdmin)) {
        $entryIds = $_POST['entry_ids'] ?? [];
        if (!is_array($entryIds)) { $entryIds = []; }
        $entryIds = array_values(array_unique(array_filter(array_map('intval', $entryIds), static fn($v) => $v > 0)));
        $status   = ($_POST['status'] ?? '') === 'rejected' ? 'rejected' : 'verified';
        $note     = trim((string)($_POST['verifier_note'] ?? ''));
        if ($entryIds) {
            $placeholders = implode(',', array_fill(0, count($entryIds), '?'));
            $sqlBulk = "UPDATE logbook_kpi_entries SET status=?, verified_by=?, verified_by_name=?, verified_at=NOW(), verifier_note=? WHERE id IN ($placeholders)";
            $stmt    = $conn->prepare($sqlBulk);
            if ($stmt) {
                $typesBulk  = 'siss' . str_repeat('i', count($entryIds));
                $paramsBulk = array_merge([$status, $user['id'], $user['name'], $note], $entryIds);
                $stmt->bind_param($typesBulk, ...$paramsBulk);
                $stmt->execute(); $stmt->close();
                $notice = 'Verifikasi kolektif berhasil untuk ' . count($entryIds) . ' aktivitas.';
            }
        } else { $notice = 'Tidak ada aktivitas yang dipilih.'; }
    }

    // ── verify_all_filtered: verifikasi semua entri pending sesuai filter aktif ──
    if ($action === 'verify_all_filtered' && lbk_can_verify($currentLevel, $isAdmin)) {
        $verifyMonth = max(1, min(12, (int)($_POST['verify_month'] ?? date('n'))));
        $verifyYear  = max(2024, min(2099, (int)($_POST['verify_year'] ?? date('Y'))));
        $verifyUnit  = max(0, (int)($_POST['verify_unit_id'] ?? 0));
        $verifyUser  = max(0, (int)($_POST['verify_user_id'] ?? 0));
        $verifyDate  = trim((string)($_POST['verify_date'] ?? ''));
        $verifyNote  = trim((string)($_POST['verifier_note'] ?? 'Verifikasi semua melalui tab Verifikasi'));

        if ($verifyDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $verifyDate)) {
            $verifyDate = '';
        }

        $verifyStart = sprintf('%04d-%02d-01', $verifyYear, $verifyMonth);
        $verifyEnd   = date('Y-m-t', strtotime($verifyStart));
        $verifyWhere = "log_date BETWEEN ? AND ? AND status <> 'verified'";
        $verifyParams = [$verifyStart, $verifyEnd];
        $verifyTypes  = 'ss';

        // Gunakan scope yang sama dengan tampilan tab Verifikasi.
        if (!$isAdmin && !in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true)) {
            $verifyWhere .= " AND user_id=?";
            $verifyParams[] = $user['id'];
            $verifyTypes .= 'i';
        }
        if ($verifyUnit > 0) {
            $verifyWhere .= " AND unit_id=?";
            $verifyParams[] = $verifyUnit;
            $verifyTypes .= 'i';
        }
        if ($verifyUser > 0) {
            $verifyWhere .= " AND user_id=?";
            $verifyParams[] = $verifyUser;
            $verifyTypes .= 'i';
        }
        if ($verifyDate !== '') {
            $verifyWhere .= " AND log_date=?";
            $verifyParams[] = $verifyDate;
            $verifyTypes .= 's';
        }

        $sqlVerifyAll = "UPDATE logbook_kpi_entries
                         SET status='verified', verified_by=?, verified_by_name=?, verified_at=NOW(), verifier_note=?
                         WHERE $verifyWhere";
        $stmt = $conn->prepare($sqlVerifyAll);
        if ($stmt) {
            $allParams = array_merge([$user['id'], $user['name'], $verifyNote], $verifyParams);
            $allTypes  = 'iss' . $verifyTypes;
            $stmt->bind_param($allTypes, ...$allParams);
            $stmt->execute();
            $affected = $stmt->affected_rows;
            $stmt->close();
            $notice = $affected > 0
                ? 'Verifikasi semua berhasil untuk ' . $affected . ' aktivitas sesuai filter aktif.'
                : 'Tidak ada aktivitas pending yang sesuai dengan filter aktif.';
        } else {
            $notice = 'Gagal menyiapkan proses verifikasi semua.';
        }
    }

    // ── save_master ──
    if ($action === 'save_master' && $isAdmin) {
        $id        = (int)($_POST['master_id'] ?? 0);
        $role      = lbk_master_role_level((string)($_POST['role_level'] ?? 'pelaksana'));
        $cat       = (string)($_POST['category_code'] ?? 'A');
        $unitGroup = strtoupper(trim((string)($_POST['unit_group'] ?? 'UMUM')));
        if (!array_key_exists($unitGroup, lbk_unit_options())) { $unitGroup = 'UMUM'; }
        if (!lbk_role_uses_unit_activity($role)) { $unitGroup = 'UMUM'; }
        $name      = trim((string)($_POST['activity_name'] ?? ''));
        $desc      = trim((string)($_POST['description'] ?? ''));
        $freq      = (string)($_POST['ideal_frequency_type'] ?? 'daily');
        if (!in_array($freq, ['per_shift','daily','weekly','monthly','event'], true)) { $freq = 'daily'; }
        $ideal    = max(0.01, (float)($_POST['ideal_frequency_value'] ?? 1));
        $unit     = trim((string)($_POST['unit_measure'] ?? 'kegiatan'));
        $weight   = max(1, min(5, (float)($_POST['weight'] ?? 1)));
        $domain   = (string)($_POST['kpi_domain'] ?? 'produktivitas');
        if (!in_array($domain, ['produktivitas','dokumentasi','patient_safety','disiplin','leadership','kompetensi','mutu','kolaborasi'], true)) { $domain = 'produktivitas'; }
        $evidence        = isset($_POST['evidence_required']) ? 1 : 0;
        $active          = isset($_POST['is_active']) ? 1 : 0;
        $duration_default = max(1,(int)($_POST['default_duration_minutes'] ?? 15));
        if ($name !== '') {
            if ($id > 0) {
                $stmt = $conn->prepare("UPDATE logbook_kpi_activity_master SET role_level=?,unit_group=?,category_code=?,activity_name=?,description=?,ideal_frequency_type=?,ideal_frequency_value=?,unit_measure=?,weight=?,kpi_domain=?,evidence_required=?,is_active=?,default_duration_minutes=? WHERE id=?");
                if ($stmt) { $stmt->bind_param('ssssssdsdsiiii',$role,$unitGroup,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence,$active,$duration_default,$id); $stmt->execute(); $stmt->close(); }
            } else {
                $stmt = $conn->prepare("INSERT INTO logbook_kpi_activity_master(role_level,unit_group,category_code,activity_name,description,ideal_frequency_type,ideal_frequency_value,unit_measure,weight,kpi_domain,evidence_required,is_active,default_duration_minutes) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)");
                if ($stmt) { $stmt->bind_param('ssssssdsdsiii',$role,$unitGroup,$cat,$name,$desc,$freq,$ideal,$unit,$weight,$domain,$evidence,$active,$duration_default); $stmt->execute(); $stmt->close(); }
            }
            $notice = $id > 0 ? 'Master aktivitas berhasil diperbarui.' : 'Master aktivitas berhasil disimpan.';
        } else { $notice = 'Nama aktivitas wajib diisi.'; }
    }

    // ── delete_master ──
    if ($action === 'delete_master' && $isAdmin) {
        $id = (int)($_POST['master_id'] ?? 0);
        if ($id > 0) {
            $used = lbk_one($conn, "SELECT COUNT(*) c FROM logbook_kpi_entries WHERE activity_id=? LIMIT 1", [$id], 'i');
            if ((int)($used['c'] ?? 0) > 0) {
                $stmt = $conn->prepare("UPDATE logbook_kpi_activity_master SET is_active=0 WHERE id=?");
                if ($stmt) { $stmt->bind_param('i', $id); $stmt->execute(); $stmt->close(); }
                $notice = 'Master aktivitas sudah pernah dipakai; statusnya dijadikan Nonaktif.';
            } else {
                $stmt = $conn->prepare("DELETE FROM logbook_kpi_activity_master WHERE id=?");
                if ($stmt) { $stmt->bind_param('i', $id); $stmt->execute(); $stmt->close(); }
                $notice = 'Master aktivitas berhasil dihapus.';
            }
        }
    }

    // ── save_workload ──
    if ($action === 'save_workload' && ($isAdmin || in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true))) {
        $workloadDate = $_POST['workload_date'] ?: date('Y-m-d');
        $unitKey      = strtoupper(trim((string)($_POST['workload_unit_key'] ?? '')));
        if ($unitKey === '') { $unitKey = 'UMUM'; }
        $unitLabel        = trim((string)($_POST['workload_unit_label'] ?? lbk_workload_unit_label($unitKey)));
        if ($unitLabel === '') { $unitLabel = lbk_workload_unit_label($unitKey); }
        $patientCount     = max(0, (float)($_POST['patient_count'] ?? 0));
        $losCount         = max(0, (float)($_POST['los_count'] ?? 0));
        $bedCapacity      = max(0, (int)($_POST['bed_capacity'] ?? 0));
        $nursesPerShift   = max(0, (int)($_POST['nurses_per_shift'] ?? 0));
        $nurseCount       = max(0, (int)($_POST['nurse_count'] ?? 0));
        $note             = trim((string)($_POST['workload_note'] ?? ''));
        $occupancy        = $bedCapacity > 0 ? min(200, ($patientCount / $bedCapacity) * 100) : 0;
        $patientPerNurse  = $nursesPerShift > 0 ? ($patientCount / $nursesPerShift) : 0;
        $losPerNurse      = $nurseCount > 0 ? ($losCount / $nurseCount) : 0;
        [$wlLevel, $multiplier] = lbk_workload_level_from_occupancy($occupancy);
        $stmt = $conn->prepare("INSERT INTO logbook_kpi_unit_workload_daily(workload_date,unit_key,unit_label,patient_count,los_count,bed_capacity,nurses_per_shift,nurse_count,occupancy_percent,patient_per_nurse_shift,los_per_nurse,workload_level,multiplier,note,created_by,created_by_name) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE unit_label=VALUES(unit_label),patient_count=VALUES(patient_count),los_count=VALUES(los_count),bed_capacity=VALUES(bed_capacity),nurses_per_shift=VALUES(nurses_per_shift),nurse_count=VALUES(nurse_count),occupancy_percent=VALUES(occupancy_percent),patient_per_nurse_shift=VALUES(patient_per_nurse_shift),los_per_nurse=VALUES(los_per_nurse),workload_level=VALUES(workload_level),multiplier=VALUES(multiplier),note=VALUES(note),updated_at=NOW()");
        if ($stmt) {
            $stmt->bind_param('sssddiiidddsdsis', $workloadDate,$unitKey,$unitLabel,$patientCount,$losCount,$bedCapacity,$nursesPerShift,$nurseCount,$occupancy,$patientPerNurse,$losPerNurse,$wlLevel,$multiplier,$note,$user['id'],$user['name']);
            $stmt->execute(); $stmt->close();
            $notice = 'Beban unit disimpan. Occupancy '.number_format($occupancy,1).'% – '.$wlLevel.' – x'.number_format($multiplier,2).'.';
        }
    }

    // ── save_monthly_workload ──
    if ($action === 'save_monthly_workload' && ($isAdmin || in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true))) {
        $mwMonth  = max(1, min(12, (int)($_POST['mw_month'] ?? date('n'))));
        $mwYear   = max(2024, min(2099, (int)($_POST['mw_year'] ?? date('Y'))));
        $unitKey  = strtoupper(trim((string)($_POST['mw_unit_key'] ?? '')));
        if ($unitKey === '') { $unitKey = 'UMUM'; }
        $unitLabel          = trim((string)($_POST['mw_unit_label'] ?? lbk_workload_unit_label($unitKey)));
        if ($unitLabel === '') { $unitLabel = lbk_workload_unit_label($unitKey); }
        $totalPatients      = max(0, (float)($_POST['mw_total_patients'] ?? 0));
        $totalStaff         = max(0, (int)($_POST['mw_total_staff'] ?? 0));
        $avgStaffPerShift   = max(0, (float)($_POST['mw_avg_staff_per_shift'] ?? 0));
        $bedCapacity        = max(0, (int)($_POST['mw_bed_capacity'] ?? 0));
        $independentPat     = max(0, (float)($_POST['mw_independent_patients'] ?? 0));
        $partialCarePat     = max(0, (float)($_POST['mw_partial_care_patients'] ?? 0));
        $totalCarePat       = max(0, (float)($_POST['mw_total_care_patients'] ?? 0));
        $stdIndependent     = max(0.01, (float)($_POST['mw_standard_independent'] ?? 5));
        $stdPartial         = max(0.01, (float)($_POST['mw_standard_partial'] ?? 10));
        $stdTotalCare       = max(0.01, (float)($_POST['mw_standard_total_care'] ?? 15));
        $note               = trim((string)($_POST['mw_note'] ?? ''));
        $classifiedTotal    = $independentPat + $partialCarePat + $totalCarePat;
        if ($classifiedTotal <= 0 && $totalPatients > 0) { $partialCarePat = $totalPatients; $classifiedTotal = $totalPatients; }
        if ($totalPatients <= 0 && $classifiedTotal > 0) { $totalPatients = $classifiedTotal; }
        $idealUnit  = ($independentPat * $stdIndependent) + ($partialCarePat * $stdPartial) + ($totalCarePat * $stdTotalCare);
        $idealStaff = $totalStaff > 0 ? ($idealUnit / $totalStaff) : 0;
        $stmt = $conn->prepare("INSERT INTO logbook_kpi_unit_workload_monthly(unit_key,unit_label,month,year,total_patients,total_staff,avg_staff_per_shift,bed_capacity,independent_patients,partial_care_patients,total_care_patients,standard_independent,standard_partial,standard_total_care,ideal_unit_activities,ideal_staff_activities,note,created_by,created_by_name) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE unit_label=VALUES(unit_label),total_patients=VALUES(total_patients),total_staff=VALUES(total_staff),avg_staff_per_shift=VALUES(avg_staff_per_shift),bed_capacity=VALUES(bed_capacity),independent_patients=VALUES(independent_patients),partial_care_patients=VALUES(partial_care_patients),total_care_patients=VALUES(total_care_patients),standard_independent=VALUES(standard_independent),standard_partial=VALUES(standard_partial),standard_total_care=VALUES(standard_total_care),ideal_unit_activities=VALUES(ideal_unit_activities),ideal_staff_activities=VALUES(ideal_staff_activities),note=VALUES(note),updated_at=NOW()");
        if ($stmt) {
            $stmt->bind_param('ssiidididdddddddsis', $unitKey,$unitLabel,$mwMonth,$mwYear,$totalPatients,$totalStaff,$avgStaffPerShift,$bedCapacity,$independentPat,$partialCarePat,$totalCarePat,$stdIndependent,$stdPartial,$stdTotalCare,$idealUnit,$idealStaff,$note,$user['id'],$user['name']);
            $stmt->execute(); $stmt->close();
            $notice = 'Standar beban bulanan disimpan. Ideal unit '.number_format($idealUnit,1).'; ideal staf '.number_format($idealStaff,1).'.';
        }
    }


    // ── Manajemen staf unit keperawatan ──
    if ($action === 'create_nursing_staff' && lbk_can_manage_nursing_staff($currentLevel, $isAdmin)) {
        $nikNew   = trim((string)($_POST['staff_nik'] ?? ''));
        $nameNew  = trim((string)($_POST['staff_name'] ?? ''));
        $profNew  = (string)($_POST['staff_profession'] ?? 'perawat');
        $posNew   = trim((string)($_POST['staff_position'] ?? 'Perawat Pelaksana'));
        $targetId = (int)($_POST['staff_unit_id'] ?? 0);
        if (!in_array($profNew, ['perawat','bidan','admin','lainnya'], true)) $profNew = 'perawat';
        $validTarget = lbk_one($conn, "SELECT unit_id FROM logbook_kpi_nursing_units WHERE unit_id=? AND is_active=1", [$targetId], 'i');
        if (!$validTarget || !lbk_can_manage_target_unit($conn, $currentLevel, $isAdmin, $unitId, $targetId)) {
            $notice = 'Anda tidak berwenang menambahkan staf ke unit tersebut.';
        } elseif ($nikNew === '' || $nameNew === '') {
            $notice = 'NIK dan nama staf wajib diisi.';
        } elseif (lbk_one($conn, "SELECT id FROM employees WHERE nik=? LIMIT 1", [$nikNew], 's')) {
            $notice = 'NIK sudah terdaftar. Gunakan fitur pindahkan staf.';
        } else {
            $stmt = $conn->prepare("INSERT INTO employees(nik,full_name,profession,employment_status,unit_id,position_name,is_active,created_at,updated_at) VALUES(?, ?, ?, 'aktif', ?, ?, 1, NOW(), NOW())");
            if ($stmt) {
                $stmt->bind_param('sssis',$nikNew,$nameNew,$profNew,$targetId,$posNew);
                $stmt->execute(); $newEmpId=(int)$stmt->insert_id; $stmt->close();
                $aud=$conn->prepare("INSERT INTO logbook_kpi_staff_unit_audit(employee_id,action_type,new_unit_id,new_status,note,acted_by,acted_by_name) VALUES(?,'create',?,'aktif','Tambah staf dari modul logbook',?,?)");
                if($aud){$aud->bind_param('iiis',$newEmpId,$targetId,$user['id'],$user['name']);$aud->execute();$aud->close();}
                $notice = 'Staf baru berhasil ditambahkan. Akun login belum dibuat.';
            }
        }
        $_GET['tab']='staffunit';
    }

    if ($action === 'move_nursing_staff' && lbk_can_manage_nursing_staff($currentLevel, $isAdmin)) {
        $empIdMove = (int)($_POST['employee_id'] ?? 0);
        $targetId  = (int)($_POST['target_unit_id'] ?? 0);
        $posMove   = trim((string)($_POST['position_name'] ?? ''));
        $empMove   = lbk_one($conn, "SELECT id,unit_id,employment_status FROM employees WHERE id=? LIMIT 1", [$empIdMove], 'i');
        $validTarget = lbk_one($conn, "SELECT unit_id FROM logbook_kpi_nursing_units WHERE unit_id=? AND is_active=1", [$targetId], 'i');
        $canTarget = lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,$targetId);
        $sourceMapped = $empMove ? lbk_one($conn, "SELECT canonical_unit_id FROM logbook_kpi_unit_mapping WHERE source_unit_id=? AND is_active=1 LIMIT 1", [(int)($empMove['unit_id']??0)], 'i') : null;
        $canSource = $empMove ? ($sourceMapped ? lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,(int)$sourceMapped['canonical_unit_id']) : $canTarget) : false;
        if (!$empMove || !$validTarget || !$canSource || !$canTarget) {
            $notice='Pemindahan staf ditolak karena unit tidak sesuai hak akses.';
        } else {
            $oldUnit=(int)($empMove['unit_id']??0);
            if ($posMove !== '') {
                $stmt=$conn->prepare("UPDATE employees SET unit_id=?,position_name=?,employment_status='aktif',is_active=1,updated_at=NOW() WHERE id=?");
                if($stmt){$stmt->bind_param('isi',$targetId,$posMove,$empIdMove);$stmt->execute();$stmt->close();}
            } else {
                $stmt=$conn->prepare("UPDATE employees SET unit_id=?,employment_status='aktif',is_active=1,updated_at=NOW() WHERE id=?");
                if($stmt){$stmt->bind_param('ii',$targetId,$empIdMove);$stmt->execute();$stmt->close();}
            }
            $aud=$conn->prepare("INSERT INTO logbook_kpi_staff_unit_audit(employee_id,action_type,old_unit_id,new_unit_id,old_status,new_status,note,acted_by,acted_by_name) VALUES(?,'move',?,?,?,'aktif','Mutasi/penyesuaian unit staf',?,?)");
            if($aud){$oldStatus=(string)$empMove['employment_status'];$aud->bind_param('iiisis',$empIdMove,$oldUnit,$targetId,$oldStatus,$user['id'],$user['name']);$aud->execute();$aud->close();}
            $notice='Unit staf berhasil diperbarui.';
        }
        $_GET['tab']='staffunit';
    }

    if ($action === 'set_nursing_staff_status' && lbk_can_manage_nursing_staff($currentLevel, $isAdmin)) {
        $empIdStatus=(int)($_POST['employee_id']??0);
        $newStatus=(string)($_POST['employment_status']??'nonaktif');
        if(!in_array($newStatus,['aktif','nonaktif','resign','mutasi_keluar'],true))$newStatus='nonaktif';
        $empStatus=lbk_one($conn,"SELECT id,unit_id,employment_status FROM employees WHERE id=? LIMIT 1",[$empIdStatus],'i');
        if(!$empStatus || !lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,(int)($empStatus['unit_id']??0))){
            $notice='Perubahan status staf ditolak.';
        } else {
            $activeFlag=$newStatus==='aktif'?1:0;
            $resignDate=in_array($newStatus,['resign','mutasi_keluar'],true)?date('Y-m-d'):null;
            $stmt=$conn->prepare("UPDATE employees SET employment_status=?,is_active=?,resign_date=?,updated_at=NOW() WHERE id=?");
            if($stmt){$stmt->bind_param('sisi',$newStatus,$activeFlag,$resignDate,$empIdStatus);$stmt->execute();$stmt->close();}
            $aud=$conn->prepare("INSERT INTO logbook_kpi_staff_unit_audit(employee_id,action_type,old_unit_id,old_status,new_status,note,acted_by,acted_by_name) VALUES(?,'status',?,?,?,'Perubahan status staf',?,?)");
            if($aud){$oldUnit=(int)$empStatus['unit_id'];$oldStatus=(string)$empStatus['employment_status'];$aud->bind_param('iissis',$empIdStatus,$oldUnit,$oldStatus,$newStatus,$user['id'],$user['name']);$aud->execute();$aud->close();}
            $notice='Status staf berhasil diperbarui.';
        }
        $_GET['tab']='staffunit';
    }

    if ($action === 'merge_duplicate_nursing_unit' && ($isAdmin || $currentLevel==='kadiv')) {
        $sourceId=(int)($_POST['source_unit_id']??0);
        $canonicalId=(int)($_POST['canonical_unit_id']??0);
        $mapRow=lbk_one($conn,"SELECT source_unit_id,canonical_unit_id FROM logbook_kpi_unit_mapping WHERE source_unit_id=? AND canonical_unit_id=? AND source_unit_id<>canonical_unit_id LIMIT 1",[$sourceId,$canonicalId],'ii');
        if(!$mapRow){
            $notice='Mapping unit duplikat tidak valid.';
        } else {
            $countRow=lbk_one($conn,"SELECT COUNT(*) c FROM employees WHERE unit_id=?",[$sourceId],'i');
            $moved=(int)($countRow['c']??0);
            $stmt=$conn->prepare("UPDATE employees SET unit_id=?,updated_at=NOW() WHERE unit_id=?");
            if($stmt){$stmt->bind_param('ii',$canonicalId,$sourceId);$stmt->execute();$stmt->close();}
            $stmt=$conn->prepare("UPDATE units SET is_active=0,updated_at=NOW() WHERE id=?");
            if($stmt){$stmt->bind_param('i',$sourceId);$stmt->execute();$stmt->close();}
            $notice='Unit duplikat berhasil dirapikan. '.$moved.' staf dipindahkan ke unit utama; unit lama dinonaktifkan.';
        }
        $_GET['tab']='staffunit';
    }

    // ── save_salary ──
    if ($action === 'save_salary' && $isAdmin) {
        $uid    = (int)($_POST['salary_user_id'] ?? 0);
        $month2 = (int)($_POST['salary_month'] ?? date('n'));
        $year2  = (int)($_POST['salary_year'] ?? date('Y'));
        $amount = max(0, (float)($_POST['salary_amount'] ?? 0));
        $note   = trim((string)($_POST['salary_note'] ?? ''));
        if ($uid > 0) {
            $stmt = $conn->prepare("INSERT INTO logbook_kpi_salary_refs(user_id,month,year,salary_amount,note,created_by) VALUES(?,?,?,?,?,?) ON DUPLICATE KEY UPDATE salary_amount=VALUES(salary_amount),note=VALUES(note),updated_at=NOW()");
            if ($stmt) { $stmt->bind_param('iiidsi', $uid,$month2,$year2,$amount,$note,$user['id']); $stmt->execute(); $stmt->close(); $notice = 'Referensi gaji berhasil disimpan.'; }
        }
    }
}

// ── Read params ───────────────────────────────────────────────
$month = max(1, min(12, (int)($_GET['month'] ?? date('n'))));
$year  = max(2024, min(2099, (int)($_GET['year'] ?? date('Y'))));
$tab   = (string)($_GET['tab'] ?? 'dashboard');

$selectedLogDate = (string)($_POST['log_date'] ?? $_POST['assign_date'] ?? $_GET['log_date'] ?? date('Y-m-d'));
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $selectedLogDate)) { $selectedLogDate = date('Y-m-d'); }
$selectedShift = (string)($_POST['shift'] ?? $_POST['assign_shift'] ?? $_GET['shift'] ?? 'Pagi');
if (!in_array($selectedShift, ['Pagi','Sore','Malam','Non Shift','Libur'], true)) { $selectedShift = 'Pagi'; }

$roleOptions = [
    'pelaksana'      => 'Perawat Pelaksana',
    'katim'          => 'Katim / PJ Shift',
    'kaunit'         => 'Kepala Unit',
    'kasubdiv_rajal' => 'Kasubdiv Keperawatan Rawat Jalan',
    'kasubdiv_ranap' => 'Kasubdiv Keperawatan Rawat Inap',
    'kadiv'          => 'Kepala Divisi Keperawatan',
];
$selectedInputRole = (string)($_POST['input_role'] ?? $_GET['input_role'] ?? $currentLevel);
if (!isset($roleOptions[$selectedInputRole])) {
    $selectedInputRole = isset($roleOptions[$currentLevel]) ? $currentLevel : 'pelaksana';
}
$unitActivityOptions   = lbk_unit_options();
$selectedActivityUnit  = strtoupper(trim((string)($_POST['activity_unit'] ?? $_GET['activity_unit'] ?? lbk_unit_from_text($unitName))));
if (!array_key_exists($selectedActivityUnit, $unitActivityOptions)) { $selectedActivityUnit = 'UMUM'; }
$unlockOtherUnit = (int)($_POST['unlock_unit'] ?? $_GET['unlock_unit'] ?? 0) === 1;

// ── Prefill edit entry (BARU) ────────────────────────────────
$editEntryId = (int)($_GET['edit_entry_id'] ?? 0);
$editEntry   = null;
if ($editEntryId > 0) {
    $editEntry = lbk_one($conn, "SELECT * FROM logbook_kpi_entries WHERE id=? LIMIT 1", [$editEntryId], 'i');
    if ($editEntry && !$isAdmin && (int)$editEntry['user_id'] !== $user['id']) { $editEntry = null; }
    if ($editEntry) {
        $tab               = 'input';
        $_GET['tab']       = 'input';
        $selectedLogDate   = (string)$editEntry['log_date'];
        $selectedShift     = (string)$editEntry['shift'];
        $selectedInputRole = (string)$editEntry['role_level'];
        if (!isset($roleOptions[$selectedInputRole])) { $selectedInputRole = 'pelaksana'; }
    }
}

$filterUnit = (int)($_GET['unit_id'] ?? 0);
$filterUser = (int)($_GET['user_id'] ?? 0);
$filterEmployee = (int)($_GET['employee_id'] ?? 0);
$start      = sprintf('%04d-%02d-01', $year, $month);
$end        = date('Y-m-t', strtotime($start));

$units = lbk_all($conn, "SELECT id, name FROM units WHERE is_active=1 ORDER BY category, name");
$users = lbk_all($conn, "SELECT us.id user_id, COALESCE(e.full_name, us.username) name, COALESCE(u.name,'') unit_name FROM users us LEFT JOIN employees e ON e.id=us.employee_id LEFT JOIN units u ON u.id=e.unit_id WHERE us.is_active=1 ORDER BY name LIMIT 500");

$workloadUnitOptions  = lbk_workload_options($units);
$canManageWorkload    = $isAdmin || in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true);
$defaultWorkloadKey   = lbk_workload_unit_key($unitName ?: 'UMUM');
if (!isset($workloadUnitOptions[$defaultWorkloadKey])) { $workloadUnitOptions[$defaultWorkloadKey] = lbk_workload_unit_label($defaultWorkloadKey); }
$selectedWorkloadKey  = strtoupper(trim((string)($_GET['workload_unit_key'] ?? $_POST['workload_unit_key'] ?? $defaultWorkloadKey)));
if (!isset($workloadUnitOptions[$selectedWorkloadKey])) { $selectedWorkloadKey = $defaultWorkloadKey; }
$selectedWorkloadDate = (string)($_GET['workload_date'] ?? $_POST['workload_date'] ?? date('Y-m-d'));
$workloadStart        = $start;
$workloadEnd          = $end;
$workloadRowsDaily    = lbk_all($conn, "SELECT * FROM logbook_kpi_unit_workload_daily WHERE workload_date BETWEEN ? AND ? ORDER BY workload_date DESC, unit_label ASC", [$workloadStart,$workloadEnd], 'ss');
$workloadMonthlyRows  = lbk_all($conn, "SELECT unit_key, MAX(unit_label) unit_label, AVG(patient_count) avg_patients, AVG(los_count) avg_los, AVG(bed_capacity) avg_beds, AVG(occupancy_percent) avg_occupancy, AVG(patient_per_nurse_shift) avg_ratio_shift, AVG(multiplier) avg_multiplier, COUNT(*) filled_days FROM logbook_kpi_unit_workload_daily WHERE workload_date BETWEEN ? AND ? GROUP BY unit_key", [$workloadStart,$workloadEnd], 'ss');
$workloadMap = [];
foreach ($workloadMonthlyRows as $wr) {
    $occ = (float)($wr['avg_occupancy'] ?? 0);
    [$lvl,$mul,$cls] = lbk_workload_level_from_occupancy($occ);
    $workloadMap[(string)$wr['unit_key']] = $wr + ['level_calc'=>$lvl,'multiplier_calc'=>(float)($wr['avg_multiplier'] ?: $mul),'class_calc'=>$cls];
}
$workloadToday = lbk_one($conn, "SELECT * FROM logbook_kpi_unit_workload_daily WHERE unit_key=? AND workload_date=? LIMIT 1", [$selectedWorkloadKey,$selectedWorkloadDate], 'ss') ?: null;
$monthlyWorkloadRows = lbk_all($conn, "SELECT * FROM logbook_kpi_unit_workload_monthly WHERE month=? AND year=? ORDER BY unit_label ASC", [$month,$year], 'ii');
$monthlyWorkloadMap  = [];
foreach ($monthlyWorkloadRows as $mwr) { $monthlyWorkloadMap[(string)$mwr['unit_key']] = $mwr; }
$monthlyWorkloadSelected = $monthlyWorkloadMap[$selectedWorkloadKey] ?? null;


$canManageNursingStaff = lbk_can_manage_nursing_staff($currentLevel, $isAdmin);
$ownCanonicalUnitId    = lbk_canonical_unit_id($conn, $unitId);
$nursingUnits = lbk_all($conn, "SELECT nu.unit_key,nu.unit_id,nu.display_name,nu.sort_order,
    COUNT(DISTINCT CASE WHEN e.employment_status='aktif' AND e.is_active=1 THEN e.id END) active_staff,
    COUNT(DISTINCT CASE WHEN e.employment_status<>'aktif' OR e.is_active=0 THEN e.id END) inactive_staff,
    COUNT(DISTINCT CASE WHEN us.id IS NOT NULL AND us.is_active=1 AND e.employment_status='aktif' AND e.is_active=1 THEN e.id END) with_account
    FROM logbook_kpi_nursing_units nu
    LEFT JOIN logbook_kpi_unit_mapping mp ON mp.canonical_unit_id=nu.unit_id AND mp.is_active=1
    LEFT JOIN employees e ON e.unit_id=mp.source_unit_id
    LEFT JOIN users us ON us.employee_id=e.id
    WHERE nu.is_active=1
    GROUP BY nu.unit_key,nu.unit_id,nu.display_name,nu.sort_order
    ORDER BY nu.sort_order");
$staffUnitFilter=(int)($_GET['staff_unit_id']??($currentLevel==='kaunit'?$ownCanonicalUnitId:0));
$staffStatusFilter=(string)($_GET['staff_status']??'aktif');
$staffSearch=trim((string)($_GET['staff_search']??''));
$staffWhere="WHERE nu.is_active=1"; $staffParams=[]; $staffTypes='';
if($staffUnitFilter>0){$staffWhere.=" AND nu.unit_id=?";$staffParams[]=$staffUnitFilter;$staffTypes.='i';}
if(in_array($staffStatusFilter,['aktif','nonaktif','resign','mutasi_keluar'],true)){$staffWhere.=" AND e.employment_status=?";$staffParams[]=$staffStatusFilter;$staffTypes.='s';}
if($staffSearch!==''){$staffWhere.=" AND (e.full_name LIKE ? OR e.nik LIKE ? OR e.position_name LIKE ?)";$like='%'.$staffSearch.'%';$staffParams[]=$like;$staffParams[]=$like;$staffParams[]=$like;$staffTypes.='sss';}
$nursingStaffRows=lbk_all($conn,"SELECT e.id,e.nik,e.full_name,e.profession,e.employment_status,e.is_active,e.position_name,e.unit_id source_unit_id,
    u.name source_unit_name,nu.unit_id canonical_unit_id,nu.display_name canonical_unit_name,
    us.id user_id,us.username,us.is_active user_active
    FROM employees e
    JOIN logbook_kpi_unit_mapping mp ON mp.source_unit_id=e.unit_id AND mp.is_active=1
    JOIN logbook_kpi_nursing_units nu ON nu.unit_id=mp.canonical_unit_id
    LEFT JOIN units u ON u.id=e.unit_id
    LEFT JOIN users us ON us.employee_id=e.id
    $staffWhere
    ORDER BY nu.sort_order,e.full_name LIMIT 1000",$staffParams,$staffTypes);
$duplicateUnitRows=lbk_all($conn,"SELECT mp.source_unit_id,mp.canonical_unit_id,COALESCE(usrc.name,mp.source_unit_name) source_name,nu.display_name canonical_name,COALESCE(usrc.is_active,0) source_active,COUNT(e.id) staff_count
    FROM logbook_kpi_unit_mapping mp
    JOIN logbook_kpi_nursing_units nu ON nu.unit_id=mp.canonical_unit_id
    LEFT JOIN units usrc ON usrc.id=mp.source_unit_id
    LEFT JOIN employees e ON e.unit_id=mp.source_unit_id
    WHERE mp.source_unit_id<>mp.canonical_unit_id AND mp.is_active=1
    GROUP BY mp.source_unit_id,mp.canonical_unit_id,source_name,nu.display_name,source_active
    ORDER BY nu.sort_order,source_name");
$unassignedStaff=lbk_all($conn,"SELECT e.id,e.nik,e.full_name,e.position_name,COALESCE(u.name,'Tanpa unit') current_unit FROM employees e LEFT JOIN units u ON u.id=e.unit_id LEFT JOIN logbook_kpi_unit_mapping mp ON mp.source_unit_id=e.unit_id WHERE e.employment_status='aktif' AND e.is_active=1 AND (e.unit_id IS NULL OR mp.source_unit_id IS NULL) AND (e.profession IN ('perawat','bidan') OR LOWER(COALESCE(e.position_name,'')) LIKE '%perawat%' OR LOWER(COALESCE(e.position_name,'')) LIKE '%bidan%') ORDER BY e.full_name LIMIT 500");

$params = [$start,$end]; $types = 'ss';
$where  = "WHERE le.log_date BETWEEN ? AND ?";
if (!$isAdmin && !in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true)) { $where .= " AND le.user_id=?"; $params[] = $user['id']; $types .= 'i'; }
if ($filterUnit > 0) { $where .= " AND le.unit_id=?"; $params[] = $filterUnit; $types .= 'i'; }
if ($filterEmployee > 0) {
    /* Tombol Lihat Kegiatan memakai employee_id karena lebih stabil daripada user_id pada data lama. */
    $where .= " AND le.employee_id=?";
    $params[] = $filterEmployee;
    $types .= 'i';
} elseif ($filterUser > 0) {
    /* Filter dropdown tetap mendukung akun user dan employee yang terhubung. */
    $where .= " AND (le.user_id=? OR le.employee_id=(SELECT usf.employee_id FROM users usf WHERE usf.id=? LIMIT 1))";
    $params[] = $filterUser;
    $params[] = $filterUser;
    $types .= 'ii';
}

/* KPI bulanan: ideal dihitung SATU KALI per aktivitas dalam periode, bukan setiap baris input. */
$summary      = lbk_one($conn, "SELECT
    SUM(x.total_entries) total_entries,
    SUM(LEAST(x.actual_count,x.target_count)*x.weight) real_score,
    SUM(x.actual_count*x.weight) workload_score,
    SUM(GREATEST(x.actual_count-x.target_count,0)*x.weight) overload_score,
    SUM(x.target_count*x.weight) ideal_score,
    SUM(x.total_minutes) total_minutes,
    SUM(x.verified_count) verified_count,
    SUM(x.pending_count) pending_count
FROM (
    SELECT le.activity_id,
           MAX(le.weight) weight,
           SUM(le.real_count) actual_count,
           MAX(le.ideal_count) target_count,
           COUNT(*) total_entries,
           SUM(le.duration_minutes) total_minutes,
           SUM(CASE WHEN le.status='verified' THEN 1 ELSE 0 END) verified_count,
           SUM(CASE WHEN le.status='submitted' THEN 1 ELSE 0 END) pending_count
    FROM logbook_kpi_entries le $where
    GROUP BY le.activity_id
) x", $params, $types) ?? [];
$totalEntries = (int)($summary['total_entries'] ?? 0);
$realScore    = (float)($summary['real_score'] ?? 0);
$workloadScore= (float)($summary['workload_score'] ?? 0);
$overloadScore= (float)($summary['overload_score'] ?? 0);
$idealScore   = max(1, (float)($summary['ideal_score'] ?? 0));
$achievement  = $totalEntries ? min(150, ($realScore / $idealScore) * 100) : 0;
$workloadAchievement = $totalEntries ? min(999, ($workloadScore / $idealScore) * 100) : 0;
$verifiedRate = $totalEntries ? (((int)($summary['verified_count'] ?? 0) / $totalEntries) * 100) : 0;

$domainRows = lbk_all($conn, "SELECT x.kpi_domain,
       SUM(LEAST(x.actual_count,x.target_count)*x.weight) real_score,
       SUM(x.actual_count*x.weight) workload_score,
       SUM(GREATEST(x.actual_count-x.target_count,0)*x.weight) overload_score,
       SUM(x.target_count*x.weight) ideal_score,
       SUM(x.total_entries) total
FROM (
    SELECT le.kpi_domain, le.activity_id,
           MAX(le.weight) weight,
           SUM(le.real_count) actual_count,
           MAX(le.ideal_count) target_count,
           COUNT(*) total_entries
    FROM logbook_kpi_entries le $where
    GROUP BY le.kpi_domain, le.activity_id
) x
GROUP BY x.kpi_domain
ORDER BY real_score DESC", $params, $types);
$kpiScore   = lbk_calculate_domain_kpi($domainRows, $currentLevel, $verifiedRate);
[$kpiLabel, $kpiClass] = lbk_kpi_category($kpiScore);

$personRows = lbk_all($conn, "SELECT x.user_id, MAX(x.employee_id) employee_id, MAX(x.employee_name) employee_name, MAX(x.role_level) role_level,
       MAX(x.unit_name) unit_name, SUM(x.total_entries) total_entries,
       SUM(LEAST(x.actual_count,x.target_count)*x.weight) real_score,
       SUM(x.actual_count*x.weight) workload_score,
       SUM(GREATEST(x.actual_count-x.target_count,0)*x.weight) overload_score,
       SUM(x.target_count*x.weight) ideal_score,
       SUM(x.minutes) minutes, SUM(x.verified_count) verified_count,
       COALESCE(MAX(sr.salary_amount),0) salary_amount
FROM (
    SELECT le.user_id, MAX(le.employee_id) employee_id, MAX(le.employee_name) employee_name, MAX(le.role_level) role_level,
           MAX(COALESCE(le.unit_name,'')) unit_name, le.activity_id,
           MAX(le.weight) weight, SUM(le.real_count) actual_count,
           MAX(le.ideal_count) target_count, COUNT(*) total_entries,
           SUM(le.duration_minutes) minutes,
           SUM(CASE WHEN le.status='verified' THEN 1 ELSE 0 END) verified_count
    FROM logbook_kpi_entries le $where
    GROUP BY le.user_id, le.activity_id
) x
LEFT JOIN logbook_kpi_salary_refs sr ON sr.user_id=x.user_id AND sr.month=$month AND sr.year=$year
GROUP BY x.user_id
ORDER BY real_score DESC LIMIT 200", $params, $types);

/* Rekap kegiatan bulanan per staf. Mengikuti filter bulan, tahun, unit, dan staf. */
$staffActivityRows = lbk_all($conn, "SELECT
        le.user_id,
        MAX(le.employee_id) employee_id,
        MAX(le.employee_name) employee_name,
        MAX(COALESCE(le.unit_name,'')) unit_name,
        le.activity_id,
        MAX(le.activity_name) activity_name,
        MAX(le.category_code) category_code,
        MAX(le.kpi_domain) kpi_domain,
        COUNT(*) entry_count,
        SUM(le.real_count) total_real,
        SUM(le.patients_count) total_patients,
        SUM(le.duration_minutes) total_minutes,
        SUM(CASE WHEN le.status='verified' THEN 1 ELSE 0 END) verified_count,
        MIN(le.log_date) first_date,
        MAX(le.log_date) last_date
    FROM logbook_kpi_entries le $where
    GROUP BY le.user_id, le.activity_id
    ORDER BY employee_name ASC, total_real DESC, activity_name ASC", $params, $types);

$selectedStaffName = 'Semua Staf';
if ($filterEmployee > 0) {
    $selectedStaff = lbk_one($conn, "SELECT full_name FROM employees WHERE id=? LIMIT 1", [$filterEmployee], 'i');
    if ($selectedStaff && trim((string)($selectedStaff['full_name'] ?? '')) !== '') {
        $selectedStaffName = (string)$selectedStaff['full_name'];
    } else {
        $selectedStaffLog = lbk_one($conn, "SELECT employee_name FROM logbook_kpi_entries WHERE employee_id=? ORDER BY log_date DESC,id DESC LIMIT 1", [$filterEmployee], 'i');
        if ($selectedStaffLog) $selectedStaffName = (string)$selectedStaffLog['employee_name'];
    }
} else {
    foreach ($users as $uu) {
        if ((int)$uu['user_id'] === $filterUser) {
            $selectedStaffName = (string)$uu['name'];
            break;
        }
    }
}

$unitKeyCase = lbk_entry_unit_key_case_sql('le.unit_name');
$unitRows    = lbk_all($conn, "SELECT x.unit_key, MAX(x.unit_name) unit_name,
       SUM(x.total_entries) total_entries, COUNT(DISTINCT x.user_id) staff_count,
       SUM(LEAST(x.actual_count,x.target_count)*x.weight) real_score,
       SUM(x.actual_count*x.weight) workload_score,
       SUM(GREATEST(x.actual_count-x.target_count,0)*x.weight) overload_score,
       SUM(x.target_count*x.weight) ideal_score,
       SUM(x.minutes) minutes
FROM (
    SELECT $unitKeyCase unit_key, MAX(COALESCE(le.unit_name,'Tanpa Unit')) unit_name,
           le.user_id, le.activity_id, MAX(le.weight) weight,
           SUM(le.real_count) actual_count, MAX(le.ideal_count) target_count,
           COUNT(*) total_entries, SUM(le.duration_minutes) minutes
    FROM logbook_kpi_entries le $where
    GROUP BY unit_key, le.user_id, le.activity_id
) x
GROUP BY x.unit_key
ORDER BY real_score DESC", $params, $types);
$entries     = lbk_all($conn, "SELECT le.* FROM logbook_kpi_entries le $where ORDER BY le.log_date DESC, le.created_at DESC LIMIT 300", $params, $types);

// Top 10 aktivitas berdasarkan total real_count (jumlah tindakan/kamar yang benar-benar dikerjakan).
$rankingRows = lbk_all($conn, "SELECT le.activity_id, le.activity_name, le.category_code, le.kpi_domain, COUNT(*) entry_count, SUM(le.real_count) total_real, SUM(le.patients_count) total_patients, COUNT(DISTINCT le.user_id) staff_count, COUNT(DISTINCT le.unit_id) unit_count, SUM(le.duration_minutes) total_minutes, SUM(CASE WHEN le.status='verified' THEN 1 ELSE 0 END) verified_count FROM logbook_kpi_entries le $where GROUP BY le.activity_id, le.activity_name, le.category_code, le.kpi_domain ORDER BY total_real DESC, entry_count DESC, le.activity_name ASC LIMIT 10", $params, $types);
$rankingGrandTotal = array_sum(array_map(static fn($r) => (float)($r['total_real'] ?? 0), $rankingRows));


// Monitoring kedisiplinan pengisian logbook harian per unit.
// Siklus pelaporan berganti otomatis setiap pukul 07.00 WITA:
// sebelum 07.00 masih menampilkan tanggal pelayanan kemarin, mulai 07.00 menampilkan hari ini.
$disciplineTimezone = new DateTimeZone('Asia/Makassar');
$disciplineNow      = new DateTimeImmutable('now', $disciplineTimezone);
$disciplineCutoff   = $disciplineNow->setTime(7, 0, 0);
$disciplineDateObj  = $disciplineNow < $disciplineCutoff
    ? $disciplineNow->modify('-1 day')
    : $disciplineNow;
$disciplineDate     = $disciplineDateObj->format('Y-m-d');
$nextDisciplineReset = ($disciplineNow < $disciplineCutoff
    ? $disciplineCutoff
    : $disciplineCutoff->modify('+1 day'));

$disciplineSql = "SELECT
        nu.unit_id,
        nu.unit_name,
        COUNT(DISTINCT e.id) total_staff,
        COUNT(DISTINCT CASE WHEN filled.employee_id IS NOT NULL THEN e.id END) filled_staff,
        COUNT(DISTINCT CASE WHEN filled.employee_id IS NULL THEN e.id END) not_filled_staff,
        GROUP_CONCAT(
            DISTINCT CASE WHEN filled.employee_id IS NULL THEN e.full_name END
            ORDER BY e.full_name SEPARATOR ', '
        ) not_filled_names
    FROM (
        SELECT 1 unit_id, 'IGD' unit_name, 1 sort_order
        UNION ALL SELECT 2, 'VK / Kamar Bersalin', 2
        UNION ALL SELECT 3, 'HD / Hemodialisa', 3
        UNION ALL SELECT 4, 'Poliklinik', 4
        UNION ALL SELECT 5, 'OK / Kamar Operasi', 5
        UNION ALL SELECT 6, 'Pav. Canigara', 6
        UNION ALL SELECT 7, 'Pav. Cempaka', 7
        UNION ALL SELECT 8, 'Pav. Cendana', 8
        UNION ALL SELECT 11, 'ICU', 9
        UNION ALL SELECT 10, 'NICU', 10
        UNION ALL SELECT 9, 'Ruang Bayi', 11
    ) nu
    LEFT JOIN employees e
        ON e.is_active=1
       AND e.employment_status='aktif'
       AND (
            (nu.unit_id=1  AND e.unit_id IN (1,25))
         OR (nu.unit_id=2  AND e.unit_id IN (2,27,77,84))
         OR (nu.unit_id=3  AND e.unit_id IN (3,20,71,87))
         OR (nu.unit_id=4  AND e.unit_id IN (4,86))
         OR (nu.unit_id=5  AND e.unit_id IN (5,22,85))
         OR (nu.unit_id=6  AND e.unit_id IN (6,21))
         OR (nu.unit_id=7  AND e.unit_id IN (7,24))
         OR (nu.unit_id=8  AND e.unit_id IN (8,23,88))
         OR (nu.unit_id=9  AND e.unit_id IN (9,92))
         OR (nu.unit_id=10 AND e.unit_id IN (10))
         OR (nu.unit_id=11 AND e.unit_id IN (11))
       )
    LEFT JOIN (
        SELECT DISTINCT
            COALESCE(NULLIF(le.employee_id,0), us.employee_id) employee_id
        FROM logbook_kpi_entries le
        LEFT JOIN users us ON us.id=le.user_id
        WHERE le.log_date=?
          AND COALESCE(NULLIF(le.employee_id,0), us.employee_id) IS NOT NULL
    ) filled ON filled.employee_id=e.id
    WHERE 1=1";
$disciplineParams = [$disciplineDate];
$disciplineTypes  = 's';
if ($filterUnit > 0) {
    // Filter dashboard memakai ID unit utama 1–11.
    $disciplineSql .= " AND nu.unit_id=?";
    $disciplineParams[] = $filterUnit;
    $disciplineTypes   .= 'i';
}
$disciplineSql .= " GROUP BY nu.unit_id,nu.unit_name,nu.sort_order
    ORDER BY nu.sort_order ASC";
$disciplineRows = lbk_all($conn, $disciplineSql, $disciplineParams, $disciplineTypes);
$disciplineTotalStaff  = array_sum(array_map(static fn($r) => (int)($r['total_staff'] ?? 0), $disciplineRows));
$disciplineFilledStaff = array_sum(array_map(static fn($r) => (int)($r['filled_staff'] ?? 0), $disciplineRows));
$disciplinePendingStaff= max(0, $disciplineTotalStaff - $disciplineFilledStaff);
$disciplineRate        = $disciplineTotalStaff > 0 ? ($disciplineFilledStaff / $disciplineTotalStaff * 100) : 0;

// Jika jadwal bulanan sudah diunggah, denominator kedisiplinan memakai staf yang benar-benar terjadwal wajib logbook.
$scheduleDayCount=(int)((lbk_one($conn,"SELECT COUNT(*) c FROM logbook_kpi_staff_schedules WHERE schedule_date=? AND requires_logbook=1",[$disciplineDate],'s')['c']??0));
$disciplineUsesSchedule=$scheduleDayCount>0;
if($disciplineUsesSchedule){
    $scheduleDisciplineSql="SELECT nu.unit_id,nu.display_name unit_name,
        COUNT(DISTINCT s.employee_id) total_staff,
        COUNT(DISTINCT CASE WHEN f.employee_id IS NOT NULL THEN s.employee_id END) filled_staff,
        COUNT(DISTINCT CASE WHEN f.employee_id IS NULL THEN s.employee_id END) not_filled_staff,
        GROUP_CONCAT(DISTINCT CASE WHEN f.employee_id IS NULL THEN COALESCE(e.full_name,s.employee_name_excel) END ORDER BY COALESCE(e.full_name,s.employee_name_excel) SEPARATOR ', ') not_filled_names
      FROM logbook_kpi_staff_schedules s
      JOIN logbook_kpi_nursing_units nu ON nu.unit_id=s.unit_id AND nu.is_active=1
      LEFT JOIN employees e ON e.id=s.employee_id
      LEFT JOIN (SELECT DISTINCT COALESCE(NULLIF(le.employee_id,0),us.employee_id) employee_id FROM logbook_kpi_entries le LEFT JOIN users us ON us.id=le.user_id WHERE le.log_date=?) f ON f.employee_id=s.employee_id
      WHERE s.schedule_date=? AND s.requires_logbook=1 AND s.employee_id IS NOT NULL";
    $sp=[$disciplineDate,$disciplineDate];$stp='ss';if($filterUnit>0){$scheduleDisciplineSql.=" AND s.unit_id=?";$sp[]=$filterUnit;$stp.='i';}
    $scheduleDisciplineSql.=" GROUP BY nu.unit_id,nu.display_name,nu.sort_order ORDER BY nu.sort_order";
    $disciplineRows=lbk_all($conn,$scheduleDisciplineSql,$sp,$stp);
    $disciplineTotalStaff=array_sum(array_map(static fn($r)=>(int)($r['total_staff']??0),$disciplineRows));
    $disciplineFilledStaff=array_sum(array_map(static fn($r)=>(int)($r['filled_staff']??0),$disciplineRows));
    $disciplinePendingStaff=max(0,$disciplineTotalStaff-$disciplineFilledStaff);
    $disciplineRate=$disciplineTotalStaff>0?($disciplineFilledStaff/$disciplineTotalStaff*100):0;
}

$scheduleMonthView=(int)($_GET['schedule_month']??$month);$scheduleYearView=(int)($_GET['schedule_year']??$year);$scheduleUnitView=(int)($_GET['schedule_unit']??($filterUnit>0?$filterUnit:0));
$scheduleUploads=lbk_all($conn,"SELECT su.*,nu.display_name unit_name FROM logbook_kpi_schedule_uploads su LEFT JOIN logbook_kpi_nursing_units nu ON nu.unit_id=su.unit_id ORDER BY su.created_at DESC LIMIT 20");
$scheduleShiftCodes=lbk_all($conn, "SELECT * FROM logbook_kpi_shift_codes WHERE is_active=1 ORDER BY requires_logbook DESC, code");
$unmatchedSchedules=lbk_all($conn,"SELECT unit_id,employee_name_excel,normalized_name,COUNT(*) days_count FROM logbook_kpi_staff_schedules WHERE employee_id IS NULL GROUP BY unit_id,employee_name_excel,normalized_name ORDER BY employee_name_excel");
$scheduleEmployees=$scheduleUnitView>0?lbk_all($conn,"SELECT e.id,e.full_name FROM employees e LEFT JOIN logbook_kpi_unit_mapping mp ON mp.source_unit_id=e.unit_id AND mp.is_active=1 WHERE e.is_active=1 AND COALESCE(mp.canonical_unit_id,e.unit_id)=? ORDER BY e.full_name",[$scheduleUnitView],'i'):[];
$scheduleSummaryWhere="WHERE YEAR(s.schedule_date)=? AND MONTH(s.schedule_date)=?";$scheduleSummaryParams=[$scheduleYearView,$scheduleMonthView];$scheduleSummaryTypes='ii';if($scheduleUnitView>0){$scheduleSummaryWhere.=" AND s.unit_id=?";$scheduleSummaryParams[]=$scheduleUnitView;$scheduleSummaryTypes.='i';}
$scheduleMonthlyRows=lbk_all($conn,"SELECT s.employee_id,
 COALESCE(
   MAX(CONVERT(e.full_name USING utf8mb4) COLLATE utf8mb4_unicode_ci),
   MAX(CONVERT(s.employee_name_excel USING utf8mb4) COLLATE utf8mb4_unicode_ci)
 ) employee_name,
 MAX(CONVERT(nu.display_name USING utf8mb4) COLLATE utf8mb4_unicode_ci) unit_name,
 SUM(CASE WHEN s.requires_logbook=1 THEN 1 ELSE 0 END) scheduled_days,
 COUNT(DISTINCT CASE WHEN s.requires_logbook=1 AND f.log_date IS NOT NULL THEN s.schedule_date END) filled_days,
 SUM(CASE WHEN s.requires_logbook=0 THEN 1 ELSE 0 END) off_days,
 GROUP_CONCAT(DISTINCT CASE WHEN s.requires_logbook=1 AND f.log_date IS NULL THEN DATE_FORMAT(s.schedule_date,'%d/%m') END ORDER BY s.schedule_date SEPARATOR ', ') missing_dates
 FROM logbook_kpi_staff_schedules s
 JOIN logbook_kpi_nursing_units nu ON nu.unit_id=s.unit_id
 LEFT JOIN employees e ON e.id=s.employee_id
 LEFT JOIN (SELECT DISTINCT COALESCE(NULLIF(le.employee_id,0),us.employee_id) employee_id,le.log_date FROM logbook_kpi_entries le LEFT JOIN users us ON us.id=le.user_id) f ON f.employee_id=s.employee_id AND f.log_date=s.schedule_date
 $scheduleSummaryWhere AND s.employee_id IS NOT NULL
 GROUP BY s.employee_id
 ORDER BY unit_name,employee_name",$scheduleSummaryParams,$scheduleSummaryTypes);


$activityRoleForMaster = lbk_master_role_level($selectedInputRole);
$unitFilteredRole      = lbk_role_uses_unit_activity($selectedInputRole);
if ($unitFilteredRole && !$unlockOtherUnit) {
    $activities = lbk_all($conn, "SELECT * FROM logbook_kpi_activity_master WHERE is_active=1 AND role_level=? AND unit_group IN ('UMUM', ?) ORDER BY FIELD(unit_group, ?, 'UMUM'), category_code, activity_name", [$activityRoleForMaster, $selectedActivityUnit, $selectedActivityUnit], 'sss');
} else {
    $activities = lbk_all($conn, "SELECT * FROM logbook_kpi_activity_master WHERE is_active=1 AND role_level=? ORDER BY FIELD(unit_group,'UMUM','IGD','KAMAR_BERSALIN','HD','OK','POLIKLINIK','RAWAT_INAP','RUANG_BAYI','NICU','ICU'), category_code, activity_name", [$activityRoleForMaster], 's');
}

$patientAssignment = lbk_one($conn, "SELECT * FROM logbook_kpi_patient_assignments WHERE user_id=? AND assign_date=? AND shift=? LIMIT 1", [$user['id'],$selectedLogDate,$selectedShift], 'iss');
$assignedRooms = [];
if ($patientAssignment && trim((string)($patientAssignment['room_list'] ?? '')) !== '') {
    $assignedRooms = array_values(array_unique(array_filter(array_map('trim', preg_split('/[\r\n,;]+/', (string)$patientAssignment['room_list']) ?: []), static fn($v) => $v !== '')));
}
$editSelectedRooms = [];
if ($editEntry && trim((string)($editEntry['patient_room'] ?? '')) !== '') {
    $editSelectedRooms = array_values(array_unique(array_filter(array_map('trim', preg_split('/[\r\n,;]+/', (string)$editEntry['patient_room']) ?: []), static fn($v) => $v !== '')));
}

$masterFilterRole     = trim((string)($_GET['master_role'] ?? ''));
$masterFilterUnit     = strtoupper(trim((string)($_GET['master_unit'] ?? '')));
$masterFilterCategory = strtoupper(trim((string)($_GET['master_category'] ?? '')));
$masterFilterDomain   = trim((string)($_GET['master_domain'] ?? ''));
$masterFilterStatus   = (string)($_GET['master_status'] ?? 'all');
$masterFilterQuery    = trim((string)($_GET['master_q'] ?? ''));

$masterWhere  = " WHERE 1=1";
$masterParams = [];
$masterTypes  = '';
if ($masterFilterRole !== '' && in_array($masterFilterRole, ['pelaksana','katim','kaunit','kasubdiv','kadiv'], true)) {
    $masterWhere .= " AND m.role_level=?"; $masterParams[]=$masterFilterRole; $masterTypes.='s';
}
if ($masterFilterUnit !== '' && array_key_exists($masterFilterUnit, lbk_unit_options())) {
    $masterWhere .= " AND m.unit_group=?"; $masterParams[]=$masterFilterUnit; $masterTypes.='s';
}
if ($masterFilterCategory !== '') {
    $masterWhere .= " AND m.category_code=?"; $masterParams[]=$masterFilterCategory; $masterTypes.='s';
}
if ($masterFilterDomain !== '' && in_array($masterFilterDomain, ['produktivitas','dokumentasi','patient_safety','disiplin','leadership','kompetensi','mutu','kolaborasi'], true)) {
    $masterWhere .= " AND m.kpi_domain=?"; $masterParams[]=$masterFilterDomain; $masterTypes.='s';
}
if ($masterFilterStatus === 'active') { $masterWhere .= " AND m.is_active=1"; }
elseif ($masterFilterStatus === 'inactive') { $masterWhere .= " AND m.is_active=0"; }
if ($masterFilterQuery !== '') {
    $masterWhere .= " AND (m.activity_name LIKE CONCAT('%',?,'%') OR m.description LIKE CONCAT('%',?,'%') OR m.unit_measure LIKE CONCAT('%',?,'%'))";
    array_push($masterParams,$masterFilterQuery,$masterFilterQuery,$masterFilterQuery); $masterTypes.='sss';
}
$allMaster = lbk_all($conn, "SELECT m.*, c.name category_name FROM logbook_kpi_activity_master m LEFT JOIN logbook_kpi_categories c ON c.code=m.category_code".$masterWhere." ORDER BY FIELD(m.role_level,'pelaksana','katim','kaunit','kasubdiv','kadiv'), FIELD(m.unit_group,'UMUM','IGD','KAMAR_BERSALIN','HD','OK','POLIKLINIK','RAWAT_INAP','RUANG_BAYI','NICU','ICU'), m.category_code, m.activity_name", $masterParams, $masterTypes);
$categories  = lbk_all($conn, "SELECT * FROM logbook_kpi_categories ORDER BY code");
$editMasterId= $isAdmin ? (int)($_GET['edit_master'] ?? 0) : 0;
$editMaster  = $editMasterId > 0 ? lbk_one($conn, "SELECT * FROM logbook_kpi_activity_master WHERE id=? LIMIT 1", [$editMasterId], 'i') : null;
if ($editMasterId > 0 && !$editMaster) { $notice = $notice ?: 'Master aktivitas yang akan diedit tidak ditemukan.'; }
?>
<style>
.lbk-card{background:rgba(255,255,255,.92);border:1px solid rgba(226,232,240,.9);border-radius:24px;box-shadow:0 18px 45px rgba(15,23,42,.08)}
.lbk-glass{background:linear-gradient(135deg,rgba(37,99,235,.94),rgba(124,58,237,.92));border-radius:28px;color:white;box-shadow:0 24px 60px rgba(37,99,235,.26)}
.lbk-input{width:100%;border:1px solid #e2e8f0;border-radius:16px;padding:.7rem .9rem;background:white;outline:none}.lbk-input:focus{border-color:#6366f1;box-shadow:0 0 0 4px rgba(99,102,241,.12)}
.lbk-btn{display:inline-flex;align-items:center;gap:.5rem;border-radius:16px;padding:.7rem 1rem;font-weight:800;transition:.2s}.lbk-btn:hover{transform:translateY(-1px)}
.lbk-tab{border-radius:999px;padding:.65rem 1rem;font-weight:800;border:1px solid #e2e8f0}.lbk-tab.active{background:#1e293b;color:white;border-color:#1e293b}
.lbk-table th{background:#f8fafc;color:#475569;font-size:.75rem;text-transform:uppercase;letter-spacing:.05em}
.lbk-table td,.lbk-table th{padding:.75rem;border-bottom:1px solid #e2e8f0;vertical-align:top}
.print-only{display:none}
@media print{.no-print{display:none!important}.print-only{display:block}.lbk-card,.lbk-glass{box-shadow:none!important;border:1px solid #cbd5e1!important}.module-shell{padding:0!important}}
.lbk-search-wrap{position:relative;width:100%}
.lbk-search-btn{width:100%;min-height:48px;border:1px solid #e2e8f0;border-radius:16px;background:#fff;padding:.7rem 2.4rem .7rem .9rem;text-align:left;display:flex;align-items:center;justify-content:space-between;gap:.75rem;outline:none;transition:.2s;color:#020617;font-weight:500}
.lbk-search-btn:hover{border-color:#c7d2fe;box-shadow:0 10px 22px rgba(15,23,42,.05)}
.lbk-search-wrap.open .lbk-search-btn,.lbk-search-btn:focus{border-color:#6366f1;box-shadow:0 0 0 4px rgba(99,102,241,.12)}
.lbk-search-label{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.35}
.lbk-search-caret{margin-left:auto;color:#64748b;font-size:.85rem;flex-shrink:0}
.lbk-search-panel{position:absolute;z-index:9999;left:0;right:0;top:calc(100% + 8px);background:#18151f;color:#fff;border:1px solid rgba(255,255,255,.08);border-radius:18px;box-shadow:0 28px 70px rgba(15,23,42,.35);padding:.75rem;display:none;max-height:390px;overflow:hidden}
.lbk-search-wrap.open .lbk-search-panel{display:block}
.lbk-search-input{width:100%;border:1px solid rgba(255,255,255,.12);border-radius:14px;background:#fff;color:#0f172a;padding:.72rem .9rem;margin-bottom:.65rem;outline:none;font-weight:600}
.lbk-search-input:focus{box-shadow:0 0 0 4px rgba(99,102,241,.25);border-color:#818cf8}
.lbk-search-list{max-height:285px;overflow:auto;padding-right:.25rem}
.lbk-search-option{width:100%;border:0;background:transparent;color:#f8fafc;text-align:left;border-radius:12px;padding:.65rem .7rem;cursor:pointer;font-size:.9rem;line-height:1.3;display:block}
.lbk-search-option:hover,.lbk-search-option.active{background:rgba(99,102,241,.32)}
.lbk-search-option.selected{background:#2563eb;color:#fff;font-weight:800}
.lbk-search-muted{color:#cbd5e1;font-size:.8rem;padding:.7rem}
.lbk-search-native-hidden{position:absolute!important;opacity:0!important;pointer-events:none!important;width:1px!important;height:1px!important;left:-9999px!important}
@media(max-width:768px){.lbk-search-panel{position:fixed;left:1rem;right:1rem;top:auto;bottom:1rem;max-height:70vh}.lbk-search-list{max-height:52vh}}
</style>

<div class="space-y-6">

    <!-- Header -->
    <div class="lbk-glass p-6 md:p-8 relative overflow-hidden">
        <div class="absolute -right-10 -top-10 w-44 h-44 bg-white/10 rounded-full"></div>
        <div class="absolute right-20 bottom-3 w-24 h-24 bg-white/10 rounded-full"></div>
        <div class="relative flex flex-col lg:flex-row lg:items-center lg:justify-between gap-5">
            <div>
                <div class="text-sm font-semibold text-blue-100 uppercase tracking-widest">Internal Training Centre</div>
                <h1 class="text-3xl md:text-4xl font-black mt-2">Logbook & KPI Keperawatan</h1>
                <p class="text-blue-50 mt-2 max-w-3xl">Input aktivitas harian, validasi berjenjang, analisis real vs ideal, produktivitas bulanan, dan tampilan KPI rinci per staf/unit.</p>
                <div class="mt-4 flex flex-wrap gap-2 text-xs font-bold">
                    <span class="px-3 py-1 rounded-full bg-white/15 border border-white/20">Role: <?= e(lbk_level_label($currentLevel)) ?></span>
                    <span class="px-3 py-1 rounded-full bg-white/15 border border-white/20">Unit: <?= e($unitName ?: '-') ?></span>
                    <span class="px-3 py-1 rounded-full bg-white/15 border border-white/20">Periode: <?= e(date('F Y', strtotime($start))) ?></span>
                </div>
            </div>
            <div class="bg-white/15 border border-white/20 rounded-3xl p-5 min-w-[220px]">
                <div class="text-sm text-blue-100">Skor KPI Periode</div>
                <div class="text-5xl font-black mt-1"><?= number_format($kpiScore, 1) ?></div>
                <div class="mt-2 inline-flex px-3 py-1 rounded-full bg-white text-slate-800 text-sm font-black"><?= e($kpiLabel) ?></div>
            </div>
        </div>
    </div>

    <?php if ($notice): ?>
        <div class="no-print rounded-2xl border border-emerald-200 bg-emerald-50 text-emerald-800 px-4 py-3 font-semibold">
            <i class="fas fa-check-circle mr-2"></i><?= e($notice) ?>
        </div>
    <?php endif; ?>

    <!-- Filter utama hanya untuk tab analitik/rekap. Tab operasional memakai filter masing-masing. -->
    <?php $showGlobalFilter = in_array($tab, ['dashboard','detail','unit','staf','staffactivity','ranking'], true); ?>
    <?php if ($showGlobalFilter): ?>
    <form method="get" class="no-print lbk-card p-4 grid grid-cols-1 md:grid-cols-5 gap-3 items-end">
        <input type="hidden" name="module" value="logbook_kpi">
        <input type="hidden" name="tab" value="<?= e($tab) ?>">
        <div><label class="text-xs font-bold text-slate-500 uppercase">Bulan</label>
            <select name="month" class="lbk-input"><?php for($m=1;$m<=12;$m++): ?><option value="<?= $m ?>" <?= $m===$month?'selected':'' ?>><?= date('F', mktime(0,0,0,$m,1)) ?></option><?php endfor; ?></select></div>
        <div><label class="text-xs font-bold text-slate-500 uppercase">Tahun</label><input class="lbk-input" type="number" name="year" value="<?= $year ?>"></div>
        <div><label class="text-xs font-bold text-slate-500 uppercase">Unit</label>
            <select name="unit_id" class="lbk-input"><option value="0">Semua Unit</option><?php foreach($units as $u): ?><option value="<?= (int)$u['id'] ?>" <?= (int)$u['id']===$filterUnit?'selected':'' ?>><?= e($u['name']) ?></option><?php endforeach; ?></select></div>
        <div><label class="text-xs font-bold text-slate-500 uppercase">Staf</label>
            <select name="user_id" class="lbk-input"><option value="0">Semua Staf</option><?php foreach($users as $u): ?><option value="<?= (int)$u['user_id'] ?>" <?= (int)$u['user_id']===$filterUser?'selected':'' ?>><?= e($u['name']) ?></option><?php endforeach; ?></select></div>
        <button class="lbk-btn bg-slate-900 text-white justify-center"><i class="fas fa-filter"></i> Terapkan</button>
    </form>
    <?php endif; ?>

    <!-- Tabs -->
    <div class="no-print flex flex-wrap gap-2">
        <?php
        $tabs = ['dashboard'=>'Dashboard KPI','input'=>'Input Harian','detail'=>'Detail Logbook','unit'=>'Rekap Unit','staf'=>'Rekap Staf','staffactivity'=>'Kegiatan per Staf','ranking'=>'Ranking Kegiatan','beban'=>'Beban Unit','verifikasi'=>'Verifikasi','schedule'=>'Jadwal & Kedisiplinan'];
        if ($canManageNursingStaff) $tabs['staffunit'] = 'Manajemen Staf Unit';
        if ($isAdmin) $tabs['master'] = 'Master Aktivitas';
        if ($isAdmin) $tabs['gaji']   = 'Referensi Gaji';
        foreach ($tabs as $k => $v): ?>
            <a class="lbk-tab <?= $tab===$k?'active':'' ?>"
               href="index.php?module=logbook_kpi&tab=<?= e($k) ?>&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>">
                <?= e($v) ?>
            </a>
        <?php endforeach; ?>
        <button onclick="window.print()" class="lbk-tab bg-white"><i class="fas fa-print mr-1"></i> Print</button>
    </div>

    <!-- ═══════════════════════════════ DASHBOARD ═══════════════════════════════ -->
    <?php if ($tab === 'dashboard'): ?>
        <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
            <div class="lbk-card p-5"><div class="text-sm text-slate-500 font-bold">Total Aktivitas</div><div class="text-3xl font-black text-slate-800 mt-1"><?= number_format($totalEntries) ?></div><div class="text-xs text-slate-400 mt-2">Aktivitas tercatat periode ini</div></div>
            <div class="lbk-card p-5"><div class="text-sm text-slate-500 font-bold">KPI Count vs Ideal</div><div class="text-3xl font-black text-blue-700 mt-1"><?= number_format($achievement,1) ?>%</div><div class="w-full h-2 bg-slate-100 rounded-full mt-3"><div class="h-2 bg-blue-600 rounded-full" style="width:<?= min(100,$achievement) ?>%"></div></div><div class="text-xs text-slate-400 mt-2">Beban real: <?= number_format($workloadAchievement,1) ?>% | Overload: <?= number_format($overloadScore,1) ?></div></div>
            <div class="lbk-card p-5"><div class="text-sm text-slate-500 font-bold">Terverifikasi</div><div class="text-3xl font-black text-emerald-700 mt-1"><?= number_format($verifiedRate,1) ?>%</div><div class="text-xs text-slate-400 mt-2"><?= (int)($summary['verified_count']??0) ?> verified, <?= (int)($summary['pending_count']??0) ?> pending</div></div>
            <div class="lbk-card p-5"><div class="text-sm text-slate-500 font-bold">Durasi Kerja Tercatat</div><div class="text-3xl font-black text-violet-700 mt-1"><?= number_format(((int)($summary['total_minutes']??0))/60,1) ?> jam</div><div class="text-xs text-slate-400 mt-2">Akumulasi durasi logbook</div></div>
        </div>
        <!-- Kedisiplinan pengisian logbook per unit -->
        <div class="lbk-card p-5 space-y-4">
            <div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4">
                <div>
                    <h3 class="text-xl font-black text-slate-800">Kedisiplinan Pengisian Logbook Harian per Unit</h3>
                    <p class="text-sm text-slate-500 mt-1">
                        Membandingkan jumlah staf aktif yang memiliki akses logbook dengan staf yang sudah membuat minimal satu entri pada tanggal pelayanan
                        <b><?= e(date('d/m/Y', strtotime($disciplineDate))) ?></b>.
                    </p>
                </div>
                <div class="grid grid-cols-2 md:grid-cols-4 gap-2 text-center min-w-full lg:min-w-[520px]">
                    <div class="rounded-2xl bg-slate-50 border border-slate-200 p-3"><div class="text-xs font-bold text-slate-500">TOTAL STAF</div><div class="text-2xl font-black text-slate-800"><?= number_format($disciplineTotalStaff) ?></div></div>
                    <div class="rounded-2xl bg-emerald-50 border border-emerald-200 p-3"><div class="text-xs font-bold text-emerald-700">SUDAH ISI</div><div class="text-2xl font-black text-emerald-700"><?= number_format($disciplineFilledStaff) ?></div></div>
                    <div class="rounded-2xl bg-rose-50 border border-rose-200 p-3"><div class="text-xs font-bold text-rose-700">BELUM ISI</div><div class="text-2xl font-black text-rose-700"><?= number_format($disciplinePendingStaff) ?></div></div>
                    <div class="rounded-2xl bg-blue-50 border border-blue-200 p-3"><div class="text-xs font-bold text-blue-700">KEPATUHAN</div><div class="text-2xl font-black text-blue-700"><?= number_format($disciplineRate,1) ?>%</div></div>
                </div>
            </div>

            <div class="rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
                <i class="fas fa-clock mr-2"></i>
                <b>Cutoff pukul 07.00 WITA.</b>
                Sebelum pukul 07.00 dashboard masih menampilkan kepatuhan tanggal sebelumnya. Mulai pukul 07.00 tampilan otomatis berganti ke hari baru dan hitungan kembali dari nol.
                Reset berikutnya: <b><?= e($nextDisciplineReset->format('d/m/Y H:i')) ?> WITA</b>.
            </div>

            <div class="overflow-x-auto">
                <table class="w-full lbk-table">
                    <thead><tr><th>Unit</th><th>Total Staf</th><th>Sudah Isi</th><th>Belum Isi</th><th>Kepatuhan</th><th>Status</th><th>Staf Belum Isi</th></tr></thead>
                    <tbody>
                    <?php if (!$disciplineRows): ?>
                        <tr><td colspan="7" class="text-center text-slate-400 py-8">Belum ada staf aktif yang terhubung ke unit.</td></tr>
                    <?php else: foreach ($disciplineRows as $dr):
                        $totalUnit  = (int)($dr['total_staff'] ?? 0);
                        $filledUnit = (int)($dr['filled_staff'] ?? 0);
                        $pendingUnit= max(0, $totalUnit-$filledUnit);
                        $rateUnit   = $totalUnit > 0 ? ($filledUnit/$totalUnit*100) : 0;
                        if ($rateUnit >= 100) { $statusText='Lengkap'; $statusClass='bg-emerald-50 text-emerald-700 border-emerald-200'; }
                        elseif ($rateUnit >= 80) { $statusText='Baik'; $statusClass='bg-blue-50 text-blue-700 border-blue-200'; }
                        elseif ($rateUnit >= 50) { $statusText='Perlu Diingatkan'; $statusClass='bg-amber-50 text-amber-700 border-amber-200'; }
                        else { $statusText='Belum Disiplin'; $statusClass='bg-rose-50 text-rose-700 border-rose-200'; }
                    ?>
                        <tr>
                            <td class="font-black text-slate-800"><?= e($dr['unit_name']) ?></td>
                            <td class="font-bold"><?= number_format($totalUnit) ?></td>
                            <td class="font-black text-emerald-700"><?= number_format($filledUnit) ?></td>
                            <td class="font-black text-rose-700"><?= number_format($pendingUnit) ?></td>
                            <td class="min-w-[180px]">
                                <div class="flex items-center justify-between gap-3"><span class="font-black"><?= number_format($rateUnit,1) ?>%</span><span class="text-xs text-slate-400"><?= $filledUnit ?>/<?= $totalUnit ?></span></div>
                                <div class="w-full h-2 bg-slate-100 rounded-full mt-2"><div class="h-2 rounded-full bg-emerald-500" style="width:<?= min(100,max(0,$rateUnit)) ?>%"></div></div>
                            </td>
                            <td><span class="inline-flex rounded-full border px-3 py-1 text-xs font-black <?= $statusClass ?>"><?= e($statusText) ?></span></td>
                            <td class="text-xs text-slate-500 max-w-[420px]"><?= $pendingUnit>0 ? e((string)($dr['not_filled_names'] ?? '-')) : '<span class="font-bold text-emerald-700">Semua staf sudah mengisi</span>' ?></td>
                        </tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table>
            </div>
        </div>


        <!-- Modal Kelola Staf: diletakkan di luar tabel agar tidak membuat layout/freeze -->
        <div id="staffManageModal" class="fixed inset-0 z-[9999] hidden items-center justify-center bg-slate-950/55 p-4" aria-hidden="true">
            <div class="w-full max-w-xl rounded-3xl bg-white shadow-2xl" onclick="event.stopPropagation()">
                <div class="flex items-start justify-between border-b border-slate-100 p-5">
                    <div>
                        <h3 class="text-xl font-black text-slate-900">Kelola Staf</h3>
                        <div id="staffModalName" class="mt-1 font-bold text-slate-700"></div>
                        <div id="staffModalNik" class="text-xs text-slate-400"></div>
                    </div>
                    <button type="button" onclick="closeStaffManageModal()" class="h-10 w-10 rounded-full border border-slate-200 text-slate-500 hover:bg-slate-50">&times;</button>
                </div>
                <div class="space-y-5 p-5">
                    <form method="post" class="space-y-3">
                        <input type="hidden" name="action" value="move_nursing_staff">
                        <input type="hidden" name="employee_id" id="staffMoveEmployeeId">
                        <div>
                            <label class="text-xs font-black uppercase text-slate-500">Unit Keperawatan</label>
                            <select name="target_unit_id" id="staffTargetUnitId" class="lbk-input mt-1">
                                <?php foreach($nursingUnits as $nu): if($currentLevel==='kaunit' && (int)$nu['unit_id']!==$ownCanonicalUnitId)continue; ?>
                                    <option value="<?= (int)$nu['unit_id'] ?>"><?= e($nu['display_name']) ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div>
                            <label class="text-xs font-black uppercase text-slate-500">Jabatan</label>
                            <input name="position_name" id="staffPositionName" class="lbk-input mt-1" placeholder="Jabatan">
                        </div>
                        <button class="lbk-btn lbk-btn-primary w-full justify-center"><i class="fas fa-save"></i> Simpan Unit/Jabatan</button>
                    </form>
                    <div class="border-t border-slate-100 pt-5">
                        <form method="post" class="space-y-3">
                            <input type="hidden" name="action" value="set_nursing_staff_status">
                            <input type="hidden" name="employee_id" id="staffStatusEmployeeId">
                            <div>
                                <label class="text-xs font-black uppercase text-slate-500">Status Staf</label>
                                <select name="employment_status" id="staffEmploymentStatus" class="lbk-input mt-1">
                                    <option value="aktif">Aktif</option>
                                    <option value="nonaktif">Nonaktif</option>
                                    <option value="resign">Resign</option>
                                    <option value="mutasi_keluar">Mutasi Keluar</option>
                                </select>
                            </div>
                            <button class="lbk-btn w-full justify-center border border-slate-200 bg-white text-slate-700"><i class="fas fa-user-edit"></i> Ubah Status</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <script>
        function openStaffManageModal(staff) {
            const modal = document.getElementById('staffManageModal');
            if (!modal || !staff) return;
            document.getElementById('staffModalName').textContent = staff.name || '-';
            document.getElementById('staffModalNik').textContent = staff.nik ? ('NIK: ' + staff.nik) : '';
            document.getElementById('staffMoveEmployeeId').value = staff.id || '';
            document.getElementById('staffStatusEmployeeId').value = staff.id || '';
            document.getElementById('staffTargetUnitId').value = String(staff.unit_id || '');
            document.getElementById('staffPositionName').value = staff.position || '';
            document.getElementById('staffEmploymentStatus').value = staff.status || 'aktif';
            modal.classList.remove('hidden');
            modal.classList.add('flex');
            modal.setAttribute('aria-hidden', 'false');
            document.body.style.overflow = 'hidden';
        }
        function closeStaffManageModal() {
            const modal = document.getElementById('staffManageModal');
            if (!modal) return;
            modal.classList.add('hidden');
            modal.classList.remove('flex');
            modal.setAttribute('aria-hidden', 'true');
            document.body.style.overflow = '';
        }
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') closeStaffManageModal();
        });
        document.getElementById('staffManageModal')?.addEventListener('click', closeStaffManageModal);
        </script>

        <div class="grid grid-cols-1 xl:grid-cols-2 gap-5">
            <div class="lbk-card p-5"><h3 class="text-lg font-black text-slate-800 mb-4">KPI per Domain</h3><canvas id="domainChart" height="170"></canvas></div>
            <div class="lbk-card p-5"><h3 class="text-lg font-black text-slate-800 mb-4">Top Produktivitas Staf</h3><div class="overflow-x-auto"><table class="w-full lbk-table"><thead><tr><th>Staf</th><th>Role</th><th>Skor</th><th>Capaian</th><th>KPI</th></tr></thead><tbody><?php foreach(array_slice($personRows,0,8) as $r): $ach=(float)$r['ideal_score']>0?((float)$r['real_score']/(float)$r['ideal_score']*100):0; $ks=min(100,($ach*.7)+30); [$lab,$cls]=lbk_kpi_category($ks); ?><tr><td class="font-bold"><?= e($r['employee_name']) ?><div class="text-xs text-slate-400"><?= e($r['unit_name']) ?></div></td><td><?= e(lbk_level_label($r['role_level'])) ?></td><td class="font-black"><?= number_format((float)$r['real_score'],1) ?></td><td><?= number_format($ach,1) ?>%</td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $cls ?>"><?= e($lab) ?></span></td></tr><?php endforeach; ?></tbody></table></div></div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <script>
        new Chart(document.getElementById('domainChart'),{type:'bar',data:{labels:<?= json_encode(array_map(fn($r)=>ucwords(str_replace('_',' ',$r['kpi_domain'])),$domainRows)) ?>,datasets:[{label:'Skor Real',data:<?= json_encode(array_map(fn($r)=>(float)$r['real_score'],$domainRows)) ?>},{label:'Skor Ideal',data:<?= json_encode(array_map(fn($r)=>(float)$r['ideal_score'],$domainRows)) ?>}]},options:{responsive:true,plugins:{legend:{position:'bottom'}},scales:{y:{beginAtZero:true}}}});
        </script>

    <!-- ═══════════════════════════════ INPUT HARIAN ════════════════════════════ -->
    <?php elseif ($tab === 'input'): ?>
        <div class="grid grid-cols-1 xl:grid-cols-3 gap-5">

            <!-- Form: Daftar Pasien -->
            <form method="post" class="xl:col-span-3 lbk-card p-5 space-y-4">
                <input type="hidden" name="action" value="save_patient_assignment">
                <div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4">
                    <div>
                        <h3 class="text-xl font-black text-slate-800">Pasien yang Anda Rawat Hari Ini</h3>
                        <p class="text-sm text-slate-500 mt-1">Isi sekali di awal shift. Daftar kamar/bed akan muncul sebagai pilihan saat input kegiatan.</p>
                    </div>
                    <?php if($patientAssignment): ?>
                        <div class="rounded-2xl border border-emerald-200 bg-emerald-50 px-4 py-2 text-sm font-bold text-emerald-700">
                            Tersimpan: <?= (int)($patientAssignment['patient_count']??0) ?> pasien · <?= count($assignedRooms) ?> kamar/bed
                        </div>
                    <?php endif; ?>
                </div>
                <div class="grid grid-cols-1 md:grid-cols-5 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Tanggal</label><input type="date" name="assign_date" value="<?= e($selectedLogDate) ?>" class="lbk-input"></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Shift</label><select name="assign_shift" class="lbk-input"><?php foreach(['Pagi','Sore','Malam','Non Shift','Libur'] as $sh): ?><option value="<?= e($sh) ?>" <?= $selectedShift===$sh?'selected':'' ?>><?= e($sh) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Jumlah Pasien</label><input type="number" min="0" name="assign_patient_count" value="<?= e($patientAssignment['patient_count']??'') ?>" class="lbk-input" placeholder="Contoh: 6"></div>
                    <div class="md:col-span-2"><label class="text-xs font-bold text-slate-500 uppercase">Catatan Assignment</label><input name="assign_note" value="<?= e($patientAssignment['note']??'') ?>" class="lbk-input" placeholder="Contoh: pasien isolasi, risiko jatuh"></div>
                </div>
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Daftar Kamar / Bed</label>
                    <textarea name="assign_room_list" rows="3" class="lbk-input" placeholder="Contoh: 201, 202, 205 Bed A&#10;Pisahkan dengan koma atau baris baru"><?= e($patientAssignment['room_list']??'') ?></textarea>
                    <div class="text-xs text-slate-400 mt-1">Daftar ini menjadi dropdown pilihan kamar/bed pada form kegiatan.</div>
                </div>
                <div class="flex flex-wrap gap-2 items-center">
                    <button class="lbk-btn bg-emerald-600 text-white"><i class="fas fa-bed"></i> Simpan Daftar Pasien/Kamar</button>
                    <a class="lbk-btn bg-white border border-slate-200 text-slate-700" href="index.php?module=logbook_kpi&tab=input&log_date=<?= e($selectedLogDate) ?>&shift=<?= urlencode($selectedShift) ?>&month=<?= $month ?>&year=<?= $year ?>"><i class="fas fa-rotate"></i> Muat Ulang</a>
                </div>
            </form>

            <?php
                $limitDate = (string)($editEntry ? $editEntry['log_date'] : $selectedLogDate);
                $limitShift = (string)($editEntry ? $editEntry['shift'] : $selectedShift);
                $limitEditId = $editEntry ? (int)$editEntry['id'] : 0;
                $limitPolicy = lbk_shift_duration_policy($limitShift);
                $limitUsed = lbk_shift_used_minutes($conn,$user['id'],$employeeId,$limitDate,$limitShift,$limitEditId);
                $limitRemaining = $limitPolicy['max_minutes'] > 0 ? max(0,(int)$limitPolicy['max_minutes']-$limitUsed) : 0;
            ?>
            <!-- Form: Input / Edit Logbook -->
            <form method="post" class="xl:col-span-2 lbk-card p-5 space-y-4" id="formLogbook"
                  data-used-minutes="<?= (int)$limitUsed ?>">
                <input type="hidden" name="action"        value="<?= $editEntry ? 'edit_log' : 'save_log' ?>">
                <input type="hidden" name="edit_entry_id" value="<?= $editEntry ? (int)$editEntry['id'] : 0 ?>">

                <div class="flex items-start justify-between gap-3">
                    <div>
                        <h3 class="text-xl font-black text-slate-800">
                            <?= $editEntry ? '✏️ Edit Logbook #'.(int)$editEntry['id'] : 'Input Logbook Harian' ?>
                        </h3>
                        <?php if ($editEntry): ?>
                            <p class="text-sm text-amber-600 font-bold mt-1">
                                <i class="fas fa-info-circle mr-1"></i>
                                Sedang mengedit entri yang sudah ada. Setelah disimpan, status kembali ke <b>submitted</b> untuk verifikasi ulang.
                            </p>
                        <?php endif; ?>
                    </div>
                    <?php if ($editEntry): ?>
                        <a href="index.php?module=logbook_kpi&tab=detail&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>"
                           class="lbk-btn bg-slate-100 text-slate-700 text-sm px-3 py-2">
                            <i class="fas fa-times"></i> Batal Edit
                        </a>
                    <?php endif; ?>
                </div>

                <!-- Tanggal, Shift, Role, Unit -->
                <div class="grid grid-cols-1 md:grid-cols-4 gap-3">
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Tanggal</label>
                        <input type="date" name="log_date" id="inputLogDate"
                               value="<?= e($editEntry ? $editEntry['log_date'] : $selectedLogDate) ?>"
                               class="lbk-input">
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Shift</label>
                        <select name="shift" id="inputShift" class="lbk-input">
                            <?php foreach(['Pagi','Sore','Malam','Non Shift','Libur'] as $sh): ?>
                                <option value="<?= e($sh) ?>"
                                    <?= ($editEntry ? $editEntry['shift'] : $selectedShift)===$sh?'selected':'' ?>>
                                    <?= e($sh) ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Role Sementara</label>
                        <select name="input_role" class="lbk-input"
                                onchange="window.location.href='index.php?module=logbook_kpi&tab=input&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&activity_unit=<?= e($selectedActivityUnit) ?>&unlock_unit=<?= $unlockOtherUnit?1:0 ?>&input_role='+this.value">
                            <?php foreach($roleOptions as $rv=>$rl): ?>
                                <option value="<?= e($rv) ?>" <?= $selectedInputRole===$rv?'selected':'' ?>><?= e($rl) ?></option>
                            <?php endforeach; ?>
                        </select>
                        <div class="text-xs text-slate-400 mt-1">Aktivitas mengikuti role yang dipilih.</div>
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Unit Aktivitas</label>
                        <select name="activity_unit" class="lbk-input"
                                <?= lbk_role_uses_unit_activity($selectedInputRole)?'':'disabled' ?>
                                onchange="window.location.href='index.php?module=logbook_kpi&tab=input&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&input_role=<?= e($selectedInputRole) ?>&unlock_unit=<?= $unlockOtherUnit?1:0 ?>&activity_unit='+this.value">
                            <?php foreach($unitActivityOptions as $uv=>$ul): ?>
                                <option value="<?= e($uv) ?>" <?= $selectedActivityUnit===$uv?'selected':'' ?>><?= e($ul) ?></option>
                            <?php endforeach; ?>
                        </select>
                        <label class="mt-2 flex items-center gap-2 text-xs font-bold text-slate-600">
                            <input type="checkbox" name="unlock_unit" value="1" <?= $unlockOtherUnit?'checked':'' ?>
                                   onchange="window.location.href='index.php?module=logbook_kpi&tab=input&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&input_role=<?= e($selectedInputRole) ?>&activity_unit=<?= e($selectedActivityUnit) ?>&unlock_unit='+(this.checked?1:0)">
                            Unlock kegiatan unit lain
                        </label>
                    </div>
                </div>


                <div id="shiftLimitCard" class="rounded-2xl border border-blue-200 bg-blue-50 px-4 py-3">
                    <div class="flex flex-wrap items-center justify-between gap-3">
                        <div>
                            <div class="text-sm font-black text-blue-900">
                                <i class="fas fa-clock mr-1"></i>Batas Durasi Shift
                            </div>
                            <div id="shiftPolicyLabel" class="text-xs text-blue-700 mt-1"><?= e($limitPolicy['label']) ?></div>
                        </div>
                        <div class="text-right">
                            <div class="text-xs text-slate-500">Sudah tercatat / Sisa</div>
                            <div class="font-black text-blue-900">
                                <span id="shiftUsed"><?= (int)$limitUsed ?></span> mnt /
                                <span id="shiftRemaining"><?= (int)$limitRemaining ?></span> mnt
                            </div>
                        </div>
                    </div>
                    <div class="mt-3 h-2 rounded-full bg-white overflow-hidden border border-blue-100">
                        <div id="shiftProgress" class="h-full bg-blue-600 transition-all"
                             style="width:<?= $limitPolicy['max_minutes']>0 ? min(100,round(($limitUsed/max(1,(int)$limitPolicy['max_minutes']))*100,1)) : 0 ?>%"></div>
                    </div>
                    <div id="shiftWarning" class="hidden mt-2 text-xs font-bold text-rose-600"></div>
                </div>

                <!-- Pilih Aktivitas -->
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Aktivitas</label>
                    <select name="activity_id" id="selectActivity" class="lbk-input" required>
                        <?php foreach($activities as $a): ?>
                            <option value="<?= (int)$a['id'] ?>"
                                data-duration="<?= (int)($a['default_duration_minutes']??15) ?>"
                                <?= ($editEntry && (int)$editEntry['activity_id']===(int)$a['id'])?'selected':'' ?>>
                                <?= e(($a['unit_group']&&$a['unit_group']!=='UMUM'?'['.lbk_unit_label($a['unit_group']).'] ':'').$a['category_code'].' - '.$a['activity_name'].' | ±'.(int)($a['default_duration_minutes']??15).' mnt | Ideal '.$a['ideal_frequency_value'].' '.$a['unit_measure'].' | Bobot '.$a['weight']) ?>
                            </option>
                        <?php endforeach; ?>
                    </select>
                    <?php if(empty($activities)): ?>
                        <div class="mt-2 rounded-2xl bg-amber-50 border border-amber-200 p-3 text-sm font-bold text-amber-700">Belum ada master aktivitas untuk role ini.</div>
                    <?php endif; ?>
                </div>

                <!-- Jam & Kamar/Bed -->
                <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Jam Kegiatan</label>
                        <input type="time" name="activity_time" id="inputActivityTime"
                               value="<?= e($editEntry ? substr((string)($editEntry['activity_time']??date('H:i')),0,5) : date('H:i')) ?>"
                               class="lbk-input" required>
                        <div class="text-xs text-slate-400 mt-1">Jam tindakan/edukasi dilakukan.</div>
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Kamar / Bed Pasien</label>
                        <?php if($assignedRooms): ?>
                            <div class="rounded-2xl border border-slate-200 bg-white p-3 max-h-52 overflow-y-auto" id="multiRoomPicker">
                                <div class="flex flex-wrap gap-2">
                                    <?php foreach($assignedRooms as $room):
                                        $roomChecked = in_array($room, $editSelectedRooms, true);
                                    ?>
                                        <label class="inline-flex items-center gap-2 rounded-xl border border-slate-200 px-3 py-2 cursor-pointer hover:border-indigo-300 hover:bg-indigo-50 transition">
                                            <input type="checkbox" name="patient_rooms[]" value="<?= e($room) ?>"
                                                   class="room-checkbox rounded border-slate-300"
                                                   <?= $roomChecked?'checked':'' ?>>
                                            <span class="text-sm font-bold text-slate-700"><?= e($room) ?></span>
                                        </label>
                                    <?php endforeach; ?>
                                </div>
                            </div>
                            <div class="flex items-center justify-between gap-2 mt-2">
                                <div class="text-xs text-emerald-600 font-bold">
                                    Bisa memilih beberapa kamar sekaligus. Real Count dan jumlah pasien otomatis minimal mengikuti jumlah kamar terpilih.
                                </div>
                                <button type="button" id="btnSelectAllRooms" class="text-xs font-black text-indigo-600 whitespace-nowrap">Pilih semua</button>
                            </div>
                            <div id="selectedRoomHint" class="text-xs text-slate-500 mt-1">Belum ada kamar dipilih.</div>
                        <?php else: ?>
                            <input name="patient_room" class="lbk-input"
                                   value="<?= e($editEntry?($editEntry['patient_room']??''):'') ?>"
                                   placeholder="Contoh: 205, 206, Bed 3"
                                   <?= $selectedInputRole==='pelaksana'?'required':'' ?>>
                            <div class="text-xs text-amber-600 mt-1 font-bold">Belum ada daftar kamar untuk tanggal &amp; shift ini. Beberapa kamar dapat dipisahkan dengan koma.</div>
                        <?php endif; ?>
                    </div>
                </div>

                <!-- Real Count, Jumlah Pasien, Durasi per Pasien, Total Durasi -->
                <div class="grid grid-cols-1 md:grid-cols-4 gap-3">
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Real Count</label>
                        <input type="number" step="0.1" name="real_count" id="inputRealCount"
                               value="<?= e($editEntry?$editEntry['real_count']:'1') ?>"
                               class="lbk-input">
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Jumlah Pasien</label>
                        <input type="number" name="patients_count" id="inputPatientsCount"
                               value="<?= e($editEntry?$editEntry['patients_count']:'1') ?>"
                               min="0" class="lbk-input">
                        <div class="text-xs text-slate-400 mt-1">Isi 1 bila untuk 1 pasien.</div>
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Durasi / Pasien (mnt)</label>
                        <input type="number" id="inputDurPerPasien"
                               value="<?= e($editEntry && (int)$editEntry['patients_count']>0
                                    ? max(1,(int)round($editEntry['duration_minutes']/max(1,(int)$editEntry['patients_count'])))
                                    : 30) ?>"
                               min="1" class="lbk-input" placeholder="menit">
                        <div class="text-xs text-slate-400 mt-1">Waktu rata-rata per pasien.</div>
                    </div>
                    <div>
                        <label class="text-xs font-bold text-slate-500 uppercase">Total Durasi (mnt)</label>
                        <input type="number" name="duration_minutes" id="inputDurationMinutes"
                               value="<?= e($editEntry?$editEntry['duration_minutes']:'30') ?>"
                               min="0" class="lbk-input">
                        <div class="text-xs text-emerald-600 mt-1 font-bold" id="durationHint">
                            = jumlah pasien × durasi/pasien
                        </div>
                    </div>
                </div>

                <!-- Mutu -->
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Mutu 0–100 (Opsional)</label>
                    <input type="number" step="0.1" name="quality_score"
                           value="<?= e($editEntry&&$editEntry['quality_score']!==null?$editEntry['quality_score']:'') ?>"
                           placeholder="Opsional" class="lbk-input" style="max-width:200px">
                </div>

                <!-- Catatan & Bukti -->
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Catatan Rinci</label>
                    <textarea name="notes" rows="4" class="lbk-input"
                              placeholder="Contoh: edukasi risiko jatuh pasien kamar 205 jam 09:30..."><?= e($editEntry?($editEntry['notes']??''):'') ?></textarea>
                </div>
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Bukti / Link / Nomor Dokumen</label>
                    <input name="evidence_note" class="lbk-input"
                           value="<?= e($editEntry?($editEntry['evidence_note']??''):'') ?>"
                           placeholder="Contoh: CPPT terisi, form edukasi, link Drive">
                </div>

                <button class="lbk-btn <?= $editEntry?'bg-amber-500':'bg-blue-600' ?> text-white">
                    <i class="fas <?= $editEntry?'fa-pen-to-square':'fa-save' ?>"></i>
                    <?= $editEntry?'Simpan Perubahan':'Simpan Logbook' ?>
                </button>
            </form>

            <!-- Panduan -->
            <div class="lbk-card p-5">
                <h3 class="text-lg font-black text-slate-800 mb-3">Panduan Cepat</h3>
                <ol class="space-y-3 text-sm text-slate-600 list-decimal pl-5">
                    <li>Pilih role dan unit aktivitas. Untuk pelaksana/Kepala Unit, kegiatan mengikuti unit yang dipilih.</li>
                    <li>Isi daftar pasien/kamar sekali di awal shift, lalu pilih kamar/bed saat input kegiatan.</li>
                    <li>Isi <b>Jumlah Pasien</b> dan <b>Durasi/Pasien</b> — Total Durasi akan terhitung otomatis. Kamu tetap bisa ubah Total Durasi secara manual.</li>
                    <li>Klik <b>Edit</b> di tab Detail Logbook untuk memperbaiki entri yang sudah dibuat. Semua status bisa diedit.</li>
                    <li>Setelah diedit, status kembali ke <b>submitted</b> agar perlu verifikasi ulang.</li>
                </ol>
            </div>
        </div>

    <!-- ═══════════════════════════════ DETAIL LOGBOOK ══════════════════════════ -->
    <?php elseif ($tab === 'detail'): ?>
        <div class="lbk-card p-5 overflow-x-auto">
            <h3 class="text-xl font-black text-slate-800 mb-4">Detail Logbook Bulanan</h3>
            <table class="w-full lbk-table">
                <thead>
                    <tr>
                        <th>Tanggal</th>
                        <th>Staf/Unit</th>
                        <th>Aktivitas</th>
                        <th>Real/Ideal</th>
                        <th>Skor</th>
                        <th>Durasi</th>
                        <th>Status</th>
                        <th>Catatan</th>
                        <th class="no-print">Aksi</th>
                    </tr>
                </thead>
                <tbody>
                <?php foreach($entries as $r):
                    $score   = min((float)$r['real_count'],(float)$r['ideal_count'])*(float)$r['weight'];
                    $over    = max(((float)$r['real_count']-(float)$r['ideal_count']),0)*(float)$r['weight'];
                    $canEdit = $isAdmin || (int)$r['user_id'] === $user['id'];
                ?>
                    <tr>
                        <td class="font-bold">
                            <?= e(date('d/m/Y',strtotime($r['log_date']))) ?>
                            <div class="text-xs text-slate-400"><?= e($r['shift']) ?></div>
                        </td>
                        <td class="font-bold">
                            <?= e($r['employee_name']) ?>
                            <div class="text-xs text-slate-400"><?= e($r['unit_name']) ?> — <?= e(lbk_level_label($r['role_level'])) ?></div>
                        </td>
                        <td>
                            <?= e($r['activity_name']) ?>
                            <div class="text-xs text-slate-400"><?= e($r['category_code'].' - '.$r['kpi_domain']) ?></div>
                        </td>
                        <td><?= number_format((float)$r['real_count'],1) ?> / <?= number_format((float)$r['ideal_count'],1) ?></td>
                        <td class="font-black">
                            <?= number_format($score,1) ?>
                            <?php if($over>0): ?><div class="text-xs text-orange-600">Overload <?= number_format($over,1) ?></div><?php endif; ?>
                        </td>
                        <td>
                            <?= (int)$r['duration_minutes'] ?> mnt
                            <?php if((int)$r['patients_count']>0): ?>
                                <div class="text-xs text-slate-400">
                                    <?= (int)$r['patients_count'] ?> pasien ·
                                    <?= number_format((int)$r['duration_minutes']/max(1,(int)$r['patients_count']),1) ?> mnt/pasien
                                </div>
                            <?php endif; ?>
                        </td>
                        <td>
                            <span class="px-2 py-1 rounded-full border text-xs font-black <?= lbk_status_badge($r['status']) ?>"><?= e($r['status']) ?></span>
                            <?php if($r['verified_by_name']): ?><div class="text-xs text-slate-400 mt-1">oleh <?= e($r['verified_by_name']) ?></div><?php endif; ?>
                        </td>
                        <td>
                            <div class="text-xs font-bold text-slate-500 mb-1">
                                Jam: <?= e(substr((string)($r['activity_time']??''),0,5)?:'-') ?> · Kamar/Bed: <?= e($r['patient_room']??'-') ?>
                            </div>
                            <div class="max-w-xs text-sm"><?= e($r['notes']) ?></div>
                            <div class="text-xs text-slate-400"><?= e($r['evidence_note']) ?></div>
                        </td>
                        <td class="no-print">
                            <?php if($canEdit): ?>
                                <a href="index.php?module=logbook_kpi&tab=input&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&edit_entry_id=<?= (int)$r['id'] ?>&input_role=<?= e($r['role_level']) ?>#formLogbook"
                                   class="lbk-btn bg-amber-500 text-white text-xs px-3 py-2">
                                    <i class="fas fa-pen-to-square"></i> Edit
                                </a>
                            <?php endif; ?>
                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>

    <!-- ═══════════════════════════════ VERIFIKASI ══════════════════════════════ -->
    <?php elseif ($tab === 'verifikasi'): ?>
<?php
/* ── Parameter filter & paginasi ── */
$vFilterDate  = trim((string)($_GET['v_date'] ?? ''));          // '' = semua tanggal
$vPage        = max(1, (int)($_GET['v_page'] ?? 1));
$vPageSize    = 10;                                              // grup per halaman
$vTab         = ($_GET['v_tab'] ?? 'pending') === 'done' ? 'done' : 'pending';

// Validasi format tanggal
if ($vFilterDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $vFilterDate)) {
    $vFilterDate = '';
}

/* ── Ambil data entries mentah untuk tab verifikasi ──
   Query terpisah dari $entries agar filter tanggal dan scope
   tidak mengganggu tab lain. ── */
$vParams = [$start, $end];
$vTypes  = 'ss';
$vWhere  = "WHERE le.log_date BETWEEN ? AND ?";

// Scope: staf biasa hanya lihat entri miliknya
if (!$isAdmin && !in_array($currentLevel, ['kaunit','kasubdiv','kasubdiv_rajal','kasubdiv_ranap','kadiv'], true)) {
    $vWhere  .= " AND le.user_id=?";
    $vParams[] = $user['id'];
    $vTypes  .= 'i';
}
if ($filterUnit > 0) { $vWhere .= " AND le.unit_id=?"; $vParams[] = $filterUnit; $vTypes .= 'i'; }
if ($filterUser > 0) { $vWhere .= " AND le.user_id=?"; $vParams[] = $filterUser; $vTypes .= 'i'; }
if ($vFilterDate !== '') {
    $vWhere  .= " AND le.log_date=?";
    $vParams[] = $vFilterDate;
    $vTypes  .= 's';
}

$vEntries = lbk_all($conn,
    "SELECT le.* FROM logbook_kpi_entries le $vWhere ORDER BY le.log_date DESC, le.created_at DESC LIMIT 1000",
    $vParams, $vTypes
);

/* ── Bangun grup ── */
$groupsPending = [];   // belum terverifikasi (ada submitted/rejected)
$groupsDone    = [];   // semua sudah verified

foreach ($vEntries as $r) {
    $groupKey = $r['log_date'].'|'.$r['user_id'].'|'.$r['shift'];
    $tpl = [
        'log_date'=>$r['log_date'],'shift'=>$r['shift'],
        'user_id'=>$r['user_id'],'employee_name'=>$r['employee_name'],
        'unit_name'=>$r['unit_name'],'role_level'=>$r['role_level'],
        'total'=>0,'verified'=>0,'submitted'=>0,'rejected'=>0,'draft'=>0,
        'kpi_score'=>0.0,'real_score'=>0.0,'ideal_score'=>0.0,'overload_score'=>0.0,
        'minutes'=>0,'rows'=>[],'ids'=>[],
    ];

    // Merge ke groupsPending & groupsDone sekaligus, pisah nanti
    if (!isset($groupsPending[$groupKey])) {
        $groupsPending[$groupKey] = $tpl;
        $groupsDone[$groupKey]    = $tpl;
    }

    $score  = min((float)$r['real_count'],(float)$r['ideal_count'])*(float)$r['weight'];
    $realR  = (float)$r['real_count']*(float)$r['weight'];
    $idealR = (float)$r['ideal_count']*(float)$r['weight'];
    $overR  = max(((float)$r['real_count']-(float)$r['ideal_count']),0)*(float)$r['weight'];

    foreach (['groupsPending','groupsDone'] as $gVar) {
        $$gVar[$groupKey]['total']++;
        $$gVar[$groupKey]['verified']       += ((string)$r['status']==='verified')?1:0;
        $$gVar[$groupKey]['submitted']      += ((string)$r['status']==='submitted')?1:0;
        $$gVar[$groupKey]['rejected']       += ((string)$r['status']==='rejected')?1:0;
        $$gVar[$groupKey]['draft']          += ((string)$r['status']==='draft')?1:0;
        $$gVar[$groupKey]['kpi_score']      += $score;
        $$gVar[$groupKey]['real_score']     += $realR;
        $$gVar[$groupKey]['ideal_score']    += $idealR;
        $$gVar[$groupKey]['overload_score'] += $overR;
        $$gVar[$groupKey]['minutes']        += (int)$r['duration_minutes'];
        $$gVar[$groupKey]['rows'][]          = $r;
        $$gVar[$groupKey]['ids'][]           = (int)$r['id'];
    }
}

// Pisah: pending = ada minimal 1 non-verified | done = semua verified
$groupsPending = array_filter($groupsPending, fn($g) => ($g['submitted']+$g['rejected']+$g['draft']) > 0);
$groupsDone    = array_filter($groupsDone,    fn($g) => $g['verified'] === $g['total'] && $g['total'] > 0);

$groupsPending = array_values($groupsPending);
$groupsDone    = array_values($groupsDone);

/* ── Paginasi ── */
function lbk_paginate(array $items, int $page, int $size): array {
    $total     = count($items);
    $totalPage = max(1, (int)ceil($total / $size));
    $page      = max(1, min($page, $totalPage));
    $offset    = ($page - 1) * $size;
    return [
        'items'      => array_slice($items, $offset, $size),
        'total'      => $total,
        'total_page' => $totalPage,
        'page'       => $page,
    ];
}

$activeGroups = $vTab === 'done' ? $groupsDone : $groupsPending;
$paged        = lbk_paginate($activeGroups, $vPage, $vPageSize);

/* ── Helper: build URL dengan parameter dipertahankan ── */
function lbk_v_url(array $override = []): string {
    $base = [
        'module'  => 'logbook_kpi',
        'tab'     => 'verifikasi',
        'month'   => $_GET['month']   ?? date('n'),
        'year'    => $_GET['year']    ?? date('Y'),
        'unit_id' => $_GET['unit_id'] ?? 0,
        'user_id' => $_GET['user_id'] ?? 0,
        'v_date'  => $_GET['v_date']  ?? '',
        'v_tab'   => $_GET['v_tab']   ?? 'pending',
        'v_page'  => $_GET['v_page']  ?? 1,
    ];
    return 'index.php?' . http_build_query(array_merge($base, $override));
}

/* ── Hitung unique tanggal tersedia untuk dropdown filter ── */
$vDatesAvail = lbk_all($conn,
    "SELECT DISTINCT le.log_date FROM logbook_kpi_entries le $vWhere ORDER BY le.log_date DESC LIMIT 60",
    $vParams, $vTypes
);
?>

<div class="space-y-5">

    <!-- ── Header + Filter ── -->
    <div class="lbk-card p-5">
        <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-4">
            <div>
                <h3 class="text-xl font-black text-slate-800">Verifikasi Logbook</h3>
                <p class="text-sm text-slate-500 mt-1">
                    Tabel dipisah antara <b>Belum Diverifikasi</b> dan <b>Sudah Diverifikasi</b>.
                    Gunakan filter tanggal untuk mempersempit data.
                </p>
            </div>
            <!-- Statistik cepat + verifikasi semua -->
            <div class="flex flex-wrap gap-3 items-center">
                <?php if($vTab==='pending' && !empty($groupsPending) && lbk_can_verify($currentLevel,$isAdmin)): ?>
                    <form method="post" onsubmit="return confirm('Verifikasi SEMUA aktivitas pending yang sesuai filter aktif? Tindakan ini berlaku untuk seluruh halaman, bukan hanya halaman yang sedang tampil.');">
                        <input type="hidden" name="action" value="verify_all_filtered">
                        <input type="hidden" name="verify_month" value="<?= (int)$month ?>">
                        <input type="hidden" name="verify_year" value="<?= (int)$year ?>">
                        <input type="hidden" name="verify_unit_id" value="<?= (int)$filterUnit ?>">
                        <input type="hidden" name="verify_user_id" value="<?= (int)$filterUser ?>">
                        <input type="hidden" name="verify_date" value="<?= e($vFilterDate) ?>">
                        <input type="hidden" name="verifier_note" value="Verifikasi semua sesuai filter aktif">
                        <button type="submit" class="lbk-btn bg-emerald-600 hover:bg-emerald-700 text-white px-4 py-3 shadow-sm">
                            <i class="fas fa-check-double"></i>
                            Verifikasi Semua
                        </button>
                        <div class="text-[11px] text-slate-400 mt-1 text-center">Seluruh halaman terfilter</div>
                    </form>
                <?php endif; ?>
                <div class="rounded-2xl bg-amber-50 border border-amber-200 px-4 py-2 text-center">
                    <div class="text-2xl font-black text-amber-700"><?= count($groupsPending) ?></div>
                    <div class="text-xs font-bold text-amber-600">Belum Verif</div>
                </div>
                <div class="rounded-2xl bg-emerald-50 border border-emerald-200 px-4 py-2 text-center">
                    <div class="text-2xl font-black text-emerald-700"><?= count($groupsDone) ?></div>
                    <div class="text-xs font-bold text-emerald-600">Sudah Verif</div>
                </div>
            </div>
        </div>

        <!-- Filter tanggal -->
        <form method="get" class="flex flex-wrap gap-3 items-end">
            <input type="hidden" name="module"  value="logbook_kpi">
            <input type="hidden" name="tab"     value="verifikasi">
            <input type="hidden" name="month"   value="<?= $month ?>">
            <input type="hidden" name="year"    value="<?= $year ?>">
            <input type="hidden" name="unit_id" value="<?= $filterUnit ?>">
            <input type="hidden" name="user_id" value="<?= $filterUser ?>">
            <input type="hidden" name="v_tab"   value="<?= e($vTab) ?>">
            <input type="hidden" name="v_page"  value="1">
            <div>
                <label class="text-xs font-bold text-slate-500 uppercase block mb-1">Filter Tanggal</label>
                <select name="v_date" class="lbk-input" style="min-width:200px">
                    <option value="">— Semua Tanggal —</option>
                    <?php foreach($vDatesAvail as $d): ?>
                        <option value="<?= e($d['log_date']) ?>"
                            <?= $vFilterDate===$d['log_date']?'selected':'' ?>>
                            <?= e(date('d/m/Y', strtotime($d['log_date']))) ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>
            <button class="lbk-btn bg-slate-800 text-white">
                <i class="fas fa-filter"></i> Terapkan Filter
            </button>
            <?php if($vFilterDate !== ''): ?>
                <a href="<?= lbk_v_url(['v_date'=>'','v_page'=>1]) ?>"
                   class="lbk-btn bg-white border border-slate-200 text-slate-600">
                    <i class="fas fa-times"></i> Reset
                </a>
            <?php endif; ?>
        </form>
    </div>

    <!-- ── Sub-tab: Belum / Sudah ── -->
    <div class="flex gap-2 flex-wrap">
        <a href="<?= lbk_v_url(['v_tab'=>'pending','v_page'=>1]) ?>"
           class="lbk-tab <?= $vTab==='pending'?'active':'' ?>">
            <i class="fas fa-hourglass-half mr-1 text-amber-500"></i>
            Belum Diverifikasi
            <span class="ml-1 px-2 py-0.5 rounded-full text-xs font-black
                <?= $vTab==='pending'?'bg-white/20 text-white':'bg-amber-100 text-amber-700' ?>">
                <?= count($groupsPending) ?>
            </span>
        </a>
        <a href="<?= lbk_v_url(['v_tab'=>'done','v_page'=>1]) ?>"
           class="lbk-tab <?= $vTab==='done'?'active':'' ?>">
            <i class="fas fa-check-circle mr-1 text-emerald-500"></i>
            Sudah Diverifikasi
            <span class="ml-1 px-2 py-0.5 rounded-full text-xs font-black
                <?= $vTab==='done'?'bg-white/20 text-white':'bg-emerald-100 text-emerald-700' ?>">
                <?= count($groupsDone) ?>
            </span>
        </a>
    </div>

    <!-- ── Tabel ── -->
    <div class="lbk-card p-5 overflow-x-auto">

        <?php if(empty($paged['items'])): ?>
            <div class="text-center py-16 text-slate-400">
                <i class="fas fa-inbox text-4xl mb-3 block"></i>
                <div class="font-bold text-lg">
                    <?= $vTab==='pending' ? 'Tidak ada logbook yang menunggu verifikasi' : 'Belum ada logbook yang terverifikasi' ?>
                </div>
                <div class="text-sm mt-1">
                    <?= $vFilterDate!=='' ? 'untuk tanggal '.date('d/m/Y',strtotime($vFilterDate)) : 'pada periode '.date('F Y',strtotime($start)) ?>
                </div>
            </div>
        <?php else: ?>

            <!-- Info paginasi -->
            <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 mb-4">
                <div class="text-sm text-slate-500 font-bold">
                    Menampilkan grup <?= (($paged['page']-1)*$vPageSize)+1 ?>–<?= min($paged['page']*$vPageSize, $paged['total']) ?>
                    dari <?= $paged['total'] ?> grup
                    <?= $vFilterDate!==''?'· tanggal '.date('d/m/Y',strtotime($vFilterDate)):'' ?>
                </div>
                <!-- Paginasi atas -->
                <?php if($paged['total_page']>1): ?>
                <div class="flex gap-1 flex-wrap">
                    <?php if($paged['page']>1): ?>
                        <a href="<?= lbk_v_url(['v_page'=>$paged['page']-1]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-chevron-left"></i>
                        </a>
                    <?php endif; ?>
                    <?php
                    $pStart = max(1, $paged['page']-2);
                    $pEnd   = min($paged['total_page'], $paged['page']+2);
                    for($pi=$pStart;$pi<=$pEnd;$pi++):
                    ?>
                        <a href="<?= lbk_v_url(['v_page'=>$pi]) ?>"
                           class="lbk-btn text-xs px-3 py-2 <?= $pi===$paged['page']?'bg-slate-900 text-white':'bg-white border border-slate-200 text-slate-700' ?>">
                            <?= $pi ?>
                        </a>
                    <?php endfor; ?>
                    <?php if($paged['page']<$paged['total_page']): ?>
                        <a href="<?= lbk_v_url(['v_page'=>$paged['page']+1]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-chevron-right"></i>
                        </a>
                    <?php endif; ?>
                </div>
                <?php endif; ?>
            </div>

            <table class="w-full lbk-table">
                <thead>
                    <tr>
                        <th>Tanggal</th>
                        <th>Staf / Unit</th>
                        <th>Ringkasan</th>
                        <th>Skor</th>
                        <th>Status</th>
                        <?php if($vTab==='pending' && lbk_can_verify($currentLevel,$isAdmin)): ?>
                            <th>Aksi Verifikasi</th>
                        <?php else: ?>
                            <th>Info Verifikasi</th>
                        <?php endif; ?>
                    </tr>
                </thead>
                <tbody>
                <?php foreach($paged['items'] as $g):
                    $detailId   = 'vg_'.substr(md5($g['log_date'].'|'.$g['user_id'].'|'.$g['shift']),0,10);
                    $groupStatus= $g['verified']===$g['total']?'verified':($g['rejected']>0?'rejected':'submitted');
                    $achGroup   = $g['ideal_score']>0?($g['kpi_score']/$g['ideal_score']*100):0;
                    $lastVerifier = '';
                    foreach(array_reverse($g['rows']) as $rv){
                        if($rv['verified_by_name']){ $lastVerifier=(string)$rv['verified_by_name']; break; }
                    }
                ?>
                    <!-- Baris ringkasan -->
                    <tr class="<?= $vTab==='pending'?'bg-amber-50/30':'' ?>">
                        <td class="font-bold">
                            <?= e(date('d/m/Y',strtotime($g['log_date']))) ?>
                            <div class="text-xs text-slate-400"><?= e($g['shift']) ?></div>
                        </td>
                        <td>
                            <button type="button"
                                    class="text-left font-black text-blue-700 hover:text-blue-900 transition"
                                    onclick="toggleVerifDetail('<?= e($detailId) ?>', this)">
                                <i class="fas fa-chevron-right mr-1 text-xs transition-transform" id="icon_<?= e($detailId) ?>"></i>
                                <?= e($g['employee_name']) ?>
                            </button>
                            <div class="text-xs text-slate-400 mt-1">
                                <?= e($g['unit_name']) ?> — <?= e(lbk_level_label($g['role_level'])) ?>
                            </div>
                        </td>
                        <td>
                            <div class="font-bold"><?= (int)$g['total'] ?> aktivitas</div>
                            <div class="text-xs text-slate-500"><?= number_format($g['minutes']/60,1) ?> jam tercatat</div>
                            <div class="text-xs text-slate-500">Capaian <?= number_format($achGroup,1) ?>%</div>
                        </td>
                        <td class="font-black">
                            KPI <?= number_format($g['kpi_score'],1) ?>
                            <div class="text-xs text-slate-500">
                                Real <?= number_format($g['real_score'],1) ?> / Ideal <?= number_format($g['ideal_score'],1) ?>
                            </div>
                            <?php if($g['overload_score']>0): ?>
                                <div class="text-xs text-orange-600">Overload <?= number_format($g['overload_score'],1) ?></div>
                            <?php endif; ?>
                        </td>
                        <td>
                            <span class="px-2 py-1 rounded-full border text-xs font-black <?= lbk_status_badge($groupStatus) ?>">
                                <?= e($groupStatus) ?>
                            </span>
                            <div class="text-xs text-slate-500 mt-1">
                                <?= (int)$g['verified'] ?> verified
                                <?php if($g['submitted']>0): ?>, <span class="text-amber-600 font-bold"><?= (int)$g['submitted'] ?> pending</span><?php endif; ?>
                                <?php if($g['rejected']>0): ?>, <span class="text-rose-600 font-bold"><?= (int)$g['rejected'] ?> ditolak</span><?php endif; ?>
                            </div>
                            <?php if($lastVerifier): ?>
                                <div class="text-xs text-slate-400 mt-1">oleh <?= e($lastVerifier) ?></div>
                            <?php endif; ?>
                        </td>
                        <td>
                            <?php if($vTab==='pending' && lbk_can_verify($currentLevel,$isAdmin)): ?>
                                <form method="post" class="space-y-2 min-w-[240px]">
                                    <input type="hidden" name="action" value="bulk_verify">
                                    <?php foreach($g['ids'] as $gid): ?>
                                        <input type="hidden" name="entry_ids[]" value="<?= (int)$gid ?>">
                                    <?php endforeach; ?>
                                    <input name="verifier_note" class="lbk-input text-sm"
                                           placeholder="Catatan verifikator (opsional)">
                                    <div class="flex gap-2">
                                        <button name="status" value="verified"
                                                class="lbk-btn bg-emerald-600 text-white text-xs px-3 py-2">
                                            <i class="fas fa-check"></i> Setujui Semua
                                        </button>
                                        <button name="status" value="rejected"
                                                class="lbk-btn bg-rose-600 text-white text-xs px-3 py-2">
                                            <i class="fas fa-times"></i> Tolak
                                        </button>
                                    </div>
                                </form>
                            <?php else: ?>
                                <!-- Sudah verif: tampilkan info saja -->
                                <?php
                                $lastVerifiedAt = '';
                                foreach(array_reverse($g['rows']) as $rv){
                                    if($rv['verified_at']){
                                        $lastVerifiedAt = date('d/m/Y H:i', strtotime($rv['verified_at']));
                                        break;
                                    }
                                }
                                ?>
                                <div class="text-xs text-emerald-700 font-bold">
                                    <i class="fas fa-check-circle mr-1"></i> Terverifikasi
                                </div>
                                <?php if($lastVerifiedAt): ?>
                                    <div class="text-xs text-slate-400 mt-1"><?= e($lastVerifiedAt) ?></div>
                                <?php endif; ?>
                            <?php endif; ?>
                        </td>
                    </tr>

                    <!-- Baris detail (tersembunyi) -->
                    <tr id="<?= e($detailId) ?>" class="hidden">
                        <td colspan="6" class="p-0">
                            <div class="p-4 border-l-4 <?= $vTab==='pending'?'border-amber-400':'border-emerald-400' ?> bg-slate-50">
                                <div class="font-black text-slate-700 mb-3">
                                    Detail aktivitas <?= e($g['employee_name']) ?>
                                    — <?= e(date('d/m/Y',strtotime($g['log_date']))) ?> <?= e($g['shift']) ?>
                                </div>
                                <div class="overflow-x-auto">
                                    <table class="w-full lbk-table bg-white rounded-2xl overflow-hidden">
                                        <thead>
                                            <tr>
                                                <th>Aktivitas</th>
                                                <th>Real/Ideal</th>
                                                <th>Skor</th>
                                                <th>Durasi</th>
                                                <th>Jam · Kamar</th>
                                                <th>Status</th>
                                                <th>Catatan / Bukti</th>
                                                <?php if($vTab==='pending' && lbk_can_verify($currentLevel,$isAdmin)): ?>
                                                    <th>Aksi Item</th>
                                                <?php endif; ?>
                                            </tr>
                                        </thead>
                                        <tbody>
                                        <?php foreach($g['rows'] as $r):
                                            $scoreR = min((float)$r['real_count'],(float)$r['ideal_count'])*(float)$r['weight'];
                                            $overR  = max(((float)$r['real_count']-(float)$r['ideal_count']),0)*(float)$r['weight'];
                                        ?>
                                            <tr class="<?= $r['status']==='verified'?'bg-emerald-50/40':($r['status']==='rejected'?'bg-rose-50/40':'') ?>">
                                                <td>
                                                    <?= e($r['activity_name']) ?>
                                                    <div class="text-xs text-slate-400"><?= e($r['category_code'].' · '.$r['kpi_domain']) ?></div>
                                                </td>
                                                <td><?= number_format((float)$r['real_count'],1) ?> / <?= number_format((float)$r['ideal_count'],1) ?></td>
                                                <td class="font-black">
                                                    <?= number_format($scoreR,1) ?>
                                                    <?php if($overR>0): ?><div class="text-xs text-orange-600">+<?= number_format($overR,1) ?></div><?php endif; ?>
                                                </td>
                                                <td>
                                                    <?= (int)$r['duration_minutes'] ?> mnt
                                                    <?php if((int)$r['patients_count']>0): ?>
                                                        <div class="text-xs text-slate-400"><?= (int)$r['patients_count'] ?> pasien</div>
                                                    <?php endif; ?>
                                                </td>
                                                <td>
                                                    <div class="text-xs font-bold text-slate-600">
                                                        <?= e(substr((string)($r['activity_time']??''),0,5)?:'-') ?>
                                                    </div>
                                                    <div class="text-xs text-slate-400"><?= e($r['patient_room']??'-') ?></div>
                                                </td>
                                                <td>
                                                    <span class="px-2 py-1 rounded-full border text-xs font-black <?= lbk_status_badge($r['status']) ?>">
                                                        <?= e($r['status']) ?>
                                                    </span>
                                                    <?php if($r['verified_by_name']): ?>
                                                        <div class="text-xs text-slate-400 mt-1">oleh <?= e($r['verified_by_name']) ?></div>
                                                    <?php endif; ?>
                                                </td>
                                                <td>
                                                    <div class="max-w-xs text-sm"><?= e($r['notes']) ?></div>
                                                    <?php if($r['evidence_note']): ?>
                                                        <div class="text-xs text-blue-600 mt-1"><?= e($r['evidence_note']) ?></div>
                                                    <?php endif; ?>
                                                </td>
                                                <?php if($vTab==='pending' && lbk_can_verify($currentLevel,$isAdmin)): ?>
                                                <td>
                                                    <form method="post" class="flex flex-col gap-2 min-w-[160px]">
                                                        <input type="hidden" name="action"   value="verify">
                                                        <input type="hidden" name="entry_id" value="<?= (int)$r['id'] ?>">
                                                        <input name="verifier_note" class="lbk-input text-xs" placeholder="Catatan">
                                                        <div class="flex gap-1">
                                                            <button name="status" value="verified"
                                                                    class="lbk-btn bg-emerald-600 text-white text-xs px-2 py-1">
                                                                <i class="fas fa-check"></i>
                                                            </button>
                                                            <button name="status" value="rejected"
                                                                    class="lbk-btn bg-rose-600 text-white text-xs px-2 py-1">
                                                                <i class="fas fa-times"></i>
                                                            </button>
                                                        </div>
                                                    </form>
                                                </td>
                                                <?php endif; ?>
                                            </tr>
                                        <?php endforeach; ?>
                                        </tbody>
                                    </table>
                                </div>
                            </div>
                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>

            <!-- Paginasi bawah -->
            <?php if($paged['total_page']>1): ?>
            <div class="flex items-center justify-between mt-5 flex-wrap gap-3">
                <div class="text-sm text-slate-500">
                    Halaman <?= $paged['page'] ?> / <?= $paged['total_page'] ?>
                </div>
                <div class="flex gap-1 flex-wrap">
                    <!-- Tombol Pertama -->
                    <?php if($paged['page']>1): ?>
                        <a href="<?= lbk_v_url(['v_page'=>1]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-angle-double-left"></i>
                        </a>
                        <a href="<?= lbk_v_url(['v_page'=>$paged['page']-1]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-chevron-left"></i>
                        </a>
                    <?php endif; ?>
                    <?php
                    $pStart = max(1, $paged['page']-2);
                    $pEnd   = min($paged['total_page'], $paged['page']+2);
                    for($pi=$pStart;$pi<=$pEnd;$pi++):
                    ?>
                        <a href="<?= lbk_v_url(['v_page'=>$pi]) ?>"
                           class="lbk-btn text-xs px-3 py-2
                               <?= $pi===$paged['page']?'bg-slate-900 text-white':'bg-white border border-slate-200 text-slate-700' ?>">
                            <?= $pi ?>
                        </a>
                    <?php endfor; ?>
                    <?php if($paged['page']<$paged['total_page']): ?>
                        <a href="<?= lbk_v_url(['v_page'=>$paged['page']+1]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-chevron-right"></i>
                        </a>
                        <a href="<?= lbk_v_url(['v_page'=>$paged['total_page']]) ?>"
                           class="lbk-btn bg-white border border-slate-200 text-slate-700 text-xs px-3 py-2">
                            <i class="fas fa-angle-double-right"></i>
                        </a>
                    <?php endif; ?>
                </div>
            </div>
            <?php endif; ?>

        <?php endif; // end empty check ?>
    </div>
</div>

<script>
/* ── Toggle detail baris verifikasi ── */
function toggleVerifDetail(id, btn) {
    var row  = document.getElementById(id);
    var icon = document.getElementById('icon_' + id);
    if (!row) return;
    var isOpen = !row.classList.contains('hidden');
    row.classList.toggle('hidden', isOpen);
    if (icon) {
        icon.style.transform = isOpen ? '' : 'rotate(90deg)';
    }
}
</script>

    <!-- ═══════════════════════════════ REKAP UNIT ══════════════════════════════ -->
    <?php elseif ($tab === 'unit'): ?>
        <div class="lbk-card p-5 overflow-x-auto"><h3 class="text-xl font-black text-slate-800 mb-1">Rekap Unit</h3><p class="text-xs text-slate-500 mb-4">Target KPI dihitung satu kali per aktivitas pada periode terpilih. Input berulang menambah realisasi dan tidak lagi menambah target.</p><table class="w-full lbk-table"><thead><tr><th>Unit</th><th>Staf</th><th>Aktivitas</th><th>Skor KPI Tercapai</th><th>Skor Aktual</th><th>Overload</th><th>Target KPI</th><th>Ideal Bulanan/Staf</th><th>Efektivitas</th><th>Beban Harian</th><th>KPI Adjusted</th><th>Durasi</th></tr></thead><tbody><?php foreach($unitRows as $r): $ach=(float)$r['ideal_score']>0?((float)$r['real_score']/(float)$r['ideal_score']*100):0; $uk=(string)($r['unit_key']??lbk_workload_unit_key((string)$r['unit_name'])); $mw=$monthlyWorkloadMap[$uk]??null; $monthlyIdealStaff=(float)($mw['ideal_staff_activities']??0); $unitEff=$monthlyIdealStaff>0?((float)$r['total_entries']/max(1,(float)$r['staff_count'])/$monthlyIdealStaff*100):0; $wm=$workloadMap[$uk]??null; $mul=$wm?(float)($wm['multiplier_calc']??1):1; $baseForAdj=$monthlyIdealStaff>0?$unitEff:$ach; $adj=min(150,$baseForAdj*$mul); [$wl,$m0,$wcls]=$wm?[($wm['level_calc']??'Belum Diisi'),$mul,($wm['class_calc']??'text-slate-600 bg-slate-50 border-slate-200')]:['Belum Diisi',1,'text-slate-600 bg-slate-50 border-slate-200']; ?><tr><td class="font-black"><?= e(lbk_workload_unit_label($uk)) ?><div class="text-xs text-slate-400"><?= e($r['unit_name']) ?></div></td><td><?= (int)$r['staff_count'] ?></td><td><?= (int)$r['total_entries'] ?></td><td><?= number_format((float)$r['real_score'],1) ?></td><td><?= number_format((float)($r['workload_score']??0),1) ?></td><td class="text-orange-600 font-bold"><?= number_format((float)($r['overload_score']??0),1) ?></td><td><?= number_format((float)$r['ideal_score'],1) ?></td><td><?= $mw?number_format($monthlyIdealStaff,1).' keg/staf':'<span class="text-slate-400">Belum diisi</span>' ?></td><td class="font-black"><?= $mw?number_format($unitEff,1).'%':'-' ?></td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $wcls ?>"><?= e($wl) ?> x<?= number_format($mul,2) ?></span><?php if($wm): ?><div class="text-xs text-slate-400 mt-1">Occ <?= number_format((float)$wm['avg_occupancy'],1) ?>% | <?= (int)$wm['filled_days'] ?> hari</div><?php endif; ?></td><td class="font-black text-blue-700"><?= number_format($adj,1) ?>%</td><td><?= number_format(((int)$r['minutes'])/60,1) ?> jam</td></tr><?php endforeach; ?></tbody></table></div>

    <!-- ═══════════════════════════════ REKAP STAF ══════════════════════════════ -->
    <?php elseif ($tab === 'staf'): ?>
        <div class="lbk-card p-5 overflow-x-auto">
        <div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3 mb-4 no-print">
            <h3 class="text-xl font-black text-slate-800">Rekap Staf + KPI + Produktivitas/Gaji</h3>
            <a href="<?= 'index.php?module=logbook_kpi&tab=export_laporan&month='.$month.'&year='.$year.'&unit_id='.$filterUnit ?>"
               class="lbk-btn text-white" style="background:#0F766E" target="_blank">
                <i class="fas fa-file-excel"></i> Export Laporan Lengkap (4 Sheet)
            </a>
        </div><table class="w-full lbk-table"><thead><tr><th>Staf</th><th>Role/Unit</th><th>Aktivitas</th><th>Skor KPI Tercapai</th><th>Skor Aktual</th><th>Overload</th><th>Target KPI</th><th>Ideal Beban</th><th>Efektivitas</th><th>Beban/Status</th><th>KPI Adjusted</th><th>KPI</th><th>Gaji</th><th>Skor/Rp1Jt</th><th>Aksi</th></tr></thead><tbody><?php foreach($personRows as $r): $ach=(float)$r['ideal_score']>0?((float)$r['real_score']/(float)$r['ideal_score']*100):0; $usesAdj=lbk_role_uses_workload_adjustment((string)$r['role_level']); $uk=lbk_workload_unit_key((string)$r['unit_name']); $mw=$usesAdj?($monthlyWorkloadMap[$uk]??null):null; $monthlyIdealStaff=(float)($mw['ideal_staff_activities']??0); $monthlyEff=$monthlyIdealStaff>0?((int)$r['total_entries']/$monthlyIdealStaff*100):0; $wm=$usesAdj?($workloadMap[$uk]??null):null; $mul=$wm?(float)($wm['multiplier_calc']??1):1; $baseAch=($usesAdj&&$monthlyIdealStaff>0)?$monthlyEff:$ach; $adjAch=$usesAdj?min(150,$baseAch*$mul):min(100,$ach); $vr=(int)$r['total_entries']>0?((int)$r['verified_count']/(int)$r['total_entries']*100):0; $ks=min(100,($adjAch*.55)+($vr*.25)+20); [$lab,$cls]=lbk_kpi_category($ks); if(!$usesAdj){[$wl,$m0,$wcls]=['Manajemen',1,'text-indigo-700 bg-indigo-50 border-indigo-200'];}else{[$wl,$m0,$wcls]=$wm?[($wm['level_calc']??'Belum Diisi'),$mul,($wm['class_calc']??'text-slate-600 bg-slate-50 border-slate-200')]:['Belum Diisi',1,'text-slate-600 bg-slate-50 border-slate-200'];} $salary=(float)$r['salary_amount']; $prod=$salary>0?(float)$r['real_score']/($salary/1000000):0; ?><tr><td class="font-black"><?= e($r['employee_name']) ?></td><td><?= e(lbk_level_label($r['role_level'])) ?><div class="text-xs text-slate-400"><?= e($r['unit_name']) ?></div></td><td><?= (int)$r['total_entries'] ?></td><td><?= number_format((float)$r['real_score'],1) ?></td><td><?= number_format((float)($r['workload_score']??0),1) ?></td><td class="text-orange-600 font-bold"><?= number_format((float)($r['overload_score']??0),1) ?></td><td><?= number_format((float)$r['ideal_score'],1) ?></td><td><?= $mw?number_format($monthlyIdealStaff,1).' keg/staf':($usesAdj?'<span class="text-slate-400">Belum diisi</span>':'-') ?></td><td class="font-black"><?= $mw?number_format($monthlyEff,1).'%':($usesAdj?'-':'Manajemen') ?></td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $wcls ?>"><?= e($wl) ?> x<?= number_format($mul,2) ?></span></td><td class="font-black text-blue-700"><?= number_format($adjAch,1) ?>%</td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $cls ?>"><?= number_format($ks,1).' - '.e($lab) ?></span></td><td><?= $salary>0?'Rp '.number_format($salary,0,',','.'):'-' ?></td><td><?= $prod>0?number_format($prod,1):'-' ?></td><td><a class="lbk-btn bg-blue-600 text-white text-xs px-3 py-2 whitespace-nowrap" href="index.php?module=logbook_kpi&tab=staffactivity&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= (int)$r['user_id'] ?>&employee_id=<?= (int)($r['employee_id'] ?? 0) ?>"><i class="fas fa-list-check"></i> Lihat Kegiatan</a></td></tr><?php endforeach; ?></tbody></table></div>


    <!-- ═══════════════════════════ KEGIATAN PER STAF ═══════════════════════════ -->
    <?php elseif ($tab === 'staffactivity'): ?>
        <div class="lbk-card p-5">
            <div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 mb-5">
                <div>
                    <h3 class="text-xl font-black text-slate-800">Rekap Kegiatan Bulanan per Staf</h3>
                    <p class="text-sm text-slate-500 mt-1">Menampilkan jenis kegiatan, jumlah realisasi, pasien, durasi, dan status verifikasi selama bulan yang dipilih.</p>
                </div>
                <div class="flex flex-wrap gap-2 no-print">
                    <a href="index.php?module=logbook_kpi&tab=staf&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&employee_id=<?= $filterEmployee ?>" class="lbk-btn bg-slate-100 text-slate-700"><i class="fas fa-arrow-left"></i> Kembali</a>
                    <button type="button" onclick="exportStaffActivityExcel()" class="lbk-btn bg-emerald-600 text-white"><i class="fas fa-file-excel"></i> Export Excel</button>
                    <a href="<?= 'index.php?module=logbook_kpi&tab=export_laporan&month='.$month.'&year='.$year.'&unit_id='.$filterUnit.'&user_id='.$filterUser.'&employee_id='.$filterEmployee ?>"
                       class="lbk-btn text-white no-print" style="background:#0F766E" target="_blank">
                        <i class="fas fa-file-excel"></i> Export Laporan Lengkap (4 Sheet)
                    </a>
                </div>
            </div>

            <div class="grid grid-cols-1 md:grid-cols-3 gap-3 mb-5">
                <div class="rounded-2xl border border-blue-100 bg-blue-50 p-4"><div class="text-xs font-black uppercase text-blue-500">Periode</div><div class="font-black text-blue-900 mt-1"><?= e(date('F Y', strtotime($start))) ?></div></div>
                <div class="rounded-2xl border border-violet-100 bg-violet-50 p-4"><div class="text-xs font-black uppercase text-violet-500">Staf</div><div class="font-black text-violet-900 mt-1"><?= e($selectedStaffName) ?></div></div>
                <div class="rounded-2xl border border-emerald-100 bg-emerald-50 p-4"><div class="text-xs font-black uppercase text-emerald-500">Total Jenis Kegiatan</div><div class="font-black text-emerald-900 mt-1"><?= number_format(count($staffActivityRows)) ?></div></div>
            </div>

            <?php if ($filterUser <= 0 && $filterEmployee <= 0): ?>
                <div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-amber-800 font-bold mb-5"><i class="fas fa-circle-info mr-2"></i>Pilih satu staf pada filter di atas agar rekap bulanan lebih spesifik, atau klik tombol <b>Lihat Kegiatan</b> pada tab Rekap Staf.</div>
            <?php endif; ?>

            <div class="overflow-x-auto">
                <table id="staffActivityTable" class="w-full lbk-table">
                    <thead><tr><th>No</th><?php if($filterUser<=0 && $filterEmployee<=0): ?><th>Staf/Unit</th><?php endif; ?><th>Kegiatan</th><th>Domain KPI</th><th>Total Dikerjakan</th><th>Entri</th><th>Pasien</th><th>Durasi</th><th>Terverifikasi</th><th>Rentang Tanggal</th></tr></thead>
                    <tbody>
                    <?php if(!$staffActivityRows): ?>
                        <tr><td colspan="10" class="text-center text-slate-400 py-8">Belum ada data kegiatan pada staf atau periode yang dipilih.</td></tr>
                    <?php else: foreach($staffActivityRows as $idx=>$r): $vp=(int)$r['entry_count']>0?((int)$r['verified_count']/(int)$r['entry_count']*100):0; ?>
                        <tr>
                            <td><?= $idx+1 ?></td>
                            <?php if($filterUser<=0 && $filterEmployee<=0): ?><td class="font-bold"><?= e($r['employee_name']) ?><div class="text-xs text-slate-400"><?= e($r['unit_name']) ?></div></td><?php endif; ?>
                            <td class="font-black text-slate-800"><?= e($r['activity_name']) ?><div class="text-xs text-slate-400">Kategori <?= e($r['category_code']) ?></div></td>
                            <td><?= e(ucwords(str_replace('_',' ',(string)$r['kpi_domain']))) ?></td>
                            <td class="font-black text-blue-700"><?= number_format((float)$r['total_real'],1) ?></td>
                            <td><?= number_format((int)$r['entry_count']) ?></td>
                            <td><?= number_format((int)$r['total_patients']) ?></td>
                            <td><?= number_format(((int)$r['total_minutes'])/60,1) ?> jam</td>
                            <td><?= number_format($vp,1) ?>%</td>
                            <td><?= e(date('d/m/Y',strtotime($r['first_date']))) ?> – <?= e(date('d/m/Y',strtotime($r['last_date']))) ?></td>
                        </tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table>
            </div>
        </div>
        <script>
        function exportStaffActivityExcel(){
            const table=document.getElementById('staffActivityTable');
            if(!table) return;
            const html=`<html><head><meta charset="UTF-8"></head><body><h2>Rekap Kegiatan Bulanan per Staf</h2><p>Periode: <?= e(date('F Y', strtotime($start))) ?><br>Staf: <?= e($selectedStaffName) ?></p>${table.outerHTML}
<script>
(function(){
    const form=document.getElementById('formLogbook');
    const shift=document.getElementById('inputShift');
    const date=document.getElementById('inputLogDate');
    const duration=document.getElementById('inputDurationMinutes');
    const label=document.getElementById('shiftPolicyLabel');
    const used=document.getElementById('shiftUsed');
    const remaining=document.getElementById('shiftRemaining');
    const progress=document.getElementById('shiftProgress');
    const warning=document.getElementById('shiftWarning');
    if(!form||!shift||!duration)return;

    const policies={
        'Pagi':{max:420,label:'Maksimal 7 jam kegiatan + 1 jam istirahat'},
        'Sore':{max:420,label:'Maksimal 7 jam kegiatan + 1 jam istirahat'},
        'Malam':{max:720,label:'Maksimal 12 jam kegiatan + 1 jam istirahat'}
    };
    let baseUsed=parseInt(form.dataset.usedMinutes||'0',10)||0;

    function refresh(){
        const p=policies[shift.value]||{max:0,label:'Shift ini tidak memiliki batas khusus'};
        const entered=Math.max(0,parseInt(duration.value||'0',10)||0);
        const total=baseUsed+entered;
        const remain=p.max>0?Math.max(0,p.max-baseUsed):0;
        label.textContent=p.label;
        used.textContent=String(baseUsed);
        remaining.textContent=p.max>0?String(remain):'-';
        progress.style.width=p.max>0?Math.min(100,(total/p.max)*100)+'%':'0%';

        if(p.max>0 && total>p.max){
            warning.classList.remove('hidden');
            warning.textContent='Durasi melebihi batas shift '+(total-p.max)+' menit. Maksimal tambahan '+remain+' menit.';
            duration.setCustomValidity('Total durasi kegiatan melebihi batas shift.');
            progress.classList.remove('bg-blue-600');
            progress.classList.add('bg-rose-600');
        }else{
            warning.classList.add('hidden');
            warning.textContent='';
            duration.setCustomValidity('');
            progress.classList.remove('bg-rose-600');
            progress.classList.add('bg-blue-600');
        }
    }
    duration.addEventListener('input',refresh);
    shift.addEventListener('change',()=>{baseUsed=0;refresh();});
    if(date)date.addEventListener('change',()=>{baseUsed=0;refresh();});
    form.addEventListener('submit',function(e){refresh();if(!duration.checkValidity()){e.preventDefault();duration.reportValidity();}});
    refresh();
})();
</script>

</body></html>`;
            const blob=new Blob(['\ufeff',html],{type:'application/vnd.ms-excel;charset=utf-8;'});
            const a=document.createElement('a'); a.href=URL.createObjectURL(blob);
            a.download='rekap_kegiatan_<?= preg_replace('/[^A-Za-z0-9_-]+/','_',strtolower($selectedStaffName)) ?>_<?= $year ?>_<?= str_pad((string)$month,2,'0',STR_PAD_LEFT) ?>.xls';
            document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(a.href),1000);
        }
        </script>

    <!-- ═══════════════════════════════ RANKING KEGIATAN ═══════════════════════ -->
    <?php elseif ($tab === 'ranking'): ?>
        <div class="lbk-card p-5">
            <div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 mb-5">
                <div>
                    <h3 class="text-xl font-black text-slate-800">10 Kegiatan Paling Banyak Dikerjakan</h3>
                    <p class="text-sm text-slate-500 mt-1">Ranking dihitung dari total <b>Real Count</b>, sehingga satu aktivitas untuk 3 kamar dihitung sebagai 3 kegiatan. Filter bulan, tahun, unit, dan staf mengikuti filter utama di atas.</p>
                </div>
                <button type="button" onclick="exportRankingExcel()" class="no-print lbk-btn bg-emerald-600 text-white justify-center">
                    <i class="fas fa-file-excel"></i> Export Excel
                </button>
            </div>

            <div class="grid grid-cols-1 md:grid-cols-3 gap-3 mb-5">
                <div class="rounded-2xl border border-blue-100 bg-blue-50 p-4">
                    <div class="text-xs font-black uppercase text-blue-500">Periode</div>
                    <div class="font-black text-blue-900 mt-1"><?= e(date('F Y', strtotime($start))) ?></div>
                </div>
                <div class="rounded-2xl border border-violet-100 bg-violet-50 p-4">
                    <div class="text-xs font-black uppercase text-violet-500">Filter Unit</div>
                    <div class="font-black text-violet-900 mt-1"><?php $fu='Semua Unit'; foreach($units as $uu){if((int)$uu['id']===$filterUnit){$fu=(string)$uu['name'];break;}} echo e($fu); ?></div>
                </div>
                <div class="rounded-2xl border border-emerald-100 bg-emerald-50 p-4">
                    <div class="text-xs font-black uppercase text-emerald-500">Filter Staf</div>
                    <div class="font-black text-emerald-900 mt-1"><?php $fs='Semua Staf'; foreach($users as $uu){if((int)$uu['user_id']===$filterUser){$fs=(string)$uu['name'];break;}} echo e($fs); ?></div>
                </div>
            </div>

            <div class="overflow-x-auto">
                <table id="rankingKegiatanTable" class="w-full lbk-table">
                    <thead><tr><th>Ranking</th><th>Kegiatan</th><th>Domain</th><th>Total Dikerjakan</th><th>Entri Log</th><th>Staf Pelaksana</th><th>Jumlah Pasien</th><th>Durasi</th><th>Verifikasi</th><th>Rekomendasi Pelatihan</th></tr></thead>
                    <tbody>
                    <?php if(!$rankingRows): ?>
                        <tr><td colspan="10" class="text-center text-slate-400 py-8">Belum ada data kegiatan pada filter/periode ini.</td></tr>
                    <?php else: foreach($rankingRows as $idx=>$r):
                        $rank=$idx+1;
                        $totalReal=(float)($r['total_real']??0);
                        $share=$rankingGrandTotal>0?($totalReal/$rankingGrandTotal*100):0;
                        $verifyPct=(int)($r['entry_count']??0)>0?((int)($r['verified_count']??0)/(int)$r['entry_count']*100):0;
                        $training = $rank<=3 ? 'Prioritas refreshment/SOP dan audit kompetensi' : ($rank<=6 ? 'Masukkan dalam pelatihan berkala unit' : 'Monitoring dan microlearning');
                    ?>
                        <tr>
                            <td><span class="inline-flex w-9 h-9 rounded-full items-center justify-center font-black <?= $rank<=3?'bg-amber-100 text-amber-700':'bg-slate-100 text-slate-700' ?>"><?= $rank ?></span></td>
                            <td class="font-black text-slate-800"><?= e($r['activity_name']) ?><div class="text-xs text-slate-400 mt-1">Kategori <?= e($r['category_code']) ?> · <?= number_format($share,1) ?>% dari Top 10</div></td>
                            <td><?= e(ucwords(str_replace('_',' ',(string)$r['kpi_domain']))) ?></td>
                            <td class="font-black text-blue-700"><?= number_format($totalReal,1) ?></td>
                            <td><?= number_format((int)$r['entry_count']) ?></td>
                            <td><?= number_format((int)$r['staff_count']) ?></td>
                            <td><?= number_format((int)$r['total_patients']) ?></td>
                            <td><?= number_format(((int)$r['total_minutes'])/60,1) ?> jam</td>
                            <td><?= number_format($verifyPct,1) ?>%</td>
                            <td><span class="text-xs font-bold <?= $rank<=3?'text-rose-700':'text-slate-600' ?>"><?= e($training) ?></span></td>
                        </tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table>
            </div>
            <div class="mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900">
                <b>Interpretasi:</b> kegiatan dengan frekuensi tinggi menjadi prioritas untuk standardisasi praktik, refreshment SOP, simulasi, audit keterampilan, dan evaluasi kepatuhan. Ranking menunjukkan volume kerja, bukan otomatis menunjukkan ketidakmampuan staf.
            </div>
        </div>
        <script>
        function exportRankingExcel(){
            const table=document.getElementById('rankingKegiatanTable');
            if(!table) return;
            const title='Ranking 10 Kegiatan Terbanyak - <?= e(date('F Y', strtotime($start))) ?>';
            const unit='<?= e($fu ?? 'Semua Unit') ?>';
            const staf='<?= e($fs ?? 'Semua Staf') ?>';
            const html=`<html><head><meta charset="UTF-8"></head><body><h2>${title}</h2><p>Unit: ${unit}<br>Staf: ${staf}</p>${table.outerHTML}</body></html>`;
            const blob=new Blob(['\ufeff',html],{type:'application/vnd.ms-excel;charset=utf-8;'});
            const a=document.createElement('a');
            a.href=URL.createObjectURL(blob);
            a.download='ranking_10_kegiatan_<?= $year ?>_<?= str_pad((string)$month,2,'0',STR_PAD_LEFT) ?>.xls';
            document.body.appendChild(a); a.click(); a.remove();
            setTimeout(()=>URL.revokeObjectURL(a.href),1000);
        }
        </script>

    <!-- ═══════════════════════════════ BEBAN UNIT ══════════════════════════════ -->
    <?php elseif ($tab === 'beban'): ?>
        <div class="grid grid-cols-1 xl:grid-cols-3 gap-5">
            <form method="post" class="xl:col-span-3 lbk-card p-5 space-y-4">
                <input type="hidden" name="action" value="save_monthly_workload">
                <h3 class="text-xl font-black text-slate-800">Input Standar Beban Bulanan Unit</h3>
                <p class="text-sm text-slate-500">Diisi kepala unit di awal bulan. Rumus: (Mandiri × standar) + (Partial × standar) + (Total Care × standar), lalu dibagi total staf.</p>
                <?php if(!$canManageWorkload): ?><div class="rounded-2xl bg-amber-50 border border-amber-200 text-amber-700 p-3 text-sm font-bold">Mode baca saja.</div><?php endif; ?>
                <div class="grid grid-cols-1 md:grid-cols-4 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Bulan</label><select name="mw_month" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>><?php for($m=1;$m<=12;$m++): ?><option value="<?= $m ?>" <?= $m===$month?'selected':'' ?>><?= date('F',mktime(0,0,0,$m,1)) ?></option><?php endfor; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Tahun</label><input type="number" name="mw_year" value="<?= $year ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Unit</label><select name="mw_unit_key" class="lbk-input" onchange="const txt=this.options[this.selectedIndex].text;this.form.querySelector('[name=mw_unit_label]').value=txt;window.location.href='index.php?module=logbook_kpi&tab=beban&month=<?= $month ?>&year=<?= $year ?>&workload_date=<?= e($selectedWorkloadDate) ?>&workload_unit_key='+this.value" <?= $canManageWorkload?'':'disabled' ?>><?php foreach($workloadUnitOptions as $uk=>$ul): ?><option value="<?= e($uk) ?>" <?= $selectedWorkloadKey===$uk?'selected':'' ?>><?= e($ul) ?></option><?php endforeach; ?></select><input type="hidden" name="mw_unit_label" value="<?= e($workloadUnitOptions[$selectedWorkloadKey]??lbk_workload_unit_label($selectedWorkloadKey)) ?>"></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Total Staf Unit</label><input type="number" name="mw_total_staff" value="<?= e($monthlyWorkloadSelected['total_staff']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                </div>
                <div class="grid grid-cols-1 md:grid-cols-5 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Total Pasien Bulanan</label><input type="number" step="0.1" name="mw_total_patients" value="<?= e($monthlyWorkloadSelected['total_patients']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Pasien Mandiri</label><input type="number" step="0.1" name="mw_independent_patients" value="<?= e($monthlyWorkloadSelected['independent_patients']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Pasien Partial Care</label><input type="number" step="0.1" name="mw_partial_care_patients" value="<?= e($monthlyWorkloadSelected['partial_care_patients']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Pasien Total Care</label><input type="number" step="0.1" name="mw_total_care_patients" value="<?= e($monthlyWorkloadSelected['total_care_patients']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Bed Unit</label><input type="number" name="mw_bed_capacity" value="<?= e($monthlyWorkloadSelected['bed_capacity']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                </div>
                <div class="grid grid-cols-1 md:grid-cols-4 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Std Mandiri</label><input type="number" step="0.1" name="mw_standard_independent" value="<?= e($monthlyWorkloadSelected['standard_independent']??5) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Std Partial</label><input type="number" step="0.1" name="mw_standard_partial" value="<?= e($monthlyWorkloadSelected['standard_partial']??10) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Std Total Care</label><input type="number" step="0.1" name="mw_standard_total_care" value="<?= e($monthlyWorkloadSelected['standard_total_care']??15) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Staf/Shift Rata-rata</label><input type="number" step="0.1" name="mw_avg_staff_per_shift" value="<?= e($monthlyWorkloadSelected['avg_staff_per_shift']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                </div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Catatan</label><input name="mw_note" value="<?= e($monthlyWorkloadSelected['note']??'') ?>" class="lbk-input" placeholder="Opsional" <?= $canManageWorkload?'':'disabled' ?>></div>
                <?php if($monthlyWorkloadSelected): ?><div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-3 text-sm text-emerald-800 font-bold">Tersimpan: Ideal unit <?= number_format((float)$monthlyWorkloadSelected['ideal_unit_activities'],1) ?> keg/bulan; ideal staf <?= number_format((float)$monthlyWorkloadSelected['ideal_staff_activities'],1) ?> keg/staf/bulan.</div><?php endif; ?>
                <?php if($canManageWorkload): ?><button class="lbk-btn bg-emerald-600 text-white"><i class="fas fa-save"></i> Simpan Standar Bulanan</button><?php endif; ?>
            </form>
            <form method="post" class="lbk-card p-5 space-y-4">
                <input type="hidden" name="action" value="save_workload">
                <h3 class="text-xl font-black text-slate-800">Input Beban Unit Harian</h3>
                <p class="text-sm text-slate-500">Diisi kepala unit setiap pagi. Role manajemen (Karu–Kadiv) tidak dipengaruhi jumlah pasien/bed.</p>
                <?php if(!$canManageWorkload): ?><div class="rounded-2xl bg-amber-50 border border-amber-200 text-amber-700 p-3 text-sm font-bold">Mode baca saja.</div><?php endif; ?>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Tanggal</label><input type="date" name="workload_date" value="<?= e($selectedWorkloadDate) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Unit</label><select name="workload_unit_key" class="lbk-input" onchange="const txt=this.options[this.selectedIndex].text;this.form.querySelector('[name=workload_unit_label]').value=txt;window.location.href='index.php?module=logbook_kpi&tab=beban&month=<?= $month ?>&year=<?= $year ?>&workload_date=<?= e($selectedWorkloadDate) ?>&workload_unit_key='+this.value" <?= $canManageWorkload?'':'disabled' ?>><?php foreach($workloadUnitOptions as $uk=>$ul): ?><option value="<?= e($uk) ?>" <?= $selectedWorkloadKey===$uk?'selected':'' ?>><?= e($ul) ?></option><?php endforeach; ?></select><input type="hidden" name="workload_unit_label" value="<?= e($workloadUnitOptions[$selectedWorkloadKey]??lbk_workload_unit_label($selectedWorkloadKey)) ?>"></div>
                <div class="grid grid-cols-2 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Jumlah Pasien</label><input type="number" step="0.1" name="patient_count" value="<?= e($workloadToday['patient_count']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Jumlah Bed</label><input type="number" name="bed_capacity" value="<?= e($workloadToday['bed_capacity']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                </div>
                <div class="grid grid-cols-2 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">LOS / Hari Rawat</label><input type="number" step="0.1" name="los_count" value="<?= e($workloadToday['los_count']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Perawat/Shift</label><input type="number" name="nurses_per_shift" value="<?= e($workloadToday['nurses_per_shift']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                </div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Total Perawat Unit</label><input type="number" name="nurse_count" value="<?= e($workloadToday['nurse_count']??0) ?>" class="lbk-input" <?= $canManageWorkload?'':'disabled' ?>></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Catatan</label><input name="workload_note" value="<?= e($workloadToday['note']??'') ?>" class="lbk-input" placeholder="Opsional" <?= $canManageWorkload?'':'disabled' ?>></div>
                <?php if($workloadToday): ?><div class="rounded-2xl border border-blue-200 bg-blue-50 p-3 text-sm text-blue-800 font-bold">Data terakhir: Occ <?= number_format((float)$workloadToday['occupancy_percent'],1) ?>% – <?= e($workloadToday['workload_level']) ?> – x<?= number_format((float)$workloadToday['multiplier'],2) ?>.</div><?php endif; ?>
                <?php if($canManageWorkload): ?><button class="lbk-btn bg-blue-600 text-white"><i class="fas fa-save"></i> Simpan Beban Harian</button><?php endif; ?>
            </form>
            <div class="xl:col-span-2 lbk-card p-5 overflow-x-auto">
                <h3 class="text-xl font-black text-slate-800 mb-4">Rekap Beban Unit Bulan Ini</h3>
                <div class="mb-5"><h4 class="font-black text-slate-700 mb-2">Standar Beban Bulanan</h4><table class="w-full lbk-table"><thead><tr><th>Unit</th><th>Total Pasien</th><th>Staf</th><th>Mandiri</th><th>Partial</th><th>Total Care</th><th>Ideal Unit</th><th>Ideal/Staf</th></tr></thead><tbody><?php foreach($monthlyWorkloadRows as $mwr): ?><tr><td class="font-black"><?= e($mwr['unit_label']) ?></td><td><?= number_format((float)$mwr['total_patients'],1) ?></td><td><?= (int)$mwr['total_staff'] ?></td><td><?= number_format((float)$mwr['independent_patients'],1) ?> x <?= number_format((float)$mwr['standard_independent'],1) ?></td><td><?= number_format((float)$mwr['partial_care_patients'],1) ?> x <?= number_format((float)$mwr['standard_partial'],1) ?></td><td><?= number_format((float)$mwr['total_care_patients'],1) ?> x <?= number_format((float)$mwr['standard_total_care'],1) ?></td><td class="font-black"><?= number_format((float)$mwr['ideal_unit_activities'],1) ?></td><td class="font-black text-emerald-700"><?= number_format((float)$mwr['ideal_staff_activities'],1) ?></td></tr><?php endforeach; ?></tbody></table></div>
                <h4 class="font-black text-slate-700 mb-2">Sensus Harian</h4>
                <table class="w-full lbk-table"><thead><tr><th>Tanggal</th><th>Unit</th><th>Pasien</th><th>LOS</th><th>Bed</th><th>Occ</th><th>Perawat/Shift</th><th>Rasio</th><th>Level</th><th>Multiplier</th></tr></thead><tbody><?php foreach($workloadRowsDaily as $wr): [$lvl,$mul,$cls]=lbk_workload_level_from_occupancy((float)$wr['occupancy_percent']); ?><tr><td class="font-bold"><?= e(date('d/m/Y',strtotime($wr['workload_date']))) ?></td><td class="font-black"><?= e($wr['unit_label']) ?></td><td><?= number_format((float)$wr['patient_count'],1) ?></td><td><?= number_format((float)$wr['los_count'],1) ?></td><td><?= (int)$wr['bed_capacity'] ?></td><td class="font-black"><?= number_format((float)$wr['occupancy_percent'],1) ?>%</td><td><?= (int)$wr['nurses_per_shift'] ?></td><td><?= number_format((float)$wr['patient_per_nurse_shift'],2) ?></td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $cls ?>"><?= e($wr['workload_level']) ?></span></td><td class="font-black">x<?= number_format((float)$wr['multiplier'],2) ?></td></tr><?php endforeach; ?></tbody></table>
                <div class="mt-5 grid grid-cols-2 md:grid-cols-4 gap-3">
                    <div class="rounded-2xl bg-slate-50 border border-slate-200 p-3"><div class="font-black text-slate-700">&lt;50%</div><div class="text-xs text-slate-500">Rendah x0.90</div></div>
                    <div class="rounded-2xl bg-blue-50 border border-blue-200 p-3"><div class="font-black text-blue-700">50–69%</div><div class="text-xs text-blue-600">Sedang x1.00</div></div>
                    <div class="rounded-2xl bg-amber-50 border border-amber-200 p-3"><div class="font-black text-amber-700">70–89%</div><div class="text-xs text-amber-600">Tinggi x1.15</div></div>
                    <div class="rounded-2xl bg-rose-50 border border-rose-200 p-3"><div class="font-black text-rose-700">≥90%</div><div class="text-xs text-rose-600">Sangat Tinggi x1.30</div></div>
                </div>
            </div>
        </div>

    <!-- ═══════════════════════════════ MASTER AKTIVITAS ════════════════════════ -->

    <?php elseif ($tab === 'schedule'): ?>
        <div class="grid grid-cols-1 xl:grid-cols-3 gap-5">
            <div class="lbk-card p-5 xl:col-span-2 space-y-4">
                <div>
                    <h3 class="text-xl font-black text-slate-800">Upload Jadwal Bulanan</h3>
                    <p class="text-sm text-slate-500 mt-1">Unggah file Excel jadwal unit. Sistem akan mencocokkan nama pegawai dengan master staf dan menghitung kewajiban pengisian logbook.</p>
                </div>
                <form method="post" enctype="multipart/form-data" class="grid grid-cols-1 md:grid-cols-4 gap-3">
                    <input type="hidden" name="action" value="upload_staff_schedule">
                    <select name="schedule_unit_id" class="lbk-input" required>
                        <option value="">Pilih unit</option>
                        <?php foreach($nursingUnits as $nu): if($currentLevel==='kaunit' && (int)$nu['unit_id']!==$ownCanonicalUnitId)continue; ?>
                            <option value="<?= (int)$nu['unit_id'] ?>" <?= $scheduleUnitView===(int)$nu['unit_id']?'selected':'' ?>><?= e($nu['display_name']) ?></option>
                        <?php endforeach; ?>
                    </select>
                    <select name="schedule_month" class="lbk-input"><?php for($m=1;$m<=12;$m++): ?><option value="<?= $m ?>" <?= $scheduleMonthView===$m?'selected':'' ?>><?= e(date('F',mktime(0,0,0,$m,1))) ?></option><?php endfor; ?></select>
                    <input type="number" name="schedule_year" class="lbk-input" min="2020" max="2100" value="<?= $scheduleYearView ?>" required>
                    <input type="file" name="schedule_file" class="lbk-input" accept=".xlsx" required>
                    <div class="md:col-span-4"><button class="lbk-btn bg-emerald-600 text-white"><i class="fas fa-file-excel"></i> Upload & Proses Jadwal</button></div>
                </form>
                <div class="rounded-2xl bg-blue-50 border border-blue-200 p-4 text-sm text-blue-800">
                    Format mengikuti contoh: nama staf pada kolom nama, tanggal pada baris tanggal, dan kode jaga seperti P1, S1, M, L, atau Cuti.
                </div>
            </div>

            <div class="lbk-card p-5 space-y-3">
                <h3 class="text-lg font-black text-slate-800">Filter Rekap</h3>
                <form method="get" class="space-y-3">
                    <input type="hidden" name="module" value="logbook_kpi"><input type="hidden" name="tab" value="schedule">
                    <select name="schedule_unit" class="lbk-input"><option value="0">Semua unit</option><?php foreach($nursingUnits as $nu): ?><option value="<?= (int)$nu['unit_id'] ?>" <?= $scheduleUnitView===(int)$nu['unit_id']?'selected':'' ?>><?= e($nu['display_name']) ?></option><?php endforeach; ?></select>
                    <select name="schedule_month" class="lbk-input"><?php for($m=1;$m<=12;$m++): ?><option value="<?= $m ?>" <?= $scheduleMonthView===$m?'selected':'' ?>><?= e(date('F',mktime(0,0,0,$m,1))) ?></option><?php endfor; ?></select>
                    <input type="number" name="schedule_year" class="lbk-input" value="<?= $scheduleYearView ?>">
                    <button class="lbk-btn bg-slate-900 text-white w-full justify-center">Tampilkan Rekap</button>
                </form>
            </div>
        </div>

        <div class="lbk-card p-5 space-y-4">
            <div class="flex items-center justify-between gap-3"><div><h3 class="text-xl font-black text-slate-800">Rekap Kedisiplinan Bulanan</h3><p class="text-sm text-slate-500">Periode <?= e(date('F',mktime(0,0,0,$scheduleMonthView,1))) ?> <?= $scheduleYearView ?></p></div><div class="rounded-2xl bg-violet-50 border border-violet-200 px-4 py-2 text-violet-700 font-black"><?= count($scheduleMonthlyRows) ?> staf</div></div>
            <div class="overflow-x-auto"><table class="w-full lbk-table"><thead><tr><th>Staf</th><th>Unit</th><th>Hari Wajib</th><th>Sudah Isi</th><th>Belum Isi</th><th>Libur/Cuti</th><th>Kepatuhan</th><th>Tanggal Belum Isi</th></tr></thead><tbody>
            <?php if(!$scheduleMonthlyRows): ?><tr><td colspan="8" class="text-center text-slate-400 py-10">Belum ada jadwal untuk filter ini. Silakan upload jadwal bulanan terlebih dahulu.</td></tr>
            <?php else: foreach($scheduleMonthlyRows as $sr): $sd=(int)$sr['scheduled_days'];$fd=(int)$sr['filled_days'];$miss=max(0,$sd-$fd);$rate=$sd>0?$fd/$sd*100:0; ?>
                <tr><td class="font-black text-slate-800"><?= e($sr['employee_name']) ?></td><td><?= e($sr['unit_name']) ?></td><td><?= $sd ?></td><td class="font-black text-emerald-700"><?= $fd ?></td><td class="font-black text-rose-700"><?= $miss ?></td><td><?= (int)$sr['off_days'] ?></td><td><span class="font-black <?= $rate>=90?'text-emerald-700':($rate>=75?'text-amber-700':'text-rose-700') ?>"><?= number_format($rate,1) ?>%</span></td><td class="text-xs text-slate-500 max-w-[360px]"><?= e($sr['missing_dates'] ?: '-') ?></td></tr>
            <?php endforeach; endif; ?></tbody></table></div>
        </div>

        <?php if($unmatchedSchedules): ?>
        <div class="lbk-card p-5 space-y-4"><div><h3 class="text-xl font-black text-slate-800">Nama Jadwal Belum Cocok</h3><p class="text-sm text-slate-500">Petakan nama dari Excel ke staf pada database agar masuk perhitungan.</p></div><div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
        <?php foreach($unmatchedSchedules as $um): $emps=lbk_all($conn,"SELECT e.id,e.full_name FROM employees e LEFT JOIN logbook_kpi_unit_mapping mp ON mp.source_unit_id=e.unit_id AND mp.is_active=1 WHERE e.is_active=1 AND COALESCE(mp.canonical_unit_id,e.unit_id)=? ORDER BY e.full_name",[(int)$um['unit_id']],'i'); ?>
            <form method="post" class="rounded-2xl border border-amber-200 bg-amber-50 p-4"><input type="hidden" name="action" value="map_schedule_employee"><input type="hidden" name="schedule_name" value="<?= e($um['employee_name_excel']) ?>"><input type="hidden" name="map_unit_id" value="<?= (int)$um['unit_id'] ?>"><div class="font-black text-slate-800"><?= e($um['employee_name_excel']) ?></div><div class="text-xs text-slate-500 mb-2"><?= (int)$um['days_count'] ?> hari jadwal</div><div class="flex gap-2"><select name="map_employee_id" class="lbk-input flex-1" required><option value="">Pilih staf database</option><?php foreach($emps as $ep): ?><option value="<?= (int)$ep['id'] ?>"><?= e($ep['full_name']) ?></option><?php endforeach; ?></select><button class="lbk-btn bg-amber-600 text-white">Petakan</button></div></form>
        <?php endforeach; ?></div></div>
        <?php endif; ?>

        <div class="grid grid-cols-1 xl:grid-cols-2 gap-5">
            <div class="lbk-card p-5"><h3 class="text-xl font-black text-slate-800 mb-4">Riwayat Upload Jadwal</h3><div class="overflow-x-auto"><table class="w-full lbk-table"><thead><tr><th>Waktu</th><th>Unit</th><th>Periode</th><th>File</th><th>Cocok</th><th>Belum Cocok</th></tr></thead><tbody><?php if(!$scheduleUploads): ?><tr><td colspan="6" class="text-center text-slate-400">Belum ada upload.</td></tr><?php else: foreach($scheduleUploads as $su): ?><tr><td><?= e(date('d/m/Y H:i',strtotime($su['created_at']))) ?></td><td><?= e($su['unit_name'] ?: '-') ?></td><td><?= sprintf('%02d/%04d',(int)$su['month'],(int)$su['year']) ?></td><td><?= e($su['original_filename']) ?></td><td class="text-emerald-700 font-bold"><?= (int)$su['matched_rows'] ?></td><td class="text-rose-700 font-bold"><?= (int)$su['unmatched_rows'] ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div>
            <div class="lbk-card p-5"><h3 class="text-xl font-black text-slate-800 mb-4">Master Kode Jadwal</h3><?php if($isAdmin||in_array($currentLevel,['kadiv','kasubdiv','kasubdiv_rajal','kasubdiv_ranap'],true)): ?><form method="post" class="grid grid-cols-2 gap-2 mb-4"><input type="hidden" name="action" value="save_shift_code"><input class="lbk-input" name="shift_code" placeholder="Kode, contoh P1" required><input class="lbk-input" name="shift_name" placeholder="Nama shift" required><input class="lbk-input" type="time" name="start_time"><input class="lbk-input" type="time" name="end_time"><label class="text-sm font-bold"><input type="checkbox" name="requires_logbook" checked> Wajib logbook</label><label class="text-sm font-bold"><input type="checkbox" name="crosses_midnight"> Lintas hari</label><button class="lbk-btn bg-blue-600 text-white col-span-2 justify-center">Simpan Kode</button></form><?php endif; ?><div class="max-h-80 overflow-auto"><table class="w-full lbk-table"><thead><tr><th>Kode</th><th>Nama</th><th>Jam</th><th>Wajib</th></tr></thead><tbody><?php foreach($scheduleShiftCodes as $sc): ?><tr><td class="font-black"><?= e($sc['code']) ?></td><td><?= e($sc['shift_name']) ?></td><td><?= e(substr((string)$sc['start_time'],0,5)) ?>–<?= e(substr((string)$sc['end_time'],0,5)) ?></td><td><?= (int)$sc['requires_logbook']?'Ya':'Tidak' ?></td></tr><?php endforeach; ?></tbody></table></div></div>
        </div>

    <?php elseif ($tab === 'staffunit' && $canManageNursingStaff): ?>
        <!-- Modal Kelola Staf khusus tab Manajemen Staf Unit -->
        <div id="staffManageModal" class="fixed inset-0 z-[99999] hidden items-center justify-center bg-slate-950/60 p-4" aria-hidden="true">
            <div class="w-full max-w-xl rounded-3xl bg-white shadow-2xl" data-modal-panel>
                <div class="flex items-start justify-between border-b border-slate-100 p-5">
                    <div>
                        <h3 class="text-xl font-black text-slate-900">Kelola Staf</h3>
                        <div id="staffModalName" class="mt-1 font-bold text-slate-700"></div>
                        <div id="staffModalNik" class="text-xs text-slate-400"></div>
                    </div>
                    <button type="button" id="staffModalClose" class="h-10 w-10 rounded-full border border-slate-200 text-slate-500 hover:bg-slate-50">&times;</button>
                </div>
                <div class="space-y-5 p-5">
                    <form method="post" class="space-y-3">
                        <input type="hidden" name="action" value="move_nursing_staff">
                        <input type="hidden" name="employee_id" id="staffMoveEmployeeId">
                        <div>
                            <label class="text-xs font-black uppercase text-slate-500">Unit Keperawatan</label>
                            <select name="target_unit_id" id="staffTargetUnitId" class="lbk-input mt-1">
                                <?php foreach($nursingUnits as $nu): if($currentLevel==='kaunit' && (int)$nu['unit_id']!==$ownCanonicalUnitId)continue; ?>
                                    <option value="<?= (int)$nu['unit_id'] ?>"><?= e($nu['display_name']) ?></option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div>
                            <label class="text-xs font-black uppercase text-slate-500">Jabatan</label>
                            <input name="position_name" id="staffPositionName" class="lbk-input mt-1" placeholder="Jabatan">
                        </div>
                        <button type="submit" class="lbk-btn lbk-btn-primary w-full justify-center"><i class="fas fa-save"></i> Simpan Unit/Jabatan</button>
                    </form>
                    <div class="border-t border-slate-100 pt-5">
                        <form method="post" class="space-y-3">
                            <input type="hidden" name="action" value="set_nursing_staff_status">
                            <input type="hidden" name="employee_id" id="staffStatusEmployeeId">
                            <div>
                                <label class="text-xs font-black uppercase text-slate-500">Status Staf</label>
                                <select name="employment_status" id="staffEmploymentStatus" class="lbk-input mt-1">
                                    <option value="aktif">Aktif</option>
                                    <option value="nonaktif">Nonaktif</option>
                                    <option value="resign">Resign</option>
                                    <option value="mutasi_keluar">Mutasi Keluar</option>
                                </select>
                            </div>
                            <button type="submit" class="lbk-btn w-full justify-center border border-slate-200 bg-white text-slate-700"><i class="fas fa-user-edit"></i> Ubah Status</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <script>
        (function () {
            function byId(id) { return document.getElementById(id); }
            function openModal(button) {
                const modal = byId('staffManageModal');
                if (!modal || !button) return;
                byId('staffModalName').textContent = button.dataset.name || '-';
                byId('staffModalNik').textContent = button.dataset.nik ? ('NIK: ' + button.dataset.nik) : '';
                byId('staffMoveEmployeeId').value = button.dataset.id || '';
                byId('staffStatusEmployeeId').value = button.dataset.id || '';
                byId('staffPositionName').value = button.dataset.position || '';
                byId('staffEmploymentStatus').value = button.dataset.status || 'aktif';
                const unitSelect = byId('staffTargetUnitId');
                if (unitSelect) unitSelect.value = String(button.dataset.unitId || '');
                modal.classList.remove('hidden');
                modal.classList.add('flex');
                modal.setAttribute('aria-hidden', 'false');
                document.body.style.overflow = 'hidden';
            }
            function closeModal() {
                const modal = byId('staffManageModal');
                if (!modal) return;
                modal.classList.add('hidden');
                modal.classList.remove('flex');
                modal.setAttribute('aria-hidden', 'true');
                document.body.style.overflow = '';
            }
            document.addEventListener('click', function (event) {
                const button = event.target.closest('.js-staff-manage');
                if (button) {
                    event.preventDefault();
                    event.stopPropagation();
                    openModal(button);
                    return;
                }
                if (event.target.id === 'staffManageModal' || event.target.id === 'staffModalClose') {
                    event.preventDefault();
                    closeModal();
                }
            });
            document.addEventListener('keydown', function (event) {
                if (event.key === 'Escape') closeModal();
            });
        })();
        </script>
        <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4 mb-5">
            <?php foreach($nursingUnits as $nu): ?>
                <a href="?module=logbook_kpi&tab=staffunit&month=<?= $month ?>&year=<?= $year ?>&staff_unit_id=<?= (int)$nu['unit_id'] ?>&staff_status=aktif" class="lbk-card p-4 block hover:shadow-lg transition">
                    <div class="text-xs font-black text-slate-400 uppercase"><?= e($nu['display_name']) ?></div>
                    <div class="flex items-end justify-between mt-2"><div class="text-3xl font-black text-slate-900"><?= (int)$nu['active_staff'] ?></div><div class="text-xs text-slate-500"><?= (int)$nu['with_account'] ?> punya akun</div></div>
                    <div class="text-xs text-slate-400 mt-1"><?= (int)$nu['inactive_staff'] ?> nonaktif/keluar</div>
                </a>
            <?php endforeach; ?>
        </div>

        <div class="lbk-card p-5 mb-5">
            <div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3 mb-4">
                <div><h3 class="text-xl font-black text-slate-800">Manajemen Staf Unit Keperawatan</h3><p class="text-sm text-slate-500">Jumlah staf dihitung dari data individu aktif. Histori logbook tidak dihapus saat staf dipindahkan atau dinonaktifkan.</p></div>
            </div>
            <form method="get" class="grid grid-cols-1 md:grid-cols-4 gap-3 mb-5">
                <input type="hidden" name="module" value="logbook_kpi"><input type="hidden" name="tab" value="staffunit"><input type="hidden" name="month" value="<?= $month ?>"><input type="hidden" name="year" value="<?= $year ?>">
                <select name="staff_unit_id" class="lbk-input" <?= $currentLevel==='kaunit'?'disabled':'' ?>>
                    <option value="0">Semua unit keperawatan</option><?php foreach($nursingUnits as $nu): ?><option value="<?= (int)$nu['unit_id'] ?>" <?= $staffUnitFilter===(int)$nu['unit_id']?'selected':'' ?>><?= e($nu['display_name']) ?></option><?php endforeach; ?>
                </select><?php if($currentLevel==='kaunit'): ?><input type="hidden" name="staff_unit_id" value="<?= (int)$ownCanonicalUnitId ?>"><?php endif; ?>
                <select name="staff_status" class="lbk-input"><option value="">Semua status</option><?php foreach(['aktif'=>'Aktif','nonaktif'=>'Nonaktif','resign'=>'Resign','mutasi_keluar'=>'Mutasi Keluar'] as $sv=>$sl): ?><option value="<?= $sv ?>" <?= $staffStatusFilter===$sv?'selected':'' ?>><?= $sl ?></option><?php endforeach; ?></select>
                <input class="lbk-input" name="staff_search" value="<?= e($staffSearch) ?>" placeholder="Cari nama, NIK, jabatan">
                <button class="lbk-btn lbk-btn-primary">Terapkan Filter</button>
            </form>

            <div class="overflow-x-auto"><table class="w-full lbk-table"><thead><tr><th>Staf</th><th>Unit</th><th>Jabatan/Profesi</th><th>Status</th><th>Akun</th><th>Aksi</th></tr></thead><tbody>
                <?php foreach($nursingStaffRows as $sr): $canRow=lbk_can_manage_target_unit($conn,$currentLevel,$isAdmin,$unitId,(int)$sr['canonical_unit_id']); ?>
                <tr><td><div class="font-black"><?= e($sr['full_name']) ?></div><div class="text-xs text-slate-400"><?= e($sr['nik']) ?></div></td><td><div class="font-bold"><?= e($sr['canonical_unit_name']) ?></div><?php if((int)$sr['source_unit_id']!==(int)$sr['canonical_unit_id']): ?><div class="text-xs text-amber-600">Masih memakai unit duplikat: <?= e($sr['source_unit_name']) ?></div><?php endif; ?></td><td><?= e($sr['position_name']?:'-') ?><div class="text-xs text-slate-400"><?= e($sr['profession']) ?></div></td><td><span class="px-2 py-1 rounded-full border text-xs font-black <?= $sr['employment_status']==='aktif'?'bg-emerald-50 text-emerald-700 border-emerald-200':'bg-slate-50 text-slate-600 border-slate-200' ?>"><?= e($sr['employment_status']) ?></span></td><td><?= $sr['user_id']?'<span class="text-emerald-700 font-bold">Ada</span>':'<span class="text-amber-600">Belum ada</span>' ?></td><td>
                    <?php if($canRow): ?>
                        <button type="button"
                            class="js-staff-manage font-black text-blue-700 hover:text-blue-900"
                            data-id="<?= (int)$sr['id'] ?>"
                            data-name="<?= e($sr['full_name']) ?>"
                            data-nik="<?= e($sr['nik']) ?>"
                            data-unit-id="<?= (int)$sr['canonical_unit_id'] ?>"
                            data-position="<?= e($sr['position_name']) ?>"
                            data-status="<?= e($sr['employment_status']) ?>">
                            <i class="fas fa-sliders-h mr-1"></i> Kelola
                        </button>
                    <?php else: ?><span class="text-xs text-slate-400">Lihat saja</span><?php endif; ?>
                </td></tr><?php endforeach; ?>
                <?php if(!$nursingStaffRows): ?><tr><td colspan="6" class="text-center text-slate-400 py-8">Tidak ada staf sesuai filter.</td></tr><?php endif; ?>
            </tbody></table></div>
        </div>

        <div class="grid grid-cols-1 xl:grid-cols-2 gap-5">
            <div class="lbk-card p-5"><h3 class="text-lg font-black mb-3">Tambah Staf Baru</h3><form method="post" class="grid grid-cols-1 md:grid-cols-2 gap-3"><input type="hidden" name="action" value="create_nursing_staff"><input class="lbk-input" name="staff_nik" required placeholder="NIK"><input class="lbk-input" name="staff_name" required placeholder="Nama lengkap"><select class="lbk-input" name="staff_profession"><option value="perawat">Perawat</option><option value="bidan">Bidan</option><option value="lainnya">Lainnya</option></select><input class="lbk-input" name="staff_position" value="Perawat Pelaksana" placeholder="Jabatan"><select class="lbk-input" name="staff_unit_id" required><?php foreach($nursingUnits as $nu): if($currentLevel==='kaunit' && (int)$nu['unit_id']!==$ownCanonicalUnitId)continue; ?><option value="<?= (int)$nu['unit_id'] ?>"><?= e($nu['display_name']) ?></option><?php endforeach; ?></select><button class="lbk-btn lbk-btn-primary">Tambah Staf</button></form><p class="text-xs text-slate-400 mt-3">Penambahan ini membuat data staf, bukan akun login. Akun tetap dibuat melalui menu manajemen user.</p>
                <?php if($unassignedStaff): ?><div class="mt-5"><h4 class="font-black mb-2">Perawat/Bidan aktif di luar unit keperawatan</h4><div class="max-h-72 overflow-auto space-y-2"><?php foreach($unassignedStaff as $usf): ?><div class="border rounded-xl p-3"><div class="font-bold"><?= e($usf['full_name']) ?></div><div class="text-xs text-slate-400"><?= e($usf['nik']) ?> · <?= e($usf['current_unit']) ?></div><form method="post" class="flex gap-2 mt-2"><input type="hidden" name="action" value="move_nursing_staff"><input type="hidden" name="employee_id" value="<?= (int)$usf['id'] ?>"><select name="target_unit_id" class="lbk-input text-sm flex-1"><?php foreach($nursingUnits as $nu): if($currentLevel==='kaunit' && (int)$nu['unit_id']!==$ownCanonicalUnitId)continue; ?><option value="<?= (int)$nu['unit_id'] ?>"><?= e($nu['display_name']) ?></option><?php endforeach; ?></select><button class="lbk-btn text-sm">Masukkan</button></form></div><?php endforeach; ?></div></div><?php endif; ?>
            </div>

            <div class="lbk-card p-5"><h3 class="text-lg font-black mb-1">Unit Duplikat</h3><p class="text-sm text-slate-500 mb-3">Tombol rapikan memindahkan staf aktif ke ID unit utama dan menonaktifkan unit lama. Histori logbook tidak diubah.</p><div class="overflow-x-auto"><table class="w-full lbk-table"><thead><tr><th>Unit lama</th><th>Unit utama</th><th>Staf</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php foreach($duplicateUnitRows as $du): ?><tr><td><?= e($du['source_name']) ?> <span class="text-xs text-slate-400">#<?= (int)$du['source_unit_id'] ?></span></td><td class="font-bold"><?= e($du['canonical_name']) ?></td><td><?= (int)$du['staff_count'] ?></td><td><?= (int)$du['source_active']===1?'Aktif':'Nonaktif' ?></td><td><?php if($isAdmin||$currentLevel==='kadiv'): ?><form method="post" onsubmit="return confirm('Pindahkan semua staf ke unit utama dan nonaktifkan unit lama?')"><input type="hidden" name="action" value="merge_duplicate_nursing_unit"><input type="hidden" name="source_unit_id" value="<?= (int)$du['source_unit_id'] ?>"><input type="hidden" name="canonical_unit_id" value="<?= (int)$du['canonical_unit_id'] ?>"><button class="lbk-btn text-sm" <?= ((int)$du['source_active']===0&&(int)$du['staff_count']===0)?'disabled':'' ?>>Rapikan</button></form><?php else: ?><span class="text-xs text-slate-400">Kadiv/Admin</span><?php endif; ?></td></tr><?php endforeach; ?></tbody></table></div></div>
        </div>

    <?php elseif ($tab === 'master' && $isAdmin): ?>
        <?php
        $mf = $editMaster ?: ['id'=>0,'role_level'=>'pelaksana','unit_group'=>'UMUM','category_code'=>($categories[0]['code']??'A'),'activity_name'=>'','description'=>'','ideal_frequency_type'=>'daily','ideal_frequency_value'=>1,'unit_measure'=>'kegiatan','weight'=>3,'kpi_domain'=>'produktivitas','evidence_required'=>0,'is_active'=>1,'default_duration_minutes'=>15];
        $masterRoleForForm = (string)($mf['role_level']??'pelaksana');
        $masterUnitForForm = (string)($mf['unit_group']??'UMUM');
        if (!array_key_exists($masterUnitForForm, lbk_unit_options())) { $masterUnitForForm = 'UMUM'; }
        ?>
        <div class="grid grid-cols-1 xl:grid-cols-3 gap-5">
            <form method="post" class="lbk-card p-5 space-y-3">
                <input type="hidden" name="action" value="save_master">
                <input type="hidden" name="master_id" value="<?= (int)($mf['id']??0) ?>">
                <div class="flex items-start justify-between gap-3">
                    <div>
                        <h3 class="text-xl font-black"><?= $editMaster?'Edit Master Aktivitas':'Tambah Master Aktivitas' ?></h3>
                        <p class="text-xs text-slate-500 mt-1"><?= $editMaster?'Perbaiki parameter aktivitas.':'Tambahkan aktivitas baru.' ?></p>
                    </div>
                    <?php if($editMaster): ?><a href="index.php?module=logbook_kpi&tab=master&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>" class="lbk-btn bg-slate-100 text-slate-700 text-xs px-3 py-2">Batal Edit</a><?php endif; ?>
                </div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Role</label><select name="role_level" class="lbk-input"><?php foreach(['pelaksana'=>'Perawat Pelaksana','katim'=>'Katim / PJ Shift','kaunit'=>'Kepala Unit','kasubdiv_rajal'=>'Kasubdiv Rawat Jalan','kasubdiv_ranap'=>'Kasubdiv Rawat Inap','kadiv'=>'Kadiv'] as $rv=>$rl): ?><option value="<?= e($rv) ?>" <?= $masterRoleForForm===$rv?'selected':'' ?>><?= e($rl) ?></option><?php endforeach; ?></select></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Unit Aktivitas</label><select name="unit_group" class="lbk-input"><?php foreach(lbk_unit_options() as $uv=>$ul): ?><option value="<?= e($uv) ?>" <?= $masterUnitForForm===$uv?'selected':'' ?>><?= e($ul) ?></option><?php endforeach; ?></select></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Kategori</label><select name="category_code" class="lbk-input"><?php foreach($categories as $c): ?><option value="<?= e($c['code']) ?>" <?= (string)($mf['category_code']??'')===(string)$c['code']?'selected':'' ?>><?= e($c['code'].' - '.$c['name']) ?></option><?php endforeach; ?></select></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Nama Aktivitas</label><input name="activity_name" value="<?= e($mf['activity_name']??'') ?>" class="lbk-input" required></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Deskripsi</label><textarea name="description" rows="2" class="lbk-input"><?= e($mf['description']??'') ?></textarea></div>
                <div class="grid grid-cols-2 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Freq</label><select name="ideal_frequency_type" class="lbk-input"><?php foreach(['per_shift','daily','weekly','monthly','event'] as $fq): ?><option value="<?= e($fq) ?>" <?= (string)($mf['ideal_frequency_type']??'')===$fq?'selected':'' ?>><?= e($fq) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Ideal</label><input name="ideal_frequency_value" type="number" step="0.1" value="<?= e($mf['ideal_frequency_value']??1) ?>" class="lbk-input"></div>
                </div>
                <div class="grid grid-cols-2 gap-3">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Satuan</label><input name="unit_measure" value="<?= e($mf['unit_measure']??'kegiatan') ?>" class="lbk-input"></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Bobot</label><input name="weight" type="number" step="0.1" value="<?= e($mf['weight']??3) ?>" min="1" max="5" class="lbk-input"></div>
                </div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Domain KPI</label><select name="kpi_domain" class="lbk-input"><?php foreach(['produktivitas','dokumentasi','patient_safety','disiplin','leadership','kompetensi','mutu','kolaborasi'] as $dom): ?><option value="<?= e($dom) ?>" <?= (string)($mf['kpi_domain']??'')===$dom?'selected':'' ?>><?= e($dom) ?></option><?php endforeach; ?></select></div>
                <div>
                    <label class="text-xs font-bold text-slate-500 uppercase">Durasi Default / Pasien (menit)</label>
                    <input name="default_duration_minutes" type="number" min="1" max="480" value="<?= (int)($mf['default_duration_minutes']??15) ?>" class="lbk-input" style="max-width:200px">
                    <div class="text-xs text-slate-400 mt-1">Waktu rata-rata per tindakan. Dipakai sebagai default saat perawat mengisi logbook.</div>
                </div>
                <label class="flex gap-2 items-center"><input type="checkbox" name="evidence_required" <?= (int)($mf['evidence_required']??0)===1?'checked':'' ?>> <span class="font-bold text-sm">Wajib bukti</span></label>
                <label class="flex gap-2 items-center"><input type="checkbox" name="is_active" <?= (int)($mf['is_active']??1)===1?'checked':'' ?>> <span class="font-bold text-sm">Aktif</span></label>
                <button class="lbk-btn bg-blue-600 text-white"><i class="fas fa-save"></i> <?= $editMaster?'Update Master':'Simpan Master' ?></button>
            </form>
            <div class="xl:col-span-2 lbk-card p-5 overflow-x-auto">
                <div class="flex flex-col gap-1 mb-4">
                    <h3 class="text-xl font-black">Daftar Master Aktivitas</h3>
                    <p class="text-sm text-slate-500">Filter ini khusus tab Master Aktivitas dan tidak mengikuti filter bulan, unit staf, atau staf pada tab rekap.</p>
                </div>
                <form method="get" class="no-print grid grid-cols-1 md:grid-cols-3 xl:grid-cols-4 gap-3 mb-5 rounded-2xl border border-slate-200 bg-slate-50 p-4">
                    <input type="hidden" name="module" value="logbook_kpi">
                    <input type="hidden" name="tab" value="master">
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Role</label><select name="master_role" class="lbk-input"><option value="">Semua Role</option><?php foreach(['pelaksana'=>'Perawat Pelaksana','katim'=>'Katim / PJ Shift','kaunit'=>'Kepala Unit','kasubdiv'=>'Kasubdiv','kadiv'=>'Kadiv'] as $rv=>$rl): ?><option value="<?= e($rv) ?>" <?= $masterFilterRole===$rv?'selected':'' ?>><?= e($rl) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Unit Aktivitas</label><select name="master_unit" class="lbk-input"><option value="">Semua Unit</option><?php foreach(lbk_unit_options() as $uv=>$ul): ?><option value="<?= e($uv) ?>" <?= $masterFilterUnit===$uv?'selected':'' ?>><?= e($ul) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Kategori</label><select name="master_category" class="lbk-input"><option value="">Semua Kategori</option><?php foreach($categories as $c): ?><option value="<?= e($c['code']) ?>" <?= $masterFilterCategory===(string)$c['code']?'selected':'' ?>><?= e($c['code'].' - '.$c['name']) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Domain KPI</label><select name="master_domain" class="lbk-input"><option value="">Semua Domain</option><?php foreach(['produktivitas','dokumentasi','patient_safety','disiplin','leadership','kompetensi','mutu','kolaborasi'] as $dom): ?><option value="<?= e($dom) ?>" <?= $masterFilterDomain===$dom?'selected':'' ?>><?= e(ucwords(str_replace('_',' ',$dom))) ?></option><?php endforeach; ?></select></div>
                    <div><label class="text-xs font-bold text-slate-500 uppercase">Status</label><select name="master_status" class="lbk-input"><option value="all" <?= $masterFilterStatus==='all'?'selected':'' ?>>Semua Status</option><option value="active" <?= $masterFilterStatus==='active'?'selected':'' ?>>Aktif</option><option value="inactive" <?= $masterFilterStatus==='inactive'?'selected':'' ?>>Nonaktif</option></select></div>
                    <div class="md:col-span-2"><label class="text-xs font-bold text-slate-500 uppercase">Cari Aktivitas</label><input name="master_q" value="<?= e($masterFilterQuery) ?>" class="lbk-input" placeholder="Nama aktivitas, deskripsi, atau satuan"></div>
                    <div class="flex gap-2 items-end"><button class="lbk-btn bg-slate-900 text-white justify-center flex-1"><i class="fas fa-filter"></i> Terapkan</button><a href="index.php?module=logbook_kpi&tab=master" class="lbk-btn bg-white border border-slate-200 text-slate-700 justify-center"><i class="fas fa-rotate-left"></i></a></div>
                </form>
                <div class="text-sm font-bold text-slate-600 mb-3">Ditemukan <?= number_format(count($allMaster)) ?> aktivitas.</div>
                <table class="w-full lbk-table"><thead><tr><th>Role</th><th>Unit</th><th>Kategori</th><th>Aktivitas</th><th>Ideal</th><th>Menit</th><th>Bobot</th><th>Domain</th><th>Status</th><th>Aksi</th></tr></thead><tbody>
                <?php if(!$allMaster): ?><tr><td colspan="9" class="text-center text-slate-400 py-10">Tidak ada master aktivitas yang sesuai filter.</td></tr><?php endif; ?>
                <?php foreach($allMaster as $m): ?><tr><td><?= e(lbk_level_label($m['role_level'])) ?></td><td><?= e(lbk_unit_label($m['unit_group']??'UMUM')) ?></td><td><?= e($m['category_code'].' - '.$m['category_name']) ?></td><td class="font-bold"><?= e($m['activity_name']) ?><?php if(!empty($m['description'])): ?><div class="text-xs text-slate-400 mt-1 max-w-md"><?= e($m['description']) ?></div><?php endif; ?></td><td><?= e($m['ideal_frequency_value'].' '.$m['unit_measure'].'/'.$m['ideal_frequency_type']) ?></td><td><span class="font-bold text-blue-700"><?= (int)($m['default_duration_minutes']??0) ?> mnt</span></td><td><?= e($m['weight']) ?></td><td><?= e($m['kpi_domain']) ?></td><td><?php if((int)$m['is_active']===1): ?><span class="px-2 py-1 rounded-full border text-xs font-black bg-emerald-50 text-emerald-700 border-emerald-200">Aktif</span><?php else: ?><span class="px-2 py-1 rounded-full border text-xs font-black bg-slate-100 text-slate-600 border-slate-200">Nonaktif</span><?php endif; ?></td><td><div class="flex flex-wrap gap-2"><a class="lbk-btn bg-amber-500 text-white text-xs px-3 py-2" href="index.php?module=logbook_kpi&tab=master&month=<?= $month ?>&year=<?= $year ?>&unit_id=<?= $filterUnit ?>&user_id=<?= $filterUser ?>&master_role=<?= urlencode($masterFilterRole) ?>&master_unit=<?= urlencode($masterFilterUnit) ?>&master_category=<?= urlencode($masterFilterCategory) ?>&master_domain=<?= urlencode($masterFilterDomain) ?>&master_status=<?= urlencode($masterFilterStatus) ?>&master_q=<?= urlencode($masterFilterQuery) ?>&edit_master=<?= (int)$m['id'] ?>"><i class="fas fa-edit"></i> Edit</a><form method="post" onsubmit="return confirm('Yakin hapus/nonaktifkan?');"><input type="hidden" name="action" value="delete_master"><input type="hidden" name="master_id" value="<?= (int)$m['id'] ?>"><button class="lbk-btn bg-rose-600 text-white text-xs px-3 py-2" type="submit"><i class="fas fa-trash"></i></button></form></div></td></tr>
                <?php endforeach; ?>
                </tbody></table>
            </div>
        </div>

    <!-- ═══════════════════════════════ REFERENSI GAJI ══════════════════════════ -->
    <?php elseif ($tab === 'gaji' && $isAdmin): ?>
        <div class="lbk-card p-5 max-w-3xl">
            <h3 class="text-xl font-black mb-4">Input Referensi Gaji Bulanan</h3>
            <form method="post" class="grid grid-cols-1 md:grid-cols-2 gap-3">
                <input type="hidden" name="action" value="save_salary">
                <div class="md:col-span-2"><label class="text-xs font-bold text-slate-500 uppercase">Staf</label><select name="salary_user_id" class="lbk-input"><?php foreach($users as $u): ?><option value="<?= (int)$u['user_id'] ?>"><?= e($u['name'].' - '.$u['unit_name']) ?></option><?php endforeach; ?></select></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Bulan</label><input name="salary_month" value="<?= $month ?>" type="number" min="1" max="12" class="lbk-input"></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Tahun</label><input name="salary_year" value="<?= $year ?>" type="number" class="lbk-input"></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Nominal Gaji</label><input name="salary_amount" type="number" step="1000" class="lbk-input" placeholder="4500000"></div>
                <div><label class="text-xs font-bold text-slate-500 uppercase">Catatan</label><input name="salary_note" class="lbk-input" placeholder="Opsional"></div>
                <div class="md:col-span-2"><button class="lbk-btn bg-blue-600 text-white">Simpan Referensi Gaji</button></div>
            </form>
        </div>
    <?php endif; ?>

</div><!-- /space-y-6 -->

<!-- ═══════════════════════════════ SCRIPTS ═════════════════════════════════ -->
<script>
/* ── Searchable dropdown ── */
(function(){
    function normalizeText(str){ return (str||'').toString().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,''); }
    function enhanceSelect(select){
        if(!select||select.dataset.lbkEnhanced==='1'||select.disabled)return;
        select.dataset.lbkEnhanced='1';
        select.classList.add('lbk-search-native-hidden');
        const wrap=document.createElement('div'); wrap.className='lbk-search-wrap';
        const btn=document.createElement('button'); btn.type='button'; btn.className='lbk-search-btn'; btn.setAttribute('aria-haspopup','listbox');
        const label=document.createElement('span'); label.className='lbk-search-label';
        const caret=document.createElement('span'); caret.className='lbk-search-caret'; caret.innerHTML='<i class="fas fa-chevron-down"></i>';
        btn.appendChild(label); btn.appendChild(caret);
        const panel=document.createElement('div'); panel.className='lbk-search-panel';
        const input=document.createElement('input'); input.type='text'; input.className='lbk-search-input'; input.placeholder='Ketik untuk mencari...';
        const list=document.createElement('div'); list.className='lbk-search-list'; list.setAttribute('role','listbox');
        panel.appendChild(input); panel.appendChild(list); wrap.appendChild(btn); wrap.appendChild(panel);
        select.parentNode.insertBefore(wrap,select.nextSibling);
        function selectedText(){ const opt=select.options[select.selectedIndex]; return opt?opt.text:'Pilih data'; }
        function updateLabel(){ label.textContent=selectedText(); label.title=selectedText(); }
        function render(){
            const q=normalizeText(input.value); list.innerHTML=''; let shown=0;
            Array.from(select.options).forEach(function(opt){
                if(q&&!normalizeText(opt.text+' '+opt.value).includes(q))return;
                const item=document.createElement('button'); item.type='button';
                item.className='lbk-search-option'+(opt.selected?' selected':'');
                item.textContent=opt.text; item.title=opt.text; item.dataset.value=opt.value;
                item.addEventListener('click',function(){ select.value=opt.value; updateLabel(); close(); select.dispatchEvent(new Event('change',{bubbles:true})); });
                list.appendChild(item); shown++;
            });
            if(!shown){ const empty=document.createElement('div'); empty.className='lbk-search-muted'; empty.textContent='Tidak ada data yang cocok.'; list.appendChild(empty); }
        }
        function open(){ document.querySelectorAll('.lbk-search-wrap.open').forEach(function(other){ if(other!==wrap)other.classList.remove('open'); }); wrap.classList.add('open'); input.value=''; render(); setTimeout(function(){ input.focus(); },40); }
        function close(){ wrap.classList.remove('open'); }
        btn.addEventListener('click',function(e){ e.preventDefault(); wrap.classList.contains('open')?close():open(); });
        input.addEventListener('input',render);
        input.addEventListener('keydown',function(e){ if(e.key==='Escape'){e.preventDefault();close();btn.focus();} if(e.key==='Enter'){const first=list.querySelector('.lbk-search-option');if(first){e.preventDefault();first.click();}} });
        document.addEventListener('click',function(e){ if(!wrap.contains(e.target))close(); });
        select.addEventListener('change',updateLabel);
        updateLabel();
    }
    function initLbkSearchSelects(){ document.querySelectorAll('select.lbk-input').forEach(enhanceSelect); }
    if(document.readyState==='loading'){ document.addEventListener('DOMContentLoaded',initLbkSearchSelects); } else { initLbkSearchSelects(); }
})();

/* ── Multi kamar/bed: sinkronkan jumlah pasien dan real count ── */
(function(){
    var boxes = Array.prototype.slice.call(document.querySelectorAll('.room-checkbox'));
    if(!boxes.length) return;
    var elPatients = document.getElementById('inputPatientsCount');
    var elReal     = document.getElementById('inputRealCount');
    var elHint     = document.getElementById('selectedRoomHint');
    var btnAll     = document.getElementById('btnSelectAllRooms');

    function syncRooms(){
        var selected = boxes.filter(function(cb){ return cb.checked; });
        var count = selected.length;
        if(elHint){
            elHint.textContent = count
                ? count + ' kamar dipilih: ' + selected.map(function(cb){ return cb.value; }).join(', ')
                : 'Belum ada kamar dipilih.';
        }
        if(count > 0){
            if(elPatients && (parseInt(elPatients.value || '0',10) < count)){
                elPatients.value = count;
                elPatients.dispatchEvent(new Event('input',{bubbles:true}));
            }
            if(elReal && (parseFloat(elReal.value || '0') < count)){
                elReal.value = count;
            }
        }
        if(btnAll){ btnAll.textContent = count === boxes.length ? 'Batalkan semua' : 'Pilih semua'; }
    }
    boxes.forEach(function(cb){ cb.addEventListener('change',syncRooms); });
    if(btnAll){
        btnAll.addEventListener('click',function(){
            var shouldCheck = !boxes.every(function(cb){ return cb.checked; });
            boxes.forEach(function(cb){ cb.checked = shouldCheck; });
            syncRooms();
        });
    }
    syncRooms();
})();

/* ── Auto-hitung durasi total = jumlah pasien × durasi per pasien ── */
(function(){
    var elPatients = document.getElementById('inputPatientsCount');
    var elDurPer   = document.getElementById('inputDurPerPasien');
    var elDurTotal = document.getElementById('inputDurationMinutes');
    var elHint     = document.getElementById('durationHint');
    var elActivity = document.getElementById('selectActivity');
    if(!elPatients||!elDurPer||!elDurTotal)return;
    var manualOverride = false;
    function applyActivityDefault(){
        if(!elActivity)return;
        var sel=elActivity.options[elActivity.selectedIndex];
        var def=sel?parseInt(sel.getAttribute('data-duration')||'0',10):0;
        if(def>0){elDurPer.value=def;manualOverride=false;calcDuration();}
    }
    if(elActivity){
        elActivity.addEventListener('change',function(){manualOverride=false;applyActivityDefault();});
        <?php if(!$editEntry): ?>applyActivityDefault();<?php endif; ?>
    }
    function calcDuration(){
        if(manualOverride)return;
        var p=parseFloat(elPatients.value)||0;
        var d=parseFloat(elDurPer.value)||0;
        var total=Math.round(p*d);
        elDurTotal.value=total>0?total:'';
        if(elHint){ elHint.textContent=total>0?('= '+p+' pasien × '+d+' mnt = '+total+' menit'):'= jumlah pasien × durasi/pasien'; }
    }
    elPatients.addEventListener('input',function(){ manualOverride=false; calcDuration(); });
    elDurPer.addEventListener('input',function(){ manualOverride=false; calcDuration(); });
    elDurTotal.addEventListener('input',function(){ manualOverride=true; if(elHint)elHint.textContent='Diisi manual — auto-hitung dinonaktifkan.'; });
    calcDuration();

    /* Scroll ke form saat mode edit */
    <?php if($editEntry): ?>
    var formEl=document.getElementById('formLogbook');
    if(formEl){ setTimeout(function(){ formEl.scrollIntoView({behavior:'smooth',block:'start'}); },200); }
    <?php endif; ?>
})();
</script>