<?php
/* KanbanBoard.php - Enterprise Kanban Project Management Tool
 * Per-user boards with drag-and-drop, setup wizard, and project tracking
 * Following Evergreen ERP patterns: Ant Design style, Poppins font, teal brand
 */

$PageSecurity = 1;
$Title = 'Kanban Board';

// ─── API MODE ───────────────────────────────────────────────
if (isset($_GET['api'])) {
    ob_start();
    include('includes/session.inc');
    ob_end_clean();
    header('Content-Type: application/json');

    $conn = new mysqli('localhost', 'sooggoo', '4Compassion*', 'evergreentest');
    if ($conn->connect_error) {
        echo json_encode(['success' => false, 'error' => 'DB connection failed']);
        exit;
    }
    $conn->set_charset('utf8');
    $userId = isset($_SESSION['UserID']) ? $_SESSION['UserID'] : '';

    // ── Ensure tables exist ──
    $conn->query("CREATE TABLE IF NOT EXISTS kanban_boards (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id VARCHAR(50) NOT NULL,
        board_name VARCHAR(200) NOT NULL,
        board_type VARCHAR(50) DEFAULT 'kanban',
        description TEXT,
        is_default TINYINT(1) DEFAULT 0,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX idx_user (user_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8");

    $conn->query("CREATE TABLE IF NOT EXISTS kanban_columns (
        id INT AUTO_INCREMENT PRIMARY KEY,
        board_id INT NOT NULL,
        column_name VARCHAR(200) NOT NULL,
        column_order INT DEFAULT 0,
        color VARCHAR(20) DEFAULT '#E5E7EB',
        wip_limit INT DEFAULT 0,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_board (board_id),
        FOREIGN KEY (board_id) REFERENCES kanban_boards(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8");

    $conn->query("CREATE TABLE IF NOT EXISTS kanban_cards (
        id INT AUTO_INCREMENT PRIMARY KEY,
        column_id INT NOT NULL,
        board_id INT NOT NULL,
        title VARCHAR(500) NOT NULL,
        description TEXT,
        priority ENUM('low','medium','high','urgent') DEFAULT 'medium',
        card_order INT DEFAULT 0,
        assigned_to VARCHAR(50) DEFAULT '',
        due_date DATE DEFAULT NULL,
        labels VARCHAR(500) DEFAULT '',
        created_by VARCHAR(50) NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        completed_at DATETIME DEFAULT NULL,
        INDEX idx_column (column_id),
        INDEX idx_board (board_id),
        FOREIGN KEY (column_id) REFERENCES kanban_columns(id) ON DELETE CASCADE,
        FOREIGN KEY (board_id) REFERENCES kanban_boards(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8");

    $conn->query("CREATE TABLE IF NOT EXISTS kanban_activity (
        id INT AUTO_INCREMENT PRIMARY KEY,
        card_id INT NOT NULL,
        board_id INT NOT NULL,
        user_id VARCHAR(50) NOT NULL,
        action_type VARCHAR(50) NOT NULL,
        action_detail TEXT,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_card (card_id),
        INDEX idx_board (board_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8");

    $action = isset($_GET['action']) ? $_GET['action'] : '';
    $safeUserId = $conn->real_escape_string($userId);

    // ── Helper: verify board belongs to current user ──
    function verifyBoardOwner($conn, $boardId, $safeUserId) {
        $r = $conn->query("SELECT id FROM kanban_boards WHERE id=" . intval($boardId) . " AND user_id='" . $safeUserId . "'");
        return ($r && $r->num_rows > 0);
    }
    // ── Helper: verify column belongs to user's board ──
    function verifyColumnOwner($conn, $columnId, $safeUserId) {
        $r = $conn->query("SELECT kc.id FROM kanban_columns kc
                           JOIN kanban_boards kb ON kc.board_id = kb.id
                           WHERE kc.id=" . intval($columnId) . " AND kb.user_id='" . $safeUserId . "'");
        return ($r && $r->num_rows > 0);
    }
    // ── Helper: verify card belongs to user's board ──
    function verifyCardOwner($conn, $cardId, $safeUserId) {
        $r = $conn->query("SELECT k.id FROM kanban_cards k
                           JOIN kanban_boards kb ON k.board_id = kb.id
                           WHERE k.id=" . intval($cardId) . " AND kb.user_id='" . $safeUserId . "'");
        return ($r && $r->num_rows > 0);
    }

    // ── Check if user has boards (for wizard) ──
    if ($action === 'check_setup') {
        $r = $conn->query("SELECT COUNT(*) as cnt FROM kanban_boards WHERE user_id='" . $conn->real_escape_string($userId) . "'");
        $row = $r ? $r->fetch_assoc() : array('cnt' => 0);
        echo json_encode(['success' => true, 'has_boards' => intval($row['cnt']) > 0]);
        exit;
    }

    // ── Setup wizard: create board with columns ──
    if ($action === 'setup_board') {
        $data = json_decode(file_get_contents('php://input'), true);
        $boardName = $conn->real_escape_string(isset($data['board_name']) ? $data['board_name'] : 'My Board');
        $boardType = $conn->real_escape_string(isset($data['board_type']) ? $data['board_type'] : 'kanban');
        $description = $conn->real_escape_string(isset($data['description']) ? $data['description'] : '');
        $columns = isset($data['columns']) ? $data['columns'] : array();

        $conn->query("INSERT INTO kanban_boards (user_id, board_name, board_type, description, is_default)
                       VALUES ('" . $conn->real_escape_string($userId) . "', '$boardName', '$boardType', '$description', 1)");
        $boardId = $conn->insert_id;

        if (empty($columns)) {
            $columns = array(
                array('name' => 'To Do', 'color' => '#E5E7EB'),
                array('name' => 'In Progress', 'color' => '#DBEAFE'),
                array('name' => 'Review', 'color' => '#FEF3C7'),
                array('name' => 'Done', 'color' => '#D1FAE5')
            );
        }
        foreach ($columns as $i => $col) {
            $colName = $conn->real_escape_string($col['name']);
            $colColor = $conn->real_escape_string(isset($col['color']) ? $col['color'] : '#E5E7EB');
            $conn->query("INSERT INTO kanban_columns (board_id, column_name, column_order, color) VALUES ($boardId, '$colName', $i, '$colColor')");
        }

        echo json_encode(['success' => true, 'board_id' => $boardId]);
        exit;
    }

    // ── Get all boards for user ──
    if ($action === 'get_boards') {
        $r = $conn->query("SELECT * FROM kanban_boards WHERE user_id='" . $conn->real_escape_string($userId) . "' ORDER BY is_default DESC, board_name");
        $boards = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $boards[] = $row; } }
        echo json_encode(['success' => true, 'boards' => $boards]);
        exit;
    }

    // ── Get full board data (columns + cards) ──
    if ($action === 'get_board') {
        $boardId = intval(isset($_GET['board_id']) ? $_GET['board_id'] : 0);
        $br = $conn->query("SELECT * FROM kanban_boards WHERE id=$boardId AND user_id='" . $conn->real_escape_string($userId) . "'");
        if (!$br || $br->num_rows === 0) {
            echo json_encode(['success' => false, 'error' => 'Board not found']);
            exit;
        }
        $board = $br->fetch_assoc();

        $cols = array();
        $cr = $conn->query("SELECT * FROM kanban_columns WHERE board_id=$boardId ORDER BY column_order");
        if ($cr) {
            while ($col = $cr->fetch_assoc()) {
                $col['cards'] = array();
                $cardR = $conn->query("SELECT * FROM kanban_cards WHERE column_id=" . intval($col['id']) . " ORDER BY card_order");
                if ($cardR) {
                    while ($card = $cardR->fetch_assoc()) { $col['cards'][] = $card; }
                }
                $cols[] = $col;
            }
        }
        $board['columns'] = $cols;

        // Stats
        $statsR = $conn->query("SELECT
            COUNT(*) as total,
            SUM(CASE WHEN kc2.column_name='Done' OR kc2.column_name='Completed' THEN 1 ELSE 0 END) as done,
            SUM(CASE WHEN k.priority='urgent' THEN 1 ELSE 0 END) as urgent,
            SUM(CASE WHEN k.due_date IS NOT NULL AND k.due_date < CURDATE() AND (kc2.column_name NOT IN ('Done','Completed')) THEN 1 ELSE 0 END) as overdue
            FROM kanban_cards k
            JOIN kanban_columns kc2 ON k.column_id = kc2.id
            WHERE k.board_id=$boardId");
        $stats = $statsR ? $statsR->fetch_assoc() : array('total'=>0,'done'=>0,'urgent'=>0,'overdue'=>0);
        $board['stats'] = $stats;

        echo json_encode(['success' => true, 'board' => $board]);
        exit;
    }

    // ── Add card ──
    if ($action === 'add_card') {
        $data = json_decode(file_get_contents('php://input'), true);
        $columnId = intval($data['column_id']);
        $boardId = intval($data['board_id']);
        if (!verifyBoardOwner($conn, $boardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $title = $conn->real_escape_string($data['title']);
        $description = $conn->real_escape_string(isset($data['description']) ? $data['description'] : '');
        $priority = $conn->real_escape_string(isset($data['priority']) ? $data['priority'] : 'medium');
        $assignedTo = $conn->real_escape_string(isset($data['assigned_to']) ? $data['assigned_to'] : '');
        $dueDate = isset($data['due_date']) && $data['due_date'] ? "'" . $conn->real_escape_string($data['due_date']) . "'" : 'NULL';
        $labels = $conn->real_escape_string(isset($data['labels']) ? $data['labels'] : '');

        // Get max order
        $or = $conn->query("SELECT COALESCE(MAX(card_order),0)+1 as nxt FROM kanban_cards WHERE column_id=$columnId");
        $nxt = $or ? $or->fetch_assoc() : array('nxt' => 0);

        $conn->query("INSERT INTO kanban_cards (column_id, board_id, title, description, priority, card_order, assigned_to, due_date, labels, created_by)
                       VALUES ($columnId, $boardId, '$title', '$description', '$priority', " . intval($nxt['nxt']) . ", '$assignedTo', $dueDate, '$labels', '" . $conn->real_escape_string($userId) . "')");
        $cardId = $conn->insert_id;

        // Activity log
        $conn->query("INSERT INTO kanban_activity (card_id, board_id, user_id, action_type, action_detail)
                       VALUES ($cardId, $boardId, '" . $conn->real_escape_string($userId) . "', 'created', 'Card created: $title')");

        echo json_encode(['success' => true, 'card_id' => $cardId]);
        exit;
    }

    // ── Update card ──
    if ($action === 'update_card') {
        $data = json_decode(file_get_contents('php://input'), true);
        $cardId = intval($data['card_id']);
        if (!verifyCardOwner($conn, $cardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $sets = array();
        foreach (array('title','description','priority','assigned_to','labels') as $f) {
            if (isset($data[$f])) {
                $sets[] = "$f='" . $conn->real_escape_string($data[$f]) . "'";
            }
        }
        if (isset($data['due_date'])) {
            $sets[] = $data['due_date'] ? "due_date='" . $conn->real_escape_string($data['due_date']) . "'" : "due_date=NULL";
        }
        if (!empty($sets)) {
            $conn->query("UPDATE kanban_cards SET " . implode(',', $sets) . " WHERE id=$cardId");
        }

        // Activity
        $boardId = intval(isset($data['board_id']) ? $data['board_id'] : 0);
        $conn->query("INSERT INTO kanban_activity (card_id, board_id, user_id, action_type, action_detail)
                       VALUES ($cardId, $boardId, '" . $conn->real_escape_string($userId) . "', 'updated', 'Card updated')");

        echo json_encode(['success' => true]);
        exit;
    }

    // ── Move card (drag-and-drop) ──
    if ($action === 'move_card') {
        $data = json_decode(file_get_contents('php://input'), true);
        $cardId = intval($data['card_id']);
        $newColumnId = intval($data['new_column_id']);
        $newOrder = intval($data['new_order']);
        $boardId = intval(isset($data['board_id']) ? $data['board_id'] : 0);
        if (!verifyCardOwner($conn, $cardId, $safeUserId) || !verifyBoardOwner($conn, $boardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }

        // Check if moving to "Done" column
        $colR = $conn->query("SELECT column_name FROM kanban_columns WHERE id=$newColumnId");
        $colName = $colR ? $colR->fetch_assoc() : array('column_name' => '');
        $completedAt = (strtolower($colName['column_name']) === 'done' || strtolower($colName['column_name']) === 'completed') ? ", completed_at=NOW()" : ", completed_at=NULL";

        $conn->query("UPDATE kanban_cards SET column_id=$newColumnId, card_order=$newOrder $completedAt WHERE id=$cardId");

        // Re-order cards in target column
        $cardsR = $conn->query("SELECT id FROM kanban_cards WHERE column_id=$newColumnId AND id != $cardId ORDER BY card_order");
        $order = 0;
        if ($cardsR) {
            while ($c = $cardsR->fetch_assoc()) {
                if ($order == $newOrder) $order++;
                $conn->query("UPDATE kanban_cards SET card_order=$order WHERE id=" . intval($c['id']));
                $order++;
            }
        }

        // Activity
        $conn->query("INSERT INTO kanban_activity (card_id, board_id, user_id, action_type, action_detail)
                       VALUES ($cardId, $boardId, '" . $conn->real_escape_string($userId) . "', 'moved', 'Moved to " . $conn->real_escape_string($colName['column_name']) . "')");

        echo json_encode(['success' => true]);
        exit;
    }

    // ── Delete card ──
    if ($action === 'delete_card') {
        $data = json_decode(file_get_contents('php://input'), true);
        $cardId = intval($data['card_id']);
        if (!verifyCardOwner($conn, $cardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $conn->query("DELETE FROM kanban_activity WHERE card_id=$cardId");
        $conn->query("DELETE FROM kanban_cards WHERE id=$cardId");
        echo json_encode(['success' => true]);
        exit;
    }

    // ── Add column ──
    if ($action === 'add_column') {
        $data = json_decode(file_get_contents('php://input'), true);
        $boardId = intval($data['board_id']);
        if (!verifyBoardOwner($conn, $boardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $colName = $conn->real_escape_string($data['column_name']);
        $color = $conn->real_escape_string(isset($data['color']) ? $data['color'] : '#E5E7EB');
        $or = $conn->query("SELECT COALESCE(MAX(column_order),0)+1 as nxt FROM kanban_columns WHERE board_id=$boardId");
        $nxt = $or ? $or->fetch_assoc() : array('nxt' => 0);
        $conn->query("INSERT INTO kanban_columns (board_id, column_name, column_order, color) VALUES ($boardId, '$colName', " . intval($nxt['nxt']) . ", '$color')");
        echo json_encode(['success' => true, 'column_id' => $conn->insert_id]);
        exit;
    }

    // ── Delete column ──
    if ($action === 'delete_column') {
        $data = json_decode(file_get_contents('php://input'), true);
        $colId = intval($data['column_id']);
        if (!verifyColumnOwner($conn, $colId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $conn->query("DELETE FROM kanban_activity WHERE card_id IN (SELECT id FROM kanban_cards WHERE column_id=$colId)");
        $conn->query("DELETE FROM kanban_cards WHERE column_id=$colId");
        $conn->query("DELETE FROM kanban_columns WHERE id=$colId");
        echo json_encode(['success' => true]);
        exit;
    }

    // ── Rename column ──
    if ($action === 'rename_column') {
        $data = json_decode(file_get_contents('php://input'), true);
        $colId = intval($data['column_id']);
        if (!verifyColumnOwner($conn, $colId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $newName = $conn->real_escape_string($data['column_name']);
        $conn->query("UPDATE kanban_columns SET column_name='$newName' WHERE id=$colId");
        echo json_encode(['success' => true]);
        exit;
    }

    // ── Delete board ──
    if ($action === 'delete_board') {
        $data = json_decode(file_get_contents('php://input'), true);
        $boardId = intval($data['board_id']);
        $conn->query("DELETE FROM kanban_activity WHERE board_id=$boardId");
        $conn->query("DELETE FROM kanban_cards WHERE board_id=$boardId");
        $conn->query("DELETE FROM kanban_columns WHERE board_id=$boardId");
        $conn->query("DELETE FROM kanban_boards WHERE id=$boardId AND user_id='" . $conn->real_escape_string($userId) . "'");
        echo json_encode(['success' => true]);
        exit;
    }

    // ── Get activity log ──
    if ($action === 'get_activity') {
        $boardId = intval(isset($_GET['board_id']) ? $_GET['board_id'] : 0);
        if (!verifyBoardOwner($conn, $boardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $r = $conn->query("SELECT a.*, c.title as card_title FROM kanban_activity a
                           LEFT JOIN kanban_cards c ON a.card_id = c.id
                           WHERE a.board_id=$boardId ORDER BY a.created_at DESC LIMIT 30");
        $activity = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $activity[] = $row; } }
        echo json_encode(['success' => true, 'activity' => $activity]);
        exit;
    }

    // ── Get users for assignment ──
    if ($action === 'get_users') {
        $r = $conn->query("SELECT userid, realname FROM www_users WHERE blocked=0 ORDER BY realname");
        $users = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $users[] = $row; } }
        echo json_encode(['success' => true, 'users' => $users]);
        exit;
    }

    // ── Rename board ──
    if ($action === 'rename_board') {
        $data = json_decode(file_get_contents('php://input'), true);
        $boardId = intval($data['board_id']);
        $newName = $conn->real_escape_string($data['board_name']);
        $conn->query("UPDATE kanban_boards SET board_name='$newName' WHERE id=$boardId AND user_id='" . $conn->real_escape_string($userId) . "'");
        echo json_encode(['success' => true]);
        exit;
    }

    // ── Board Reports & Analytics ──
    if ($action === 'get_reports') {
        $boardId = intval(isset($_GET['board_id']) ? $_GET['board_id'] : 0);
        if (!verifyBoardOwner($conn, $boardId, $safeUserId)) {
            echo json_encode(['success' => false, 'error' => 'Access denied']);
            exit;
        }
        $reports = array();

        // 1. Cards per column (workflow distribution)
        $r = $conn->query("SELECT kc.column_name, kc.color, kc.column_order, COUNT(k.id) as card_count
                           FROM kanban_columns kc
                           LEFT JOIN kanban_cards k ON k.column_id = kc.id
                           WHERE kc.board_id=$boardId
                           GROUP BY kc.id ORDER BY kc.column_order");
        $colDist = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $colDist[] = $row; } }
        $reports['column_distribution'] = $colDist;

        // 2. Priority breakdown
        $r = $conn->query("SELECT priority, COUNT(*) as cnt FROM kanban_cards WHERE board_id=$boardId GROUP BY priority ORDER BY FIELD(priority,'urgent','high','medium','low')");
        $priorities = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $priorities[] = $row; } }
        $reports['priority_breakdown'] = $priorities;

        // 3. Cards created per day (last 30 days)
        $r = $conn->query("SELECT DATE(created_at) as day, COUNT(*) as cnt
                           FROM kanban_cards WHERE board_id=$boardId AND created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                           GROUP BY DATE(created_at) ORDER BY day");
        $createdTrend = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $createdTrend[] = $row; } }
        $reports['created_trend'] = $createdTrend;

        // 4. Cards completed per day (last 30 days)
        $r = $conn->query("SELECT DATE(completed_at) as day, COUNT(*) as cnt
                           FROM kanban_cards WHERE board_id=$boardId AND completed_at IS NOT NULL AND completed_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                           GROUP BY DATE(completed_at) ORDER BY day");
        $completedTrend = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $completedTrend[] = $row; } }
        $reports['completed_trend'] = $completedTrend;

        // 5. Cumulative flow (running totals per column over last 14 days)
        $colNames = array();
        $cr = $conn->query("SELECT id, column_name FROM kanban_columns WHERE board_id=$boardId ORDER BY column_order");
        if ($cr) { while ($row = $cr->fetch_assoc()) { $colNames[] = $row; } }
        $cumulFlow = array();
        for ($d = 13; $d >= 0; $d--) {
            $dayLabel = date('M j', strtotime("-$d days"));
            $dateEnd = date('Y-m-d 23:59:59', strtotime("-$d days"));
            $entry = array('day' => $dayLabel);
            foreach ($colNames as $col) {
                $cid = intval($col['id']);
                $r2 = $conn->query("SELECT COUNT(*) as cnt FROM kanban_cards WHERE board_id=$boardId AND column_id=$cid AND created_at <= '$dateEnd'");
                $cnt = ($r2) ? $r2->fetch_assoc() : array('cnt' => 0);
                $entry[$col['column_name']] = intval($cnt['cnt']);
            }
            $cumulFlow[] = $entry;
        }
        $reports['cumulative_flow'] = $cumulFlow;
        $reports['column_names'] = array_map(function($c) { return $c['column_name']; }, $colNames);

        // 6. Assignee workload
        $r = $conn->query("SELECT
                            CASE WHEN k.assigned_to = '' OR k.assigned_to IS NULL THEN 'Unassigned' ELSE k.assigned_to END as assignee,
                            COUNT(*) as total,
                            SUM(CASE WHEN kc.column_name IN ('Done','Completed','Deployed') THEN 1 ELSE 0 END) as done
                           FROM kanban_cards k
                           JOIN kanban_columns kc ON k.column_id = kc.id
                           WHERE k.board_id=$boardId
                           GROUP BY assignee ORDER BY total DESC LIMIT 10");
        $workload = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $workload[] = $row; } }
        $reports['assignee_workload'] = $workload;

        // 7. Overdue cards list
        $r = $conn->query("SELECT k.title, k.priority, k.due_date, k.assigned_to, kc.column_name
                           FROM kanban_cards k
                           JOIN kanban_columns kc ON k.column_id = kc.id
                           WHERE k.board_id=$boardId AND k.due_date < CURDATE()
                           AND kc.column_name NOT IN ('Done','Completed','Deployed')
                           ORDER BY k.due_date ASC LIMIT 20");
        $overdue = array();
        if ($r) { while ($row = $r->fetch_assoc()) { $overdue[] = $row; } }
        $reports['overdue_cards'] = $overdue;

        // 8. Average cycle time (days from created to completed)
        $r = $conn->query("SELECT ROUND(AVG(DATEDIFF(completed_at, created_at)),1) as avg_days,
                                  ROUND(MIN(DATEDIFF(completed_at, created_at)),1) as min_days,
                                  ROUND(MAX(DATEDIFF(completed_at, created_at)),1) as max_days,
                                  COUNT(*) as completed_count
                           FROM kanban_cards WHERE board_id=$boardId AND completed_at IS NOT NULL");
        $cycle = $r ? $r->fetch_assoc() : array('avg_days'=>0,'min_days'=>0,'max_days'=>0,'completed_count'=>0);
        $reports['cycle_time'] = $cycle;

        // 9. Summary KPIs
        $r = $conn->query("SELECT
                            COUNT(*) as total,
                            SUM(CASE WHEN kc.column_name IN ('Done','Completed','Deployed') THEN 1 ELSE 0 END) as done,
                            SUM(CASE WHEN k.completed_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) THEN 1 ELSE 0 END) as done_this_week,
                            SUM(CASE WHEN k.created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) THEN 1 ELSE 0 END) as created_this_week
                           FROM kanban_cards k
                           JOIN kanban_columns kc ON k.column_id = kc.id
                           WHERE k.board_id=$boardId");
        $summary = $r ? $r->fetch_assoc() : array('total'=>0,'done'=>0,'done_this_week'=>0,'created_this_week'=>0);
        $reports['summary'] = $summary;

        echo json_encode(['success' => true, 'reports' => $reports]);
        exit;
    }

    echo json_encode(['success' => false, 'error' => 'Unknown action']);
    exit;
}

// ─── PAGE RENDER MODE ───────────────────────────────────────
include('includes/session.inc');
$Title = 'Kanban Board';
include('includes/newheader.php');
?>

<style>
/* ─── Kanban Board Styles ─── */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');

:root {
    --kb-primary: #2AABB3;
    --kb-primary-dark: #1E8F96;
    --kb-primary-darker: #187278;
    --kb-primary-light: #E6F7F8;
    --kb-success: #52C41A;
    --kb-warning: #FAAD14;
    --kb-danger: #FF4D4F;
    --kb-text: #1F2937;
    --kb-text-secondary: #6B7280;
    --kb-border: #E5E7EB;
    --kb-bg: #F3F4F6;
    --kb-white: #FFFFFF;
    --kb-shadow: 0 1px 3px rgba(0,0,0,0.1);
    --kb-shadow-lg: 0 4px 15px rgba(0,0,0,0.12);
    --kb-radius: 8px;
}

.kb-wrapper {
    font-family: 'Poppins', sans-serif;
    color: var(--kb-text);
    min-height: 100vh;
    background: var(--kb-bg);
}

/* ─── Header Banner ─── */
.kb-banner {
    background: linear-gradient(135deg, var(--kb-primary) 0%, var(--kb-primary-darker) 100%);
    padding: 20px 30px;
    color: white;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
}
.kb-banner h1 { margin: 0; font-size: 22px; font-weight: 600; }
.kb-banner .kb-breadcrumb { font-size: 13px; opacity: 0.85; margin-top: 2px; }
.kb-banner-actions { display: flex; gap: 10px; align-items: center; }
.kb-banner-actions select,
.kb-banner-actions button {
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    border: 1px solid rgba(255,255,255,0.3);
    background: rgba(255,255,255,0.15);
    color: white;
    padding: 7px 14px;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s;
}
.kb-banner-actions select option { color: #333; background: white; }
.kb-banner-actions button:hover { background: rgba(255,255,255,0.3); }
.kb-btn-solid {
    background: white !important;
    color: var(--kb-primary-dark) !important;
    font-weight: 500;
    border: none !important;
}
.kb-btn-solid:hover { opacity: 0.9; }

/* ─── Stats Bar ─── */
.kb-stats-bar {
    display: flex;
    gap: 16px;
    padding: 16px 30px;
    background: white;
    border-bottom: 1px solid var(--kb-border);
    flex-wrap: wrap;
}
.kb-stat {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    background: var(--kb-bg);
    border-radius: 8px;
    min-width: 130px;
}
.kb-stat-icon {
    width: 38px; height: 38px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
}
.kb-stat-value { font-size: 20px; font-weight: 700; line-height: 1; }
.kb-stat-label { font-size: 11px; color: var(--kb-text-secondary); text-transform: uppercase; letter-spacing: 0.5px; }

/* ─── Board Container ─── */
.kb-board {
    display: flex;
    gap: 16px;
    padding: 20px 24px;
    overflow-x: auto;
    min-height: calc(100vh - 200px);
    align-items: flex-start;
}

/* ─── Column ─── */
.kb-column {
    min-width: 300px;
    max-width: 320px;
    background: var(--kb-white);
    border-radius: var(--kb-radius);
    box-shadow: var(--kb-shadow);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    max-height: calc(100vh - 230px);
    border-top: 3px solid var(--kb-border);
}
.kb-column-header {
    padding: 14px 16px 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--kb-border);
}
.kb-column-title {
    font-size: 14px;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}
.kb-column-count {
    background: var(--kb-bg);
    color: var(--kb-text-secondary);
    font-size: 12px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 10px;
    min-width: 22px;
    text-align: center;
}
.kb-column-menu {
    position: relative;
}
.kb-column-menu-btn {
    background: none; border: none; cursor: pointer;
    color: var(--kb-text-secondary); font-size: 18px;
    padding: 4px 6px; border-radius: 4px;
    transition: background 0.15s;
}
.kb-column-menu-btn:hover { background: var(--kb-bg); }
.kb-column-dropdown {
    position: absolute;
    right: 0; top: 100%;
    background: white;
    border: 1px solid var(--kb-border);
    border-radius: 8px;
    box-shadow: var(--kb-shadow-lg);
    min-width: 160px;
    z-index: 100;
    display: none;
    overflow: hidden;
}
.kb-column-dropdown.show { display: block; }
.kb-column-dropdown button {
    display: block; width: 100%; text-align: left;
    padding: 10px 14px; border: none; background: none;
    font-family: 'Poppins', sans-serif; font-size: 13px;
    cursor: pointer; color: var(--kb-text);
    transition: background 0.15s;
}
.kb-column-dropdown button:hover { background: var(--kb-bg); }
.kb-column-dropdown button.danger { color: var(--kb-danger); }
.kb-column-dropdown button.danger:hover { background: #FEF2F2; }

.kb-column-body {
    padding: 8px;
    flex: 1;
    overflow-y: auto;
    min-height: 60px;
}
.kb-column-body.drag-over {
    background: var(--kb-primary-light);
    border: 2px dashed var(--kb-primary);
    border-radius: 6px;
}

/* ─── Card ─── */
.kb-card {
    background: white;
    border: 1px solid var(--kb-border);
    border-radius: 8px;
    padding: 12px 14px;
    margin-bottom: 8px;
    cursor: grab;
    transition: box-shadow 0.2s, transform 0.15s;
    position: relative;
}
.kb-card:hover { box-shadow: var(--kb-shadow-lg); transform: translateY(-1px); }
.kb-card.dragging { opacity: 0.5; transform: rotate(2deg); }
.kb-card-title {
    font-size: 13px;
    font-weight: 500;
    margin-bottom: 8px;
    line-height: 1.4;
    word-break: break-word;
}
.kb-card-labels {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.kb-card-label {
    font-size: 10px;
    padding: 2px 8px;
    border-radius: 10px;
    font-weight: 500;
    color: white;
}
.kb-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 11px;
    color: var(--kb-text-secondary);
    gap: 8px;
}
.kb-card-priority {
    width: 8px; height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}
.priority-urgent { background: var(--kb-danger); }
.priority-high { background: #F97316; }
.priority-medium { background: var(--kb-warning); }
.priority-low { background: var(--kb-success); }

.kb-card-due { display: flex; align-items: center; gap: 3px; }
.kb-card-due.overdue { color: var(--kb-danger); font-weight: 500; }

.kb-card-actions {
    position: absolute; top: 6px; right: 6px;
    display: none;
    gap: 2px;
}
.kb-card:hover .kb-card-actions { display: flex; }
.kb-card-actions button {
    background: var(--kb-bg); border: none; cursor: pointer;
    width: 26px; height: 26px; border-radius: 4px;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; color: var(--kb-text-secondary);
    transition: all 0.15s;
}
.kb-card-actions button:hover { background: var(--kb-primary-light); color: var(--kb-primary-dark); }
.kb-card-actions button.delete:hover { background: #FEF2F2; color: var(--kb-danger); }

/* ─── Add Card ─── */
.kb-add-card-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    border: none;
    background: none;
    color: var(--kb-text-secondary);
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    cursor: pointer;
    width: 100%;
    border-radius: 0 0 8px 8px;
    transition: all 0.15s;
}
.kb-add-card-btn:hover { background: var(--kb-bg); color: var(--kb-primary-dark); }

.kb-add-card-form {
    padding: 8px;
    display: none;
}
.kb-add-card-form textarea {
    width: 100%; min-height: 60px;
    border: 1px solid var(--kb-border);
    border-radius: 6px;
    padding: 10px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    resize: vertical;
    box-sizing: border-box;
    outline: none;
    transition: border 0.2s;
}
.kb-add-card-form textarea:focus { border-color: var(--kb-primary); }
.kb-add-card-form .kb-form-actions {
    display: flex; gap: 8px; margin-top: 8px;
}

/* ─── Add Column ─── */
.kb-add-column {
    min-width: 280px;
    flex-shrink: 0;
}
.kb-add-column-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 20px;
    background: rgba(42,171,179,0.08);
    border: 2px dashed var(--kb-primary);
    border-radius: var(--kb-radius);
    color: var(--kb-primary-dark);
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    width: 100%;
    transition: all 0.2s;
    box-sizing: border-box;
}
.kb-add-column-btn:hover { background: rgba(42,171,179,0.15); }

/* ─── Buttons ─── */
.kb-btn {
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    padding: 7px 16px;
    border-radius: 6px;
    border: none;
    cursor: pointer;
    font-weight: 500;
    transition: all 0.2s;
}
.kb-btn-primary { background: var(--kb-primary); color: white; }
.kb-btn-primary:hover { background: var(--kb-primary-dark); }
.kb-btn-ghost { background: transparent; color: var(--kb-text-secondary); }
.kb-btn-ghost:hover { background: var(--kb-bg); }
.kb-btn-danger { background: var(--kb-danger); color: white; }

/* ─── Modal ─── */
.kb-modal-overlay {
    position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.5);
    z-index: 999999;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.kb-modal-overlay.show { display: flex !important; }
.kb-modal {
    background: white;
    border-radius: 12px;
    width: 100%;
    max-width: 560px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.25);
    max-height: 90vh;
    overflow-y: auto;
    animation: slideUp 0.25s ease;
    position: relative;
    z-index: 1000000;
    margin: auto;
}
@keyframes slideUp {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}
.kb-modal-header {
    padding: 20px 24px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--kb-border);
}
.kb-modal-header h3 { margin: 0; font-size: 18px; font-weight: 600; }
.kb-modal-close {
    background: none; border: none; cursor: pointer;
    font-size: 22px; color: var(--kb-text-secondary);
    width: 32px; height: 32px; border-radius: 6px;
    display: flex; align-items: center; justify-content: center;
}
.kb-modal-close:hover { background: var(--kb-bg); }
.kb-modal-body { padding: 20px 24px; }
.kb-modal-footer {
    padding: 16px 24px;
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    border-top: 1px solid var(--kb-border);
}

/* ─── Form Fields ─── */
.kb-field { margin-bottom: 16px; }
.kb-field label {
    display: block;
    font-size: 13px;
    font-weight: 500;
    margin-bottom: 6px;
    color: var(--kb-text);
}
.kb-field input, .kb-field textarea, .kb-field select {
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--kb-border);
    border-radius: 6px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    box-sizing: border-box;
    outline: none;
    transition: border 0.2s;
}
.kb-field input:focus, .kb-field textarea:focus, .kb-field select:focus { border-color: var(--kb-primary); }
.kb-field textarea { min-height: 80px; resize: vertical; }

/* ─── Wizard ─── */
.kb-wizard-overlay {
    position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.6);
    z-index: 999999;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.kb-wizard-overlay.show { display: flex !important; }
.kb-wizard {
    background: white;
    border-radius: 16px;
    width: 100%;
    max-width: 640px;
    box-shadow: 0 25px 70px rgba(0,0,0,0.3);
    overflow: hidden;
    animation: slideUp 0.3s ease;
    position: relative;
    z-index: 1000000;
    margin: auto;
}
.kb-wizard-banner {
    background: linear-gradient(135deg, var(--kb-primary) 0%, var(--kb-primary-darker) 100%);
    padding: 32px 36px 28px;
    color: white;
}
.kb-wizard-banner h2 { margin: 0 0 8px; font-size: 24px; font-weight: 700; }
.kb-wizard-banner p { margin: 0; opacity: 0.85; font-size: 14px; }

.kb-wizard-steps {
    display: flex;
    padding: 0 36px;
    margin-top: -16px;
}
.kb-wizard-step {
    flex: 1;
    text-align: center;
    position: relative;
    padding-top: 24px;
}
.kb-wizard-step-dot {
    width: 32px; height: 32px;
    border-radius: 50%;
    background: white;
    border: 3px solid var(--kb-border);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
    color: var(--kb-text-secondary);
    position: relative;
    z-index: 2;
    transition: all 0.3s;
}
.kb-wizard-step.active .kb-wizard-step-dot {
    background: var(--kb-primary);
    border-color: var(--kb-primary);
    color: white;
}
.kb-wizard-step.completed .kb-wizard-step-dot {
    background: var(--kb-success);
    border-color: var(--kb-success);
    color: white;
}
.kb-wizard-step-label {
    font-size: 12px;
    color: var(--kb-text-secondary);
    margin-top: 6px;
    font-weight: 500;
}
.kb-wizard-step.active .kb-wizard-step-label { color: var(--kb-primary-dark); font-weight: 600; }

.kb-wizard-body { padding: 28px 36px; }
.kb-wizard-page { display: none; }
.kb-wizard-page.active { display: block; }

.kb-wizard-footer {
    padding: 16px 36px 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* ─── Template Cards ─── */
.kb-template-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
.kb-template-card {
    border: 2px solid var(--kb-border);
    border-radius: 10px;
    padding: 18px;
    cursor: pointer;
    transition: all 0.2s;
}
.kb-template-card:hover { border-color: var(--kb-primary); background: var(--kb-primary-light); }
.kb-template-card.selected { border-color: var(--kb-primary); background: var(--kb-primary-light); }
.kb-template-card h4 { margin: 0 0 6px; font-size: 15px; font-weight: 600; }
.kb-template-card p { margin: 0; font-size: 12px; color: var(--kb-text-secondary); }
.kb-template-icon { font-size: 28px; margin-bottom: 10px; }

/* ─── Column Preview ─── */
.kb-col-preview {
    display: flex; gap: 6px; flex-wrap: wrap; margin-top: 12px;
}
.kb-col-chip {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    background: var(--kb-bg);
    border-radius: 6px;
    font-size: 13px;
    font-weight: 500;
}
.kb-col-chip .dot {
    width: 10px; height: 10px;
    border-radius: 50%;
}
.kb-col-chip .remove-col {
    background: none; border: none; cursor: pointer;
    color: var(--kb-text-secondary); font-size: 16px;
    padding: 0 2px; margin-left: 2px;
}
.kb-col-chip .remove-col:hover { color: var(--kb-danger); }

/* Add custom column input */
.kb-add-col-inline {
    display: flex; gap: 8px; margin-top: 12px;
}
.kb-add-col-inline input {
    flex: 1; padding: 8px 12px;
    border: 1px solid var(--kb-border);
    border-radius: 6px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    outline: none;
}
.kb-add-col-inline input:focus { border-color: var(--kb-primary); }

/* ─── Activity Panel ─── */
.kb-activity-panel {
    position: fixed; right: -400px; top: 0; bottom: 0;
    width: 380px;
    background: white;
    box-shadow: -4px 0 20px rgba(0,0,0,0.1);
    z-index: 999998;
    transition: right 0.3s ease;
    display: flex;
    flex-direction: column;
}
.kb-activity-panel.open { right: 0; }
.kb-activity-header {
    padding: 20px;
    border-bottom: 1px solid var(--kb-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.kb-activity-header h3 { margin: 0; font-size: 16px; font-weight: 600; }
.kb-activity-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px 20px;
}
.kb-activity-item {
    display: flex;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--kb-border);
}
.kb-activity-item:last-child { border-bottom: none; }
.kb-activity-dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--kb-primary);
    margin-top: 6px;
    flex-shrink: 0;
}
.kb-activity-text { font-size: 13px; line-height: 1.5; }
.kb-activity-time { font-size: 11px; color: var(--kb-text-secondary); margin-top: 2px; }

/* ─── Empty State ─── */
.kb-empty-state {
    text-align: center;
    padding: 60px 30px;
}
.kb-empty-state-icon { font-size: 64px; margin-bottom: 16px; }
.kb-empty-state h3 { font-size: 20px; margin: 0 0 8px; }
.kb-empty-state p { color: var(--kb-text-secondary); margin: 0 0 20px; font-size: 14px; }

/* ─── Color pickers for labels ─── */
.kb-label-colors { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.kb-label-color {
    width: 24px; height: 24px;
    border-radius: 4px;
    cursor: pointer;
    border: 2px solid transparent;
    transition: all 0.15s;
}
.kb-label-color:hover { transform: scale(1.15); }
.kb-label-color.selected { border-color: var(--kb-text); }

/* ─── Scrollbar ─── */
.kb-column-body::-webkit-scrollbar { width: 4px; }
.kb-column-body::-webkit-scrollbar-track { background: transparent; }
.kb-column-body::-webkit-scrollbar-thumb { background: var(--kb-border); border-radius: 4px; }
.kb-column-body::-webkit-scrollbar-thumb:hover { background: #C0C0C0; }

/* ─── Filter bar ─── */
.kb-filter-bar {
    display: flex;
    gap: 10px;
    padding: 10px 30px;
    background: white;
    border-bottom: 1px solid var(--kb-border);
    align-items: center;
    flex-wrap: wrap;
}
.kb-filter-bar input {
    padding: 7px 12px;
    border: 1px solid var(--kb-border);
    border-radius: 6px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    outline: none;
    width: 240px;
    transition: border 0.2s;
}
.kb-filter-bar input:focus { border-color: var(--kb-primary); }
.kb-filter-bar select {
    padding: 7px 12px;
    border: 1px solid var(--kb-border);
    border-radius: 6px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    outline: none;
    background: white;
    cursor: pointer;
}

/* ─── Responsive ─── */
@media (max-width: 768px) {
    .kb-banner { padding: 15px 16px; }
    .kb-banner h1 { font-size: 18px; }
    .kb-board { padding: 12px; }
    .kb-column { min-width: 260px; }
    .kb-stats-bar { padding: 12px 16px; }
    .kb-wizard { max-width: 95vw; }
    .kb-wizard-body { padding: 20px; }
    .kb-wizard-banner { padding: 24px 20px; }
    .kb-template-grid { grid-template-columns: 1fr; }
    .rpt-chart-row { grid-template-columns: 1fr; }
    .rpt-kpi-grid { grid-template-columns: 1fr 1fr; }
    .kb-reports-panel { width: 100%; max-width: 100%; margin: 0; border-radius: 0; height: 100vh; }
}

/* ─── Reports Overlay ─── */
.kb-reports-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.55);
    z-index: 999999;
    display: none;
    align-items: flex-start;
    justify-content: center;
    padding: 20px;
    overflow-y: auto;
}
.kb-reports-overlay.show { display: flex !important; }

.kb-reports-panel {
    background: #F8F9FB;
    border-radius: 16px;
    width: 100%;
    max-width: 1100px;
    box-shadow: 0 25px 80px rgba(0,0,0,0.25);
    animation: slideUp 0.3s ease;
    position: relative;
    z-index: 1000000;
    margin: 10px auto;
    max-height: 95vh;
    overflow-y: auto;
}
.kb-reports-header {
    position: sticky;
    top: 0;
    background: white;
    padding: 20px 28px;
    border-bottom: 1px solid var(--kb-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-radius: 16px 16px 0 0;
    z-index: 10;
}
.kb-reports-body {
    padding: 24px 28px 32px;
}

/* KPI Cards */
.rpt-section { margin-bottom: 24px; }
.rpt-section-title {
    font-size: 15px;
    font-weight: 600;
    margin: 0 0 14px;
    color: var(--kb-text);
    display: flex;
    align-items: center;
    gap: 8px;
}
.rpt-kpi-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 14px;
}
.rpt-kpi {
    background: white;
    border-radius: 12px;
    padding: 18px 16px;
    box-shadow: 0 1px 4px rgba(0,0,0,0.06);
    border-left: 4px solid var(--kb-primary);
    transition: transform 0.2s;
}
.rpt-kpi:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.rpt-kpi-value {
    font-size: 28px;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 4px;
}
.rpt-kpi-label {
    font-size: 12px;
    color: var(--kb-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    font-weight: 500;
}
.rpt-kpi-sub {
    font-size: 11px;
    color: var(--kb-text-secondary);
    margin-top: 6px;
    display: flex;
    align-items: center;
    gap: 4px;
}
.rpt-kpi-sub .up { color: var(--kb-success); font-weight: 600; }
.rpt-kpi-sub .down { color: var(--kb-danger); font-weight: 600; }

/* Chart Cards */
.rpt-chart-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-bottom: 20px;
}
.rpt-chart-card {
    background: white;
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
.rpt-chart-card.rpt-full-width {
    margin-bottom: 20px;
}
.rpt-chart-title {
    font-size: 15px;
    font-weight: 600;
    margin: 0 0 2px;
    color: var(--kb-text);
}
.rpt-chart-subtitle {
    font-size: 12px;
    color: var(--kb-text-secondary);
    margin: 0 0 16px;
}
.rpt-chart-container {
    position: relative;
    height: 260px;
}
.rpt-chart-container-wide {
    position: relative;
    height: 300px;
}

/* Cycle Time Stats */
.rpt-cycle-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin-bottom: 16px;
}
.rpt-cycle-stat {
    text-align: center;
    padding: 12px 8px;
    background: var(--kb-bg);
    border-radius: 8px;
}
.rpt-cycle-stat-value {
    font-size: 22px;
    font-weight: 700;
    color: var(--kb-primary-dark);
}
.rpt-cycle-stat-label {
    font-size: 11px;
    color: var(--kb-text-secondary);
    text-transform: uppercase;
    margin-top: 2px;
}

/* Overdue Table */
.rpt-table-wrap {
    overflow-x: auto;
    margin-top: 12px;
}
.rpt-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.rpt-table th {
    text-align: left;
    padding: 10px 14px;
    background: var(--kb-bg);
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    color: var(--kb-text-secondary);
    border-bottom: 2px solid var(--kb-border);
}
.rpt-table td {
    padding: 10px 14px;
    border-bottom: 1px solid var(--kb-border);
    color: var(--kb-text);
}
.rpt-table tr:hover td { background: #FAFAFA; }
.rpt-priority-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 600;
    text-transform: capitalize;
}
.rpt-priority-urgent { background: #FEE2E2; color: #DC2626; }
.rpt-priority-high { background: #FFEDD5; color: #EA580C; }
.rpt-priority-medium { background: #FEF3C7; color: #D97706; }
.rpt-priority-low { background: #DCFCE7; color: #16A34A; }

/* Print styles */
@media print {
    .kb-reports-overlay { position: static; background: none; padding: 0; display: block !important; overflow: visible; }
    .kb-reports-panel { max-height: none; box-shadow: none; border-radius: 0; max-width: 100%; overflow: visible; }
    .kb-reports-header button { display: none; }
    .kb-wrapper > *:not(.kb-reports-overlay) { display: none !important; }
    .rpt-chart-row { break-inside: avoid; }
    .rpt-chart-card { break-inside: avoid; }
}
</style>

<div class="kb-wrapper" id="kbApp">
    <!-- Loading -->
    <div id="kbLoading" style="display:flex;align-items:center;justify-content:center;height:60vh;">
        <div style="text-align:center;">
            <div style="width:44px;height:44px;border:4px solid #E5E7EB;border-top-color:#2AABB3;border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 16px;"></div>
            <p style="font-family:Poppins,sans-serif;color:#6B7280;font-size:14px;">Loading Kanban Board...</p>
        </div>
    </div>
    <style>@keyframes spin { to { transform: rotate(360deg); } }</style>

    <!-- Main App (hidden until loaded) -->
    <div id="kbMain" style="display:none;">
        <!-- Banner -->
        <div class="kb-banner">
            <div>
                <div class="kb-breadcrumb">Projects &gt; <span id="kbBoardName">Board</span></div>
                <h1>📋 Kanban Board</h1>
            </div>
            <div class="kb-banner-actions">
                <select id="kbBoardSelect" onchange="KB.switchBoard(this.value)"></select>
                <button onclick="KB.showNewBoardWizard()" class="kb-btn-solid">＋ New Board</button>
                <button onclick="KB.toggleActivity()" title="Activity Log">📝 Activity</button>
                <button onclick="KB.openReports()" title="Board Reports" class="kb-btn-solid" style="background:linear-gradient(135deg,#667eea,#764ba2)!important;color:white!important;">📊 Reports</button>
                <button onclick="KB.deleteBoard()" title="Delete Board" style="background:rgba(255,77,79,0.3);">🗑</button>
            </div>
        </div>

        <!-- Stats Bar -->
        <div class="kb-stats-bar" id="kbStats">
            <div class="kb-stat">
                <div class="kb-stat-icon" style="background:#E6F7F8;color:#2AABB3;">📋</div>
                <div><div class="kb-stat-value" id="statTotal">0</div><div class="kb-stat-label">Total Tasks</div></div>
            </div>
            <div class="kb-stat">
                <div class="kb-stat-icon" style="background:#D1FAE5;color:#52C41A;">✅</div>
                <div><div class="kb-stat-value" id="statDone">0</div><div class="kb-stat-label">Completed</div></div>
            </div>
            <div class="kb-stat">
                <div class="kb-stat-icon" style="background:#FEF3C7;color:#F59E0B;">🔥</div>
                <div><div class="kb-stat-value" id="statUrgent">0</div><div class="kb-stat-label">Urgent</div></div>
            </div>
            <div class="kb-stat">
                <div class="kb-stat-icon" style="background:#FEE2E2;color:#FF4D4F;">⏰</div>
                <div><div class="kb-stat-value" id="statOverdue">0</div><div class="kb-stat-label">Overdue</div></div>
            </div>
            <div class="kb-stat" style="margin-left:auto;">
                <div>
                    <div class="kb-stat-value" id="statProgress" style="font-size:16px;">0%</div>
                    <div class="kb-stat-label">Progress</div>
                </div>
                <div style="width:100px;height:8px;background:#E5E7EB;border-radius:4px;overflow:hidden;">
                    <div id="statProgressBar" style="height:100%;background:#52C41A;border-radius:4px;transition:width 0.5s;width:0%;"></div>
                </div>
            </div>
        </div>

        <!-- Filter Bar -->
        <div class="kb-filter-bar">
            <input type="text" id="kbSearch" placeholder="🔍 Search cards..." oninput="KB.filterCards()">
            <select id="kbPriorityFilter" onchange="KB.filterCards()">
                <option value="">All Priorities</option>
                <option value="urgent">🔴 Urgent</option>
                <option value="high">🟠 High</option>
                <option value="medium">🟡 Medium</option>
                <option value="low">🟢 Low</option>
            </select>
        </div>

        <!-- Board -->
        <div class="kb-board" id="kbBoard"></div>
    </div>

    <!-- Setup Wizard -->
    <div class="kb-wizard-overlay" id="kbWizard">
        <div class="kb-wizard">
            <div class="kb-wizard-banner">
                <h2>Welcome to Kanban Board</h2>
                <p>Let's set up your first project board in 3 quick steps.</p>
            </div>
            <div class="kb-wizard-steps">
                <div class="kb-wizard-step active" id="wizStep1">
                    <div class="kb-wizard-step-dot">1</div>
                    <div class="kb-wizard-step-label">Template</div>
                </div>
                <div class="kb-wizard-step" id="wizStep2">
                    <div class="kb-wizard-step-dot">2</div>
                    <div class="kb-wizard-step-label">Configure</div>
                </div>
                <div class="kb-wizard-step" id="wizStep3">
                    <div class="kb-wizard-step-dot">3</div>
                    <div class="kb-wizard-step-label">Finish</div>
                </div>
            </div>
            <div class="kb-wizard-body">
                <!-- Step 1: Choose Template -->
                <div class="kb-wizard-page active" id="wizPage1">
                    <h3 style="margin:0 0 4px;font-size:17px;">Choose a board template</h3>
                    <p style="margin:0 0 16px;color:var(--kb-text-secondary);font-size:13px;">Select a template that best fits your workflow</p>
                    <div class="kb-template-grid">
                        <div class="kb-template-card selected" data-template="kanban" onclick="KB.selectTemplate(this)">
                            <div class="kb-template-icon">📋</div>
                            <h4>Kanban Board</h4>
                            <p>Classic To Do → In Progress → Done workflow for general task management</p>
                        </div>
                        <div class="kb-template-card" data-template="project" onclick="KB.selectTemplate(this)">
                            <div class="kb-template-icon">🏗️</div>
                            <h4>Project Management</h4>
                            <p>Backlog → Planning → In Progress → Review → Done for structured projects</p>
                        </div>
                        <div class="kb-template-card" data-template="dev" onclick="KB.selectTemplate(this)">
                            <div class="kb-template-icon">💻</div>
                            <h4>Software Development</h4>
                            <p>Backlog → In Dev → Code Review → QA → Deployed for dev teams</p>
                        </div>
                        <div class="kb-template-card" data-template="custom" onclick="KB.selectTemplate(this)">
                            <div class="kb-template-icon">⚙️</div>
                            <h4>Custom Board</h4>
                            <p>Start from scratch and define your own workflow columns</p>
                        </div>
                    </div>
                </div>

                <!-- Step 2: Configure -->
                <div class="kb-wizard-page" id="wizPage2">
                    <h3 style="margin:0 0 4px;font-size:17px;">Configure your board</h3>
                    <p style="margin:0 0 16px;color:var(--kb-text-secondary);font-size:13px;">Name your board and customise the columns</p>
                    <div class="kb-field">
                        <label>Board Name</label>
                        <input type="text" id="wizBoardName" value="My Project Board" placeholder="e.g. Q1 Sprint, Website Redesign">
                    </div>
                    <div class="kb-field">
                        <label>Description (optional)</label>
                        <textarea id="wizBoardDesc" rows="2" placeholder="What is this board for?"></textarea>
                    </div>
                    <div class="kb-field">
                        <label>Workflow Columns</label>
                        <div class="kb-col-preview" id="wizColumnsPreview"></div>
                        <div class="kb-add-col-inline" id="wizAddCol">
                            <input type="text" id="wizNewColName" placeholder="Add a column..." onkeypress="if(event.key==='Enter')KB.addWizardColumn()">
                            <button class="kb-btn kb-btn-primary" onclick="KB.addWizardColumn()">Add</button>
                        </div>
                    </div>
                </div>

                <!-- Step 3: Ready -->
                <div class="kb-wizard-page" id="wizPage3">
                    <div style="text-align:center;padding:20px 0;">
                        <div style="font-size:64px;margin-bottom:16px;">🎉</div>
                        <h3 style="margin:0 0 8px;font-size:20px;">You're all set!</h3>
                        <p style="margin:0 0 8px;color:var(--kb-text-secondary);font-size:14px;">Your board "<strong id="wizFinalName"></strong>" is ready to go.</p>
                        <div id="wizFinalColumns" style="display:flex;gap:6px;justify-content:center;flex-wrap:wrap;margin-top:16px;"></div>
                        <p style="margin:20px 0 0;color:var(--kb-text-secondary);font-size:13px;">
                            💡 <strong>Quick tips:</strong> Drag cards between columns, click + to add tasks, and use filters to find cards quickly.
                        </p>
                    </div>
                </div>
            </div>
            <div class="kb-wizard-footer">
                <button class="kb-btn kb-btn-ghost" id="wizPrevBtn" onclick="KB.wizardPrev()" style="visibility:hidden;">← Back</button>
                <button class="kb-btn kb-btn-primary" id="wizNextBtn" onclick="KB.wizardNext()" style="padding:9px 28px;">Next →</button>
            </div>
        </div>
    </div>

    <!-- Card Edit Modal -->
    <div class="kb-modal-overlay" id="kbCardModal">
        <div class="kb-modal">
            <div class="kb-modal-header">
                <h3 id="cardModalTitle">Edit Card</h3>
                <button class="kb-modal-close" onclick="KB.closeCardModal()">×</button>
            </div>
            <div class="kb-modal-body">
                <input type="hidden" id="editCardId">
                <input type="hidden" id="editCardColumnId">
                <input type="hidden" id="editCardBoardId">
                <div class="kb-field">
                    <label>Title <span style="color:var(--kb-danger);">*</span></label>
                    <input type="text" id="editCardTitle" placeholder="What needs to be done?">
                </div>
                <div class="kb-field">
                    <label>Description</label>
                    <textarea id="editCardDesc" placeholder="Add details, links, or notes..."></textarea>
                </div>
                <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
                    <div class="kb-field">
                        <label>Priority</label>
                        <select id="editCardPriority">
                            <option value="low">🟢 Low</option>
                            <option value="medium" selected>🟡 Medium</option>
                            <option value="high">🟠 High</option>
                            <option value="urgent">🔴 Urgent</option>
                        </select>
                    </div>
                    <div class="kb-field">
                        <label>Due Date</label>
                        <input type="date" id="editCardDue">
                    </div>
                </div>
                <div class="kb-field">
                    <label>Assigned To</label>
                    <select id="editCardAssigned">
                        <option value="">Unassigned</option>
                    </select>
                </div>
                <div class="kb-field">
                    <label>Labels</label>
                    <input type="text" id="editCardLabels" placeholder="Comma separated: bug, feature, design">
                </div>
            </div>
            <div class="kb-modal-footer">
                <button class="kb-btn kb-btn-ghost" onclick="KB.closeCardModal()">Cancel</button>
                <button class="kb-btn kb-btn-primary" onclick="KB.saveCard()">Save Card</button>
            </div>
        </div>
    </div>

    <!-- Activity Panel -->
    <div class="kb-activity-panel" id="kbActivityPanel">
        <div class="kb-activity-header">
            <h3>📝 Activity Log</h3>
            <button class="kb-modal-close" onclick="KB.toggleActivity()">×</button>
        </div>
        <div class="kb-activity-body" id="kbActivityBody">
            <p style="color:var(--kb-text-secondary);text-align:center;padding:40px 0;">Loading activity...</p>
        </div>
    </div>

    <!-- Reports Overlay -->
    <div class="kb-reports-overlay" id="kbReportsOverlay">
        <div class="kb-reports-panel">
            <div class="kb-reports-header">
                <div>
                    <h2 style="margin:0;font-size:20px;font-weight:700;display:flex;align-items:center;gap:10px;">📊 Board Analytics & Reports</h2>
                    <p style="margin:4px 0 0;font-size:13px;color:var(--kb-text-secondary);" id="rptBoardName">Board Report</p>
                </div>
                <div style="display:flex;align-items:center;gap:10px;">
                    <button class="kb-btn kb-btn-ghost" onclick="KB.printReports()" title="Print Report">🖨️ Print</button>
                    <button class="kb-modal-close" onclick="KB.closeReports()">×</button>
                </div>
            </div>

            <div class="kb-reports-body" id="kbReportsBody">
                <!-- Loading spinner -->
                <div id="rptLoading" style="text-align:center;padding:60px;">
                    <div style="width:40px;height:40px;border:4px solid #E5E7EB;border-top-color:#2AABB3;border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 16px;"></div>
                    <p style="color:var(--kb-text-secondary);">Generating reports...</p>
                </div>

                <!-- Report Content (hidden until loaded) -->
                <div id="rptContent" style="display:none;">
                    <!-- KPI Summary Cards -->
                    <div class="rpt-section">
                        <h3 class="rpt-section-title">📋 Summary Overview</h3>
                        <div class="rpt-kpi-grid" id="rptKpiGrid"></div>
                    </div>

                    <!-- Row: Workflow Distribution + Priority Breakdown -->
                    <div class="rpt-chart-row">
                        <div class="rpt-chart-card">
                            <h3 class="rpt-chart-title">📊 Workflow Distribution</h3>
                            <p class="rpt-chart-subtitle">Cards across each column</p>
                            <div class="rpt-chart-container"><canvas id="chartColumnDist"></canvas></div>
                        </div>
                        <div class="rpt-chart-card">
                            <h3 class="rpt-chart-title">🎯 Priority Breakdown</h3>
                            <p class="rpt-chart-subtitle">Task distribution by priority level</p>
                            <div class="rpt-chart-container"><canvas id="chartPriority"></canvas></div>
                        </div>
                    </div>

                    <!-- Created vs Completed Trend -->
                    <div class="rpt-chart-card rpt-full-width">
                        <h3 class="rpt-chart-title">📈 Created vs Completed Trend</h3>
                        <p class="rpt-chart-subtitle">Last 30 days card activity</p>
                        <div class="rpt-chart-container-wide"><canvas id="chartTrend"></canvas></div>
                    </div>

                    <!-- Cumulative Flow Diagram -->
                    <div class="rpt-chart-card rpt-full-width">
                        <h3 class="rpt-chart-title">🌊 Cumulative Flow Diagram</h3>
                        <p class="rpt-chart-subtitle">Cards across workflow stages over the last 14 days</p>
                        <div class="rpt-chart-container-wide"><canvas id="chartCumFlow"></canvas></div>
                    </div>

                    <!-- Row: Assignee Workload + Cycle Time -->
                    <div class="rpt-chart-row">
                        <div class="rpt-chart-card">
                            <h3 class="rpt-chart-title">👥 Assignee Workload</h3>
                            <p class="rpt-chart-subtitle">Tasks assigned vs completed per person</p>
                            <div class="rpt-chart-container"><canvas id="chartWorkload"></canvas></div>
                        </div>
                        <div class="rpt-chart-card">
                            <h3 class="rpt-chart-title">⏱️ Cycle Time</h3>
                            <p class="rpt-chart-subtitle">Average days from creation to completion</p>
                            <div class="rpt-cycle-stats" id="rptCycleStats"></div>
                            <div class="rpt-chart-container"><canvas id="chartCycle"></canvas></div>
                        </div>
                    </div>

                    <!-- Overdue Cards Table -->
                    <div class="rpt-chart-card rpt-full-width" id="rptOverdueSection" style="display:none;">
                        <h3 class="rpt-chart-title">⚠️ Overdue Cards</h3>
                        <p class="rpt-chart-subtitle">Tasks past their due date that haven't been completed</p>
                        <div class="rpt-table-wrap">
                            <table class="rpt-table" id="rptOverdueTable">
                                <thead>
                                    <tr><th>Title</th><th>Priority</th><th>Due Date</th><th>Column</th><th>Assigned</th></tr>
                                </thead>
                                <tbody id="rptOverdueBody"></tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
// ─── Kanban Board Application ───────────────────────────────
const KB = {
    currentBoard: null,
    boards: [],
    wizardStep: 1,
    wizardTemplate: 'kanban',
    wizardColumns: [],
    users: [],
    dragCard: null,

    labelColors: ['#2AABB3','#8B5CF6','#EC4899','#F97316','#22C55E','#EAB308','#06B6D4','#6366F1','#EF4444','#14B8A6'],

    templates: {
        kanban: [
            {name:'To Do', color:'#E5E7EB'},
            {name:'In Progress', color:'#DBEAFE'},
            {name:'Done', color:'#D1FAE5'}
        ],
        project: [
            {name:'Backlog', color:'#F3F4F6'},
            {name:'Planning', color:'#EDE9FE'},
            {name:'In Progress', color:'#DBEAFE'},
            {name:'Review', color:'#FEF3C7'},
            {name:'Done', color:'#D1FAE5'}
        ],
        dev: [
            {name:'Backlog', color:'#F3F4F6'},
            {name:'In Dev', color:'#DBEAFE'},
            {name:'Code Review', color:'#EDE9FE'},
            {name:'QA Testing', color:'#FEF3C7'},
            {name:'Deployed', color:'#D1FAE5'}
        ],
        custom: [
            {name:'To Do', color:'#E5E7EB'},
            {name:'Done', color:'#D1FAE5'}
        ]
    },

    // ── API helper ──
    api: function(action, data, method) {
        var opts = { method: method || 'GET', headers: {'Content-Type':'application/json'} };
        if (data && method === 'POST') opts.body = JSON.stringify(data);
        var url = 'KanbanBoard.php?api=1&action=' + action;
        if (data && method !== 'POST') {
            for (var k in data) url += '&' + k + '=' + encodeURIComponent(data[k]);
        }
        return fetch(url, opts).then(function(r) { return r.json(); });
    },

    // ── Reports ──
    chartInstances: [],
    destroyCharts: function() {
        KB.chartInstances.forEach(function(c) { if(c) c.destroy(); });
        KB.chartInstances = [];
    },
    openReports: function() {
        if (!KB.currentBoard) return;
        document.getElementById('kbReportsOverlay').classList.add('show');
        document.getElementById('rptLoading').style.display = 'block';
        document.getElementById('rptContent').style.display = 'none';
        document.getElementById('rptBoardName').textContent = KB.currentBoard.board_name + ' — Performance Report';
        KB.destroyCharts();
        KB.api('get_reports', { board_id: KB.currentBoard.id }).then(function(r) {
            if (r.success) {
                document.getElementById('rptLoading').style.display = 'none';
                document.getElementById('rptContent').style.display = 'block';
                KB.renderReports(r.reports);
            }
        });
    },
    closeReports: function() {
        document.getElementById('kbReportsOverlay').classList.remove('show');
        KB.destroyCharts();
    },
    printReports: function() { window.print(); },

    renderReports: function(rpt) {
        var s = rpt.summary;
        var total = parseInt(s.total) || 0;
        var done = parseInt(s.done) || 0;
        var pct = total > 0 ? Math.round((done / total) * 100) : 0;
        var createdWeek = parseInt(s.created_this_week) || 0;
        var doneWeek = parseInt(s.done_this_week) || 0;
        var cy = rpt.cycle_time;
        var avgDays = parseFloat(cy.avg_days) || 0;

        // KPI Cards
        document.getElementById('rptKpiGrid').innerHTML =
            KB.kpiCard('Total Tasks', total, 'var(--kb-primary)', '📋', '') +
            KB.kpiCard('Completed', done, 'var(--kb-success)', '✅', pct + '% completion rate') +
            KB.kpiCard('Created This Week', createdWeek, '#8B5CF6', '🆕', 'last 7 days') +
            KB.kpiCard('Done This Week', doneWeek, '#06B6D4', '🏆', 'last 7 days') +
            KB.kpiCard('Avg Cycle Time', avgDays > 0 ? avgDays + 'd' : '—', '#F97316', '⏱️', parseInt(cy.completed_count) + ' cards completed');

        // 1. Column distribution (bar chart)
        var colLabels = rpt.column_distribution.map(function(c) { return c.column_name; });
        var colData = rpt.column_distribution.map(function(c) { return parseInt(c.card_count); });
        var colColors = rpt.column_distribution.map(function(c, i) {
            var palette = ['#2AABB3','#8B5CF6','#F97316','#EC4899','#22C55E','#EAB308','#6366F1','#06B6D4'];
            return palette[i % palette.length];
        });
        KB.chartInstances.push(new Chart(document.getElementById('chartColumnDist'), {
            type: 'bar',
            data: {
                labels: colLabels,
                datasets: [{ label: 'Cards', data: colData, backgroundColor: colColors, borderRadius: 6, borderSkipped: false }]
            },
            options: KB.chartOpts('', false, true)
        }));

        // 2. Priority breakdown (doughnut)
        var priLabels = rpt.priority_breakdown.map(function(p) { return p.priority.charAt(0).toUpperCase() + p.priority.slice(1); });
        var priData = rpt.priority_breakdown.map(function(p) { return parseInt(p.cnt); });
        var priColors = rpt.priority_breakdown.map(function(p) {
            var map = {urgent:'#EF4444',high:'#F97316',medium:'#EAB308',low:'#22C55E'};
            return map[p.priority] || '#94A3B8';
        });
        KB.chartInstances.push(new Chart(document.getElementById('chartPriority'), {
            type: 'doughnut',
            data: {
                labels: priLabels,
                datasets: [{ data: priData, backgroundColor: priColors, borderWidth: 2, borderColor: '#fff', hoverOffset: 8 }]
            },
            options: {
                responsive: true, maintainAspectRatio: false,
                cutout: '62%',
                plugins: {
                    legend: { position: 'bottom', labels: { padding: 16, usePointStyle: true, pointStyle: 'circle', font: { family: 'Poppins', size: 12 } } }
                }
            }
        }));

        // 3. Created vs Completed trend (line chart)
        var trendDays = {};
        rpt.created_trend.forEach(function(d) { trendDays[d.day] = { created: parseInt(d.cnt), completed: 0 }; });
        rpt.completed_trend.forEach(function(d) {
            if (!trendDays[d.day]) trendDays[d.day] = { created: 0, completed: 0 };
            trendDays[d.day].completed = parseInt(d.cnt);
        });
        var sortedDays = Object.keys(trendDays).sort();
        var trendLabels = sortedDays.map(function(d) { var p=d.split('-'); var m=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; return m[parseInt(p[1])-1]+' '+parseInt(p[2]); });
        var createdLine = sortedDays.map(function(d) { return trendDays[d].created; });
        var completedLine = sortedDays.map(function(d) { return trendDays[d].completed; });
        KB.chartInstances.push(new Chart(document.getElementById('chartTrend'), {
            type: 'line',
            data: {
                labels: trendLabels,
                datasets: [
                    { label: 'Created', data: createdLine, borderColor: '#8B5CF6', backgroundColor: 'rgba(139,92,246,0.1)', fill: true, tension: 0.4, pointRadius: 3, pointHoverRadius: 6, borderWidth: 2.5 },
                    { label: 'Completed', data: completedLine, borderColor: '#22C55E', backgroundColor: 'rgba(34,197,94,0.1)', fill: true, tension: 0.4, pointRadius: 3, pointHoverRadius: 6, borderWidth: 2.5 }
                ]
            },
            options: KB.chartOpts('Cards', true, true)
        }));

        // 4. Cumulative Flow Diagram (stacked area)
        var cfLabels = rpt.cumulative_flow.map(function(d) { return d.day; });
        var flowPalette = ['#94A3B8','#8B5CF6','#3B82F6','#F59E0B','#22C55E','#06B6D4','#EC4899','#EF4444'];
        var cfDatasets = rpt.column_names.map(function(name, i) {
            return {
                label: name,
                data: rpt.cumulative_flow.map(function(d) { return d[name] || 0; }),
                backgroundColor: KB.hexToRgba(flowPalette[i % flowPalette.length], 0.45),
                borderColor: flowPalette[i % flowPalette.length],
                borderWidth: 2,
                fill: true,
                tension: 0.35,
                pointRadius: 0
            };
        });
        KB.chartInstances.push(new Chart(document.getElementById('chartCumFlow'), {
            type: 'line',
            data: { labels: cfLabels, datasets: cfDatasets },
            options: {
                responsive: true, maintainAspectRatio: false,
                scales: {
                    x: { grid: { display: false }, ticks: { font: { family: 'Poppins', size: 11 } } },
                    y: { stacked: true, beginAtZero: true, grid: { color: '#F3F4F6' }, ticks: { font: { family: 'Poppins', size: 11 } } }
                },
                plugins: { legend: { position: 'bottom', labels: { padding: 14, usePointStyle: true, pointStyle: 'circle', font: { family: 'Poppins', size: 11 } } } },
                interaction: { intersect: false, mode: 'index' }
            }
        }));

        // 5. Assignee Workload (horizontal bar)
        var wlLabels = rpt.assignee_workload.map(function(a) { return a.assignee; });
        var wlTotal = rpt.assignee_workload.map(function(a) { return parseInt(a.total) - parseInt(a.done); });
        var wlDone = rpt.assignee_workload.map(function(a) { return parseInt(a.done); });
        KB.chartInstances.push(new Chart(document.getElementById('chartWorkload'), {
            type: 'bar',
            data: {
                labels: wlLabels,
                datasets: [
                    { label: 'Completed', data: wlDone, backgroundColor: '#22C55E', borderRadius: 4, borderSkipped: false },
                    { label: 'Remaining', data: wlTotal, backgroundColor: '#E5E7EB', borderRadius: 4, borderSkipped: false }
                ]
            },
            options: {
                indexAxis: 'y',
                responsive: true, maintainAspectRatio: false,
                scales: {
                    x: { stacked: true, grid: { color: '#F3F4F6' }, ticks: { font: { family: 'Poppins', size: 11 } } },
                    y: { stacked: true, grid: { display: false }, ticks: { font: { family: 'Poppins', size: 12 } } }
                },
                plugins: { legend: { position: 'bottom', labels: { padding: 14, usePointStyle: true, pointStyle: 'circle', font: { family: 'Poppins', size: 11 } } } }
            }
        }));

        // 6. Cycle Time gauge-like display
        document.getElementById('rptCycleStats').innerHTML =
            '<div class="rpt-cycle-stat"><div class="rpt-cycle-stat-value" style="color:#22C55E;">' + (parseFloat(cy.min_days)||'—') + '</div><div class="rpt-cycle-stat-label">Fastest (days)</div></div>' +
            '<div class="rpt-cycle-stat"><div class="rpt-cycle-stat-value" style="color:#2AABB3;">' + (avgDays||'—') + '</div><div class="rpt-cycle-stat-label">Average (days)</div></div>' +
            '<div class="rpt-cycle-stat"><div class="rpt-cycle-stat-value" style="color:#F97316;">' + (parseFloat(cy.max_days)||'—') + '</div><div class="rpt-cycle-stat-label">Slowest (days)</div></div>';

        // Cycle donut
        var remain = Math.max(0, 100 - pct);
        KB.chartInstances.push(new Chart(document.getElementById('chartCycle'), {
            type: 'doughnut',
            data: {
                labels: ['Completed', 'Remaining'],
                datasets: [{ data: [pct, remain], backgroundColor: ['#2AABB3','#F3F4F6'], borderWidth: 0, hoverOffset: 4 }]
            },
            options: {
                responsive: true, maintainAspectRatio: false,
                cutout: '72%',
                plugins: {
                    legend: { display: false },
                    tooltip: { callbacks: { label: function(ctx) { return ctx.label + ': ' + ctx.raw + '%'; } } }
                }
            },
            plugins: [{
                id: 'centerText',
                afterDraw: function(chart) {
                    var w = chart.width, h = chart.height, ctx2 = chart.ctx;
                    ctx2.save();
                    ctx2.font = '700 28px Poppins';
                    ctx2.fillStyle = '#1F2937';
                    ctx2.textAlign = 'center';
                    ctx2.textBaseline = 'middle';
                    ctx2.fillText(pct + '%', w/2, h/2 - 6);
                    ctx2.font = '500 12px Poppins';
                    ctx2.fillStyle = '#6B7280';
                    ctx2.fillText('Complete', w/2, h/2 + 18);
                    ctx2.restore();
                }
            }]
        }));

        // 7. Overdue cards table
        if (rpt.overdue_cards.length > 0) {
            document.getElementById('rptOverdueSection').style.display = 'block';
            var tbody = document.getElementById('rptOverdueBody');
            tbody.innerHTML = '';
            rpt.overdue_cards.forEach(function(c) {
                var daysOver = Math.floor((new Date() - new Date(c.due_date)) / 86400000);
                tbody.innerHTML += '<tr>' +
                    '<td><strong>' + KB.escHtml(c.title) + '</strong></td>' +
                    '<td><span class="rpt-priority-badge rpt-priority-' + c.priority + '">' + c.priority + '</span></td>' +
                    '<td style="color:var(--kb-danger);font-weight:500;">' + c.due_date + ' <span style="font-size:11px;">(' + daysOver + 'd overdue)</span></td>' +
                    '<td>' + KB.escHtml(c.column_name) + '</td>' +
                    '<td>' + (c.assigned_to || '<span style="color:#aaa;">—</span>') + '</td></tr>';
            });
        } else {
            document.getElementById('rptOverdueSection').style.display = 'none';
        }
    },

    kpiCard: function(label, value, color, icon, sub) {
        return '<div class="rpt-kpi" style="border-left-color:' + color + ';">' +
            '<div class="rpt-kpi-value" style="color:' + color + ';">' + value + '</div>' +
            '<div class="rpt-kpi-label">' + icon + ' ' + KB.escHtml(label) + '</div>' +
            (sub ? '<div class="rpt-kpi-sub">' + KB.escHtml(sub) + '</div>' : '') +
            '</div>';
    },

    chartOpts: function(yLabel, showLegend, beginZero) {
        return {
            responsive: true, maintainAspectRatio: false,
            scales: {
                x: { grid: { display: false }, ticks: { font: { family: 'Poppins', size: 11 } } },
                y: { beginAtZero: beginZero !== false, grid: { color: '#F3F4F6' }, ticks: { font: { family: 'Poppins', size: 11 } }, title: yLabel ? { display: true, text: yLabel, font: { family: 'Poppins', size: 12 } } : { display: false } }
            },
            plugins: {
                legend: { display: showLegend !== false, position: 'bottom', labels: { padding: 14, usePointStyle: true, pointStyle: 'circle', font: { family: 'Poppins', size: 11 } } }
            },
            interaction: { intersect: false, mode: 'index' }
        };
    },

    hexToRgba: function(hex, alpha) {
        var r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
        return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
    },

    // ── Initialize ──
    init: function() {
        KB.api('check_setup').then(function(r) {
            if (r.success && r.has_boards) {
                KB.loadBoards();
            } else {
                document.getElementById('kbLoading').style.display = 'none';
                KB.showWizard();
            }
        });
        KB.loadUsers();
    },

    loadUsers: function() {
        KB.api('get_users').then(function(r) {
            if (r.success) {
                KB.users = r.users;
                var sel = document.getElementById('editCardAssigned');
                sel.innerHTML = '<option value="">Unassigned</option>';
                r.users.forEach(function(u) {
                    sel.innerHTML += '<option value="' + u.userid + '">' + u.realname + '</option>';
                });
            }
        });
    },

    // ── Load boards list ──
    loadBoards: function() {
        KB.api('get_boards').then(function(r) {
            if (r.success) {
                KB.boards = r.boards;
                var sel = document.getElementById('kbBoardSelect');
                sel.innerHTML = '';
                r.boards.forEach(function(b) {
                    sel.innerHTML += '<option value="' + b.id + '">' + b.board_name + '</option>';
                });
                // Load first/default board
                if (r.boards.length > 0) {
                    var boardId = KB.currentBoard ? KB.currentBoard.id : r.boards[0].id;
                    sel.value = boardId;
                    KB.loadBoard(boardId);
                }
            }
        });
    },

    // ── Load single board ──
    loadBoard: function(boardId) {
        KB.api('get_board', {board_id: boardId}).then(function(r) {
            if (r.success) {
                KB.currentBoard = r.board;
                document.getElementById('kbLoading').style.display = 'none';
                document.getElementById('kbMain').style.display = 'block';
                document.getElementById('kbBoardName').textContent = r.board.board_name;
                KB.updateStats(r.board.stats);
                KB.renderBoard(r.board);
            }
        });
    },

    // ── Switch board ──
    switchBoard: function(boardId) {
        KB.loadBoard(boardId);
    },

    // ── Update stats ──
    updateStats: function(stats) {
        var total = parseInt(stats.total) || 0;
        var done = parseInt(stats.done) || 0;
        document.getElementById('statTotal').textContent = total;
        document.getElementById('statDone').textContent = done;
        document.getElementById('statUrgent').textContent = parseInt(stats.urgent) || 0;
        document.getElementById('statOverdue').textContent = parseInt(stats.overdue) || 0;
        var pct = total > 0 ? Math.round((done / total) * 100) : 0;
        document.getElementById('statProgress').textContent = pct + '%';
        document.getElementById('statProgressBar').style.width = pct + '%';
    },

    // ── Render board ──
    renderBoard: function(board) {
        var container = document.getElementById('kbBoard');
        var html = '';

        board.columns.forEach(function(col) {
            html += '<div class="kb-column" data-column-id="' + col.id + '" style="border-top-color:' + col.color + ';">';
            html += '<div class="kb-column-header">';
            html += '<div class="kb-column-title" ondblclick="KB.renameColumn(' + col.id + ',this)">';
            html += '<span>' + KB.escHtml(col.column_name) + '</span>';
            html += '<span class="kb-column-count">' + col.cards.length + '</span>';
            html += '</div>';
            html += '<div class="kb-column-menu">';
            html += '<button class="kb-column-menu-btn" onclick="KB.toggleColumnMenu(this)">⋮</button>';
            html += '<div class="kb-column-dropdown">';
            html += '<button onclick="KB.openAddCard(' + col.id + ')">➕ Add card</button>';
            html += '<button onclick="KB.renameColumnPrompt(' + col.id + ')">✏️ Rename</button>';
            html += '<button class="danger" onclick="KB.deleteColumn(' + col.id + ')">🗑 Delete column</button>';
            html += '</div></div></div>';

            html += '<div class="kb-column-body" data-column-id="' + col.id + '" ondragover="KB.dragOver(event)" ondragleave="KB.dragLeave(event)" ondrop="KB.drop(event,' + col.id + ')">';

            col.cards.forEach(function(card) {
                html += KB.renderCard(card);
            });

            html += '</div>';

            // Quick add
            html += '<div class="kb-add-card-form" id="addForm_' + col.id + '">';
            html += '<textarea placeholder="Enter card title..." id="addInput_' + col.id + '" onkeydown="if(event.key===\'Enter\'&&!event.shiftKey){event.preventDefault();KB.quickAddCard(' + col.id + ');}"></textarea>';
            html += '<div class="kb-form-actions">';
            html += '<button class="kb-btn kb-btn-primary" onclick="KB.quickAddCard(' + col.id + ')">Add Card</button>';
            html += '<button class="kb-btn kb-btn-ghost" onclick="KB.closeAddCard(' + col.id + ')">Cancel</button>';
            html += '</div></div>';

            html += '<button class="kb-add-card-btn" onclick="KB.openAddCard(' + col.id + ')">＋ Add a card</button>';
            html += '</div>';
        });

        // Add column button
        html += '<div class="kb-add-column">';
        html += '<button class="kb-add-column-btn" onclick="KB.addColumnPrompt()">＋ Add another column</button>';
        html += '</div>';

        container.innerHTML = html;
        KB.filterCards();
    },

    renderCard: function(card) {
        var today = new Date().toISOString().split('T')[0];
        var isOverdue = card.due_date && card.due_date < today && !card.completed_at;
        var labels = card.labels ? card.labels.split(',').filter(function(l){ return l.trim(); }) : [];

        var h = '<div class="kb-card" draggable="true" data-card-id="' + card.id + '" data-priority="' + card.priority + '" data-title="' + KB.escAttr(card.title) + '" ondragstart="KB.dragStart(event,' + card.id + ')" ondragend="KB.dragEnd(event)">';

        // Actions
        h += '<div class="kb-card-actions">';
        h += '<button onclick="KB.editCard(' + card.id + ')" title="Edit">✏</button>';
        h += '<button class="delete" onclick="KB.deleteCard(' + card.id + ')" title="Delete">✕</button>';
        h += '</div>';

        // Labels
        if (labels.length > 0) {
            h += '<div class="kb-card-labels">';
            labels.forEach(function(l, i) {
                var color = KB.labelColors[i % KB.labelColors.length];
                h += '<span class="kb-card-label" style="background:' + color + ';">' + KB.escHtml(l.trim()) + '</span>';
            });
            h += '</div>';
        }

        // Title
        h += '<div class="kb-card-title">' + KB.escHtml(card.title) + '</div>';

        // Meta
        h += '<div class="kb-card-meta">';
        h += '<div style="display:flex;align-items:center;gap:6px;">';
        h += '<span class="kb-card-priority priority-' + card.priority + '" title="' + card.priority + '"></span>';
        h += '<span style="text-transform:capitalize;">' + card.priority + '</span>';
        h += '</div>';

        if (card.due_date) {
            h += '<div class="kb-card-due' + (isOverdue ? ' overdue' : '') + '">';
            h += (isOverdue ? '⚠ ' : '📅 ') + KB.formatDate(card.due_date);
            h += '</div>';
        }

        if (card.assigned_to) {
            h += '<div title="' + KB.escAttr(card.assigned_to) + '">👤 ' + KB.escHtml(card.assigned_to.substring(0, 8)) + '</div>';
        }

        h += '</div></div>';
        return h;
    },

    // ── Drag and Drop ──
    dragStart: function(e, cardId) {
        KB.dragCard = cardId;
        e.target.classList.add('dragging');
        e.dataTransfer.effectAllowed = 'move';
        e.dataTransfer.setData('text/plain', cardId);
    },
    dragEnd: function(e) {
        e.target.classList.remove('dragging');
        document.querySelectorAll('.kb-column-body').forEach(function(el) { el.classList.remove('drag-over'); });
    },
    dragOver: function(e) {
        e.preventDefault();
        e.dataTransfer.dropEffect = 'move';
        var target = e.target.closest('.kb-column-body');
        if (target) target.classList.add('drag-over');
    },
    dragLeave: function(e) {
        var target = e.target.closest('.kb-column-body');
        if (target) target.classList.remove('drag-over');
    },
    drop: function(e, columnId) {
        e.preventDefault();
        document.querySelectorAll('.kb-column-body').forEach(function(el) { el.classList.remove('drag-over'); });
        if (!KB.dragCard) return;

        // Calculate drop position
        var body = e.target.closest('.kb-column-body');
        var cards = body ? body.querySelectorAll('.kb-card') : [];
        var dropIndex = cards.length;

        KB.api('move_card', {
            card_id: KB.dragCard,
            new_column_id: columnId,
            new_order: dropIndex,
            board_id: KB.currentBoard.id
        }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
        KB.dragCard = null;
    },

    // ── Card CRUD ──
    openAddCard: function(colId) {
        document.getElementById('addForm_' + colId).style.display = 'block';
        var input = document.getElementById('addInput_' + colId);
        input.value = '';
        input.focus();
    },
    closeAddCard: function(colId) {
        document.getElementById('addForm_' + colId).style.display = 'none';
    },
    quickAddCard: function(colId) {
        var input = document.getElementById('addInput_' + colId);
        var title = input.value.trim();
        if (!title) return;
        KB.api('add_card', {
            column_id: colId,
            board_id: KB.currentBoard.id,
            title: title
        }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
    },
    editCard: function(cardId) {
        // Find card data
        var card = null;
        KB.currentBoard.columns.forEach(function(col) {
            col.cards.forEach(function(c) {
                if (parseInt(c.id) === cardId) card = c;
            });
        });
        if (!card) return;

        document.getElementById('cardModalTitle').textContent = 'Edit Card';
        document.getElementById('editCardId').value = card.id;
        document.getElementById('editCardColumnId').value = card.column_id;
        document.getElementById('editCardBoardId').value = card.board_id;
        document.getElementById('editCardTitle').value = card.title;
        document.getElementById('editCardDesc').value = card.description || '';
        document.getElementById('editCardPriority').value = card.priority;
        document.getElementById('editCardDue').value = card.due_date || '';
        document.getElementById('editCardAssigned').value = card.assigned_to || '';
        document.getElementById('editCardLabels').value = card.labels || '';

        document.getElementById('kbCardModal').classList.add('show');
    },
    openNewCardModal: function(colId) {
        document.getElementById('cardModalTitle').textContent = 'New Card';
        document.getElementById('editCardId').value = '';
        document.getElementById('editCardColumnId').value = colId;
        document.getElementById('editCardBoardId').value = KB.currentBoard.id;
        document.getElementById('editCardTitle').value = '';
        document.getElementById('editCardDesc').value = '';
        document.getElementById('editCardPriority').value = 'medium';
        document.getElementById('editCardDue').value = '';
        document.getElementById('editCardAssigned').value = '';
        document.getElementById('editCardLabels').value = '';
        document.getElementById('kbCardModal').classList.add('show');
        document.getElementById('editCardTitle').focus();
    },
    closeCardModal: function() {
        document.getElementById('kbCardModal').classList.remove('show');
    },
    saveCard: function() {
        var cardId = document.getElementById('editCardId').value;
        var data = {
            title: document.getElementById('editCardTitle').value.trim(),
            description: document.getElementById('editCardDesc').value.trim(),
            priority: document.getElementById('editCardPriority').value,
            due_date: document.getElementById('editCardDue').value || null,
            assigned_to: document.getElementById('editCardAssigned').value,
            labels: document.getElementById('editCardLabels').value.trim(),
            board_id: KB.currentBoard.id
        };
        if (!data.title) { alert('Title is required'); return; }

        if (cardId) {
            data.card_id = parseInt(cardId);
            KB.api('update_card', data, 'POST').then(function(r) {
                if (r.success) { KB.closeCardModal(); KB.loadBoard(KB.currentBoard.id); }
            });
        } else {
            data.column_id = parseInt(document.getElementById('editCardColumnId').value);
            KB.api('add_card', data, 'POST').then(function(r) {
                if (r.success) { KB.closeCardModal(); KB.loadBoard(KB.currentBoard.id); }
            });
        }
    },
    deleteCard: function(cardId) {
        if (!confirm('Delete this card?')) return;
        KB.api('delete_card', { card_id: cardId }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
    },

    // ── Column operations ──
    addColumnPrompt: function() {
        var name = prompt('New column name:');
        if (!name) return;
        KB.api('add_column', {
            board_id: KB.currentBoard.id,
            column_name: name,
            color: KB.labelColors[Math.floor(Math.random() * KB.labelColors.length)]
        }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
    },
    deleteColumn: function(colId) {
        if (!confirm('Delete this column and ALL its cards?')) return;
        KB.api('delete_column', { column_id: colId }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
        KB.closeMenus();
    },
    renameColumnPrompt: function(colId) {
        var name = prompt('New column name:');
        if (!name) return;
        KB.api('rename_column', { column_id: colId, column_name: name }, 'POST').then(function(r) {
            if (r.success) KB.loadBoard(KB.currentBoard.id);
        });
        KB.closeMenus();
    },
    renameColumn: function(colId, el) {
        var span = el.querySelector('span');
        var current = span.textContent;
        var inp = document.createElement('input');
        inp.value = current;
        inp.style.cssText = 'font-family:Poppins;font-size:14px;font-weight:600;border:1px solid #2AABB3;border-radius:4px;padding:2px 6px;width:120px;outline:none;';
        span.replaceWith(inp);
        inp.focus();
        inp.select();
        var save = function() {
            var newName = inp.value.trim() || current;
            var ns = document.createElement('span');
            ns.textContent = newName;
            inp.replaceWith(ns);
            if (newName !== current) {
                KB.api('rename_column', { column_id: colId, column_name: newName }, 'POST');
            }
        };
        inp.onblur = save;
        inp.onkeydown = function(e) { if(e.key==='Enter') inp.blur(); if(e.key==='Escape') { inp.value=current; inp.blur(); } };
    },

    toggleColumnMenu: function(btn) {
        var dd = btn.nextElementSibling;
        var isOpen = dd.classList.contains('show');
        KB.closeMenus();
        if (!isOpen) dd.classList.add('show');
    },
    closeMenus: function() {
        document.querySelectorAll('.kb-column-dropdown').forEach(function(d) { d.classList.remove('show'); });
    },

    // ── Board operations ──
    deleteBoard: function() {
        if (!KB.currentBoard) return;
        if (!confirm('Delete board "' + KB.currentBoard.board_name + '" and ALL its data? This cannot be undone.')) return;
        KB.api('delete_board', { board_id: KB.currentBoard.id }, 'POST').then(function(r) {
            if (r.success) {
                KB.currentBoard = null;
                KB.api('check_setup').then(function(r2) {
                    if (r2.success && r2.has_boards) {
                        KB.loadBoards();
                    } else {
                        document.getElementById('kbMain').style.display = 'none';
                        KB.showWizard();
                    }
                });
            }
        });
    },

    showNewBoardWizard: function() {
        KB.wizardStep = 1;
        KB.wizardTemplate = 'kanban';
        KB.showWizard();
    },

    // ── Filter ──
    filterCards: function() {
        var search = (document.getElementById('kbSearch').value || '').toLowerCase();
        var priority = document.getElementById('kbPriorityFilter').value;
        document.querySelectorAll('.kb-card').forEach(function(card) {
            var title = (card.getAttribute('data-title') || '').toLowerCase();
            var p = card.getAttribute('data-priority');
            var matchSearch = !search || title.indexOf(search) >= 0;
            var matchPriority = !priority || p === priority;
            card.style.display = (matchSearch && matchPriority) ? '' : 'none';
        });
    },

    // ── Activity ──
    toggleActivity: function() {
        var panel = document.getElementById('kbActivityPanel');
        if (panel.classList.contains('open')) {
            panel.classList.remove('open');
        } else {
            panel.classList.add('open');
            KB.loadActivity();
        }
    },
    loadActivity: function() {
        if (!KB.currentBoard) return;
        KB.api('get_activity', { board_id: KB.currentBoard.id }).then(function(r) {
            var body = document.getElementById('kbActivityBody');
            if (!r.success || r.activity.length === 0) {
                body.innerHTML = '<p style="text-align:center;color:var(--kb-text-secondary);padding:40px 0;">No activity yet. Start adding cards!</p>';
                return;
            }
            var html = '';
            r.activity.forEach(function(a) {
                var icons = {created:'🟢', moved:'🔄', updated:'✏️', deleted:'🔴'};
                html += '<div class="kb-activity-item">';
                html += '<div class="kb-activity-dot" style="background:' + (a.action_type==='created'?'#52C41A': a.action_type==='moved'?'#2AABB3':'#FAAD14') + ';"></div>';
                html += '<div>';
                html += '<div class="kb-activity-text">' + (icons[a.action_type]||'') + ' <strong>' + KB.escHtml(a.user_id) + '</strong> ' + KB.escHtml(a.action_detail) + '</div>';
                if (a.card_title) html += '<div class="kb-activity-text" style="color:var(--kb-text-secondary);font-size:12px;">Card: ' + KB.escHtml(a.card_title) + '</div>';
                html += '<div class="kb-activity-time">' + KB.timeAgo(a.created_at) + '</div>';
                html += '</div></div>';
            });
            body.innerHTML = html;
        });
    },

    // ── Wizard ──
    showWizard: function() {
        KB.wizardStep = 1;
        KB.wizardColumns = JSON.parse(JSON.stringify(KB.templates[KB.wizardTemplate]));
        KB.updateWizardUI();
        document.getElementById('kbWizard').classList.add('show');
    },
    hideWizard: function() {
        document.getElementById('kbWizard').classList.remove('show');
    },
    selectTemplate: function(el) {
        document.querySelectorAll('.kb-template-card').forEach(function(c) { c.classList.remove('selected'); });
        el.classList.add('selected');
        KB.wizardTemplate = el.getAttribute('data-template');
        KB.wizardColumns = JSON.parse(JSON.stringify(KB.templates[KB.wizardTemplate]));
    },
    wizardNext: function() {
        if (KB.wizardStep === 1) {
            KB.wizardStep = 2;
            KB.renderWizardColumns();
        } else if (KB.wizardStep === 2) {
            var name = document.getElementById('wizBoardName').value.trim();
            if (!name) { alert('Please enter a board name'); return; }
            if (KB.wizardColumns.length < 2) { alert('Please add at least 2 columns'); return; }
            KB.wizardStep = 3;
            document.getElementById('wizFinalName').textContent = name;
            var fc = document.getElementById('wizFinalColumns');
            fc.innerHTML = '';
            KB.wizardColumns.forEach(function(c) {
                fc.innerHTML += '<span class="kb-col-chip"><span class="dot" style="background:' + c.color + ';"></span>' + KB.escHtml(c.name) + '</span>';
            });
        } else if (KB.wizardStep === 3) {
            // Create board
            var btn = document.getElementById('wizNextBtn');
            btn.textContent = 'Creating...';
            btn.disabled = true;
            KB.api('setup_board', {
                board_name: document.getElementById('wizBoardName').value.trim(),
                board_type: KB.wizardTemplate,
                description: document.getElementById('wizBoardDesc').value.trim(),
                columns: KB.wizardColumns
            }, 'POST').then(function(r) {
                if (r.success) {
                    KB.hideWizard();
                    KB.currentBoard = { id: r.board_id };
                    KB.loadBoards();
                    btn.textContent = 'Create Board 🚀';
                    btn.disabled = false;
                }
            });
            return;
        }
        KB.updateWizardUI();
    },
    wizardPrev: function() {
        if (KB.wizardStep > 1) {
            KB.wizardStep--;
            KB.updateWizardUI();
        }
    },
    updateWizardUI: function() {
        // Steps
        for (var i = 1; i <= 3; i++) {
            var step = document.getElementById('wizStep' + i);
            var page = document.getElementById('wizPage' + i);
            step.className = 'kb-wizard-step' + (i === KB.wizardStep ? ' active' : '') + (i < KB.wizardStep ? ' completed' : '');
            page.className = 'kb-wizard-page' + (i === KB.wizardStep ? ' active' : '');
        }
        // Buttons
        document.getElementById('wizPrevBtn').style.visibility = KB.wizardStep > 1 ? 'visible' : 'hidden';
        var nextBtn = document.getElementById('wizNextBtn');
        if (KB.wizardStep === 3) { nextBtn.textContent = 'Create Board 🚀'; }
        else { nextBtn.textContent = 'Next →'; }
    },
    renderWizardColumns: function() {
        var container = document.getElementById('wizColumnsPreview');
        container.innerHTML = '';
        KB.wizardColumns.forEach(function(c, i) {
            container.innerHTML += '<span class="kb-col-chip"><span class="dot" style="background:' + c.color + ';"></span>' + KB.escHtml(c.name) + '<button class="remove-col" onclick="KB.removeWizardColumn(' + i + ')">×</button></span>';
        });
    },
    addWizardColumn: function() {
        var input = document.getElementById('wizNewColName');
        var name = input.value.trim();
        if (!name) return;
        KB.wizardColumns.push({ name: name, color: KB.labelColors[KB.wizardColumns.length % KB.labelColors.length] });
        input.value = '';
        KB.renderWizardColumns();
    },
    removeWizardColumn: function(idx) {
        KB.wizardColumns.splice(idx, 1);
        KB.renderWizardColumns();
    },

    // ── Utilities ──
    escHtml: function(s) {
        if (!s) return '';
        var d = document.createElement('div');
        d.appendChild(document.createTextNode(s));
        return d.innerHTML;
    },
    escAttr: function(s) {
        return KB.escHtml(s).replace(/"/g, '&quot;');
    },
    formatDate: function(d) {
        if (!d) return '';
        var parts = d.split('-');
        var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
        return months[parseInt(parts[1])-1] + ' ' + parseInt(parts[2]);
    },
    timeAgo: function(dt) {
        var now = new Date();
        var then = new Date(dt);
        var diff = Math.floor((now - then) / 1000);
        if (diff < 60) return 'just now';
        if (diff < 3600) return Math.floor(diff/60) + 'm ago';
        if (diff < 86400) return Math.floor(diff/3600) + 'h ago';
        return Math.floor(diff/86400) + 'd ago';
    }
};

// Close menus on outside click
document.addEventListener('click', function(e) {
    if (!e.target.closest('.kb-column-menu')) KB.closeMenus();
});

// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        KB.closeCardModal();
        KB.closeMenus();
        KB.closeReports();
        document.getElementById('kbActivityPanel').classList.remove('open');
    }
});

// Close reports on overlay background click
document.getElementById('kbReportsOverlay').addEventListener('click', function(e) {
    if (e.target === this) KB.closeReports();
});

// Initialize
KB.init();
</script>

<?php
include('includes/footer.inc');
?>
