<!DOCTYPE html>
<?php
// Ensure variables
if (!isset($baseUrl)) $baseUrl = '';
if (!isset($assetsUrl)) $assetsUrl = rtrim($baseUrl, '/') . '/assets';
if (!isset($menu) || !is_array($menu)) $menu = [];
if (!isset($user)) $user = [];
if (!isset($projects)) $projects = [];
if (!isset($databaseTypes) || !is_array($databaseTypes)) $databaseTypes = [];
if (!isset($projectCounts) || !is_array($projectCounts)) $projectCounts = ['total' => count($projects), 'active' => count($projects), 'archived' => 0, 'pinned' => 0, 'ready' => 0];
if (!isset($projectColors) || !is_array($projectColors)) $projectColors = \PpPhp\Core\ProjectCatalog::COLORS;
if (!isset($projectIcons) || !is_array($projectIcons)) $projectIcons = \PpPhp\Core\ProjectCatalog::ICONS;
$flashError = $_SESSION['project_error'] ?? '';
$flashSuccess = $_SESSION['project_success'] ?? '';
unset($_SESSION['project_error'], $_SESSION['project_success']);
?>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars(\PpPhp\Core\Brand::name()) ?> · Projects</title>
    <?php include constant('BASE_PATH') . '/core/views/favicon.php'; ?>
    <link href="<?= $assetsUrl ?>/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <link href="<?= $assetsUrl ?>/icons/bootstrap-icons.css" rel="stylesheet">
    <?php include constant('BASE_PATH') . '/core/views/theme-head.php'; ?>
    <!-- SweetAlert2 -->
    <link href="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.css" rel="stylesheet">
    <script src="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.js"></script>

    <style>
        :root {
            --sidebar-width: 250px;
            --topbar-height: 56px;
        }

        body {
            background-color: var(--pp-app-bg, #f5f6fa);
            color: var(--pp-text, #172033);
        }

        .navbar-top {
            height: var(--topbar-height);
            z-index: 1030;
        }

        .sidebar {
            position: fixed;
            top: var(--topbar-height);
            left: 0;
            bottom: 0;
            width: var(--sidebar-width);
            background: var(--pp-surface, #1e293b);
            color: var(--pp-text-muted, #cbd5e1);
            border-right: 1px solid var(--pp-border, #26303f);
            transition: width 0.3s;
            overflow-x: hidden;
            z-index: 1020;
        }

        .sidebar.collapsed {
            width: 0;
        }

        .sidebar .nav-link {
            color: var(--pp-text-muted, #cbd5e1);
            padding: 0.6rem 1.5rem;
            white-space: nowrap;
        }

        .sidebar .nav-link:hover,
        .sidebar .nav-link.active {
            background-color: color-mix(in srgb, var(--pp-accent, #4f46e5) 12%, transparent);
            color: var(--pp-text, #fff);
        }

        .main-content {
            margin-left: var(--sidebar-width);
            margin-top: var(--topbar-height);
            padding: 1.5rem;
            transition: margin-left 0.3s;
        }

        .main-content.expanded {
            margin-left: 0;
        }

        @media (max-width: 991.98px) {
            .sidebar {
                display: none;
            }

            .main-content,
            .main-content.expanded {
                margin-left: 0;
            }
        }

        .project-card {
            border: 1px solid var(--pp-border, #e6eaf0);
            border-radius: 16px;
            transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
            cursor: pointer;
            overflow: hidden;
        }

        .project-card:hover {
            transform: translateY(-3px);
            border-color: var(--pp-accent, #bfd3ff);
            box-shadow: 0 .9rem 2rem rgba(30, 41, 59, .1) !important;
        }

        .modal-header {
            background: linear-gradient(120deg, #172554, #1d4ed8 62%, #7c3aed);
            color: #fff;
        }

        .db-badge {
            display: inline-flex;
            align-items: center;
            gap: .35rem;
            padding: .28rem .55rem;
            border-radius: 999px;
            background: var(--pp-accent-soft, #eef4ff);
            color: var(--pp-accent, #2457a6);
            font-size: .72rem;
            font-weight: 700;
        }

        .project-modal .modal-content {
            border: 0;
            border-radius: 18px;
            overflow: hidden;
            box-shadow: 0 24px 70px rgba(15, 23, 42, .25);
        }

        .project-modal .modal-content > form {
            min-height: 0;
            max-height: 100%;
            display: flex;
            flex-direction: column;
        }

        .project-modal .modal-body {
            background: var(--pp-surface-muted, #f8fafc);
            min-height: 0;
            max-height: none;
            overflow-y: auto;
        }

        .form-section {
            background: var(--pp-surface, #fff);
            border: 1px solid var(--pp-border, #e5eaf1);
            border-radius: 14px;
            padding: 1rem;
        }

        .section-eyebrow {
            color: var(--pp-text-muted, #64748b);
            font-size: .7rem;
            font-weight: 800;
            letter-spacing: .08em;
            text-transform: uppercase;
        }

        /* Compact horizontal "chip" cards: icon on the left, name + state stacked
           on the right (CSS grid — no markup change). Fits all engines in two
           tidy rows so the whole modal stays in one window. */
        .database-grid {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: .5rem;
        }

        .database-option {
            position: relative;
            display: grid;
            grid-template-columns: auto minmax(0, 1fr);
            grid-template-rows: auto auto;
            align-items: center;
            gap: 0 .55rem;
            min-height: 48px;
            border: 1px solid var(--pp-border, #dfe5ed);
            border-radius: 11px;
            background: var(--pp-surface, #fff);
            padding: .5rem .6rem;
            color: var(--pp-text, #334155);
            text-align: left;
            transition: transform .16s, border-color .16s, box-shadow .16s, background .16s;
        }

        .database-option::after {
            content: "";
            position: absolute;
            top: .55rem;
            right: .55rem;
            width: 15px;
            height: 15px;
            border-radius: 50%;
            border: 2px solid var(--pp-border-strong, #cbd5e1);
            opacity: 0;
            transition: opacity .16s;
        }
        .database-option.active::after {
            opacity: 1;
            border-color: var(--db-color);
            background: var(--db-color) radial-gradient(circle, #fff 33%, transparent 36%);
        }

        .database-option:hover:not(.is-disabled) {
            transform: translateY(-1px);
            border-color: var(--db-color);
            box-shadow: 0 6px 16px rgba(15, 23, 42, .08);
        }

        .database-option.active {
            border: 1.5px solid var(--db-color);
            background: var(--db-tint);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--db-color) 12%, transparent);
        }

        .database-option.is-disabled {
            opacity: .58;
            cursor: not-allowed;
        }

        .database-option .db-icon {
            grid-row: 1 / 3;
            width: 30px;
            height: 30px;
            margin: 0;
            display: grid;
            place-items: center;
            border-radius: 9px;
            color: #fff;
            background: var(--db-color);
            font-size: .95rem;
            flex: 0 0 auto;
        }

        .database-option .db-name {
            grid-column: 2;
            align-self: end;
            display: block;
            font-size: .8rem;
            line-height: 1.1;
            font-weight: 800;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            padding-right: 1rem;
        }

        /* The built-in Virtual Database tile — the recommended default. */
        .database-option.db-virtual { position: relative; overflow: visible; }
        .database-option.db-virtual .db-reco {
            position: absolute; top: -9px; right: 10px; z-index: 2;
            font-size: .58rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
            color: #fff; background: linear-gradient(120deg, #7c3aed, #6d28d9);
            border-radius: 999px; padding: 2px 8px; box-shadow: 0 3px 8px rgba(124, 58, 237, .35);
        }
        .database-option.db-virtual.active { box-shadow: 0 0 0 2px #7c3aed inset, 0 8px 20px rgba(124, 58, 237, .18); }
        .database-option .db-state {
            grid-column: 2;
            align-self: start;
            display: block;
            margin-top: 1px;
            font-size: .6rem;
            font-weight: 600;
            color: var(--pp-text-muted, #64748b);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .connection-panel {
            border-left: 4px solid var(--active-db-color, #2563eb);
        }

        .connection-summary {
            color: var(--pp-text-muted, #64748b);
            font-size: .8rem;
        }

        .test-result {
            display: none;
            border-radius: 10px;
            padding: .65rem .8rem;
            font-size: .82rem;
        }

        .test-result.show { display: flex; align-items: center; gap: .55rem; }
        .test-result.success { background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; }
        .test-result.error { background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca; }

        @media (max-width: 991.98px) {
            .database-grid { grid-template-columns: repeat(3, 1fr); }
        }

        @media (max-width: 575.98px) {
            .main-content { padding: 1rem; }
            .database-grid { grid-template-columns: repeat(2, 1fr); }
            .project-modal .modal-body { max-height: none; }
        }
    </style>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/databaseConnection.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectsHub.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectTransfer.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectTemplates.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectHistory.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectSchema.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectScript.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectPolish.css') ?>
    <?= \PpPhp\Core\ModuleAssets::style('Projects', 'Views/styles/projectsTheme.css') ?>
</head>

<body>

    <!-- Top Navbar -->
    <nav class="navbar navbar-top navbar-dark bg-dark px-3 fixed-top shadow-sm">
        <div class="d-flex align-items-center">
            <button class="btn btn-dark d-lg-none me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarOffcanvas">
                <i class="bi bi-list fs-4"></i>
            </button>
            <a class="navbar-brand d-flex align-items-center" href="<?= $baseUrl ?>/projects">
                <?= \PpPhp\Core\Brand::lockup(34) ?>
            </a>
        </div>

        <div class="d-flex align-items-center gap-2">
            <?php include constant('BASE_PATH') . '/core/views/command-palette.php'; ?>
            <?php include constant('BASE_PATH') . '/core/views/keyboard-shortcuts.php'; ?>
            <?php include constant('BASE_PATH') . '/core/views/notification-bell.php'; ?>
            <?php include constant('BASE_PATH') . '/core/views/theme-toggle.php'; ?>
            <div class="dropdown">
            <a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" data-bs-toggle="dropdown">
                <i class="bi bi-person-circle me-2"></i><span class="nav-username"><?= htmlspecialchars($user['username'] ?? 'Admin') ?></span>
            </a>
            <style>
                /* Instant, left-opening tooltips for the account dropdown items. */
                .acct-menu .dropdown-item { position: relative; }
                .acct-menu .dropdown-item[data-tip]:hover::after {
                    content: attr(data-tip);
                    position: absolute; right: calc(100% + 12px); top: 50%; transform: translateY(-50%);
                    background: var(--pp-navbar-bg, #0f172a); color: #f4f6fb;
                    font-size: .72rem; font-weight: 600; line-height: 1.35; text-align: left;
                    white-space: normal; width: max-content; max-width: 230px;
                    padding: 6px 10px; border-radius: 8px; z-index: 6000; pointer-events: none;
                    box-shadow: 0 10px 26px rgba(0, 0, 0, .4); border: 1px solid rgba(255, 255, 255, .14);
                }
                @media (max-width: 575.98px) { .acct-menu .dropdown-item[data-tip]:hover::after { display: none; } }
            </style>
            <ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end acct-menu">
                <?php if (\PpPhp\Core\Security::IsOwner()): /* platform owner only */ ?>
                    <?php $__vendorOnly = !class_exists(\PpPhp\Core\Licensing\LicenseGate::class) || !\PpPhp\Core\Licensing\LicenseGate::isClientEdition(); /* these + their routes are stripped from client bundles */ ?>
                    <?php if ($__vendorOnly): ?><li><a class="dropdown-item" href="<?= $baseUrl ?>/platform/app-bundle" data-tip="Package this platform into a clean, secret-free ZIP for a fresh server install"><i class="bi bi-box-seam me-2"></i>App Bundle</a></li><?php endif; ?>
                    <li><a class="dropdown-item" href="<?= $baseUrl ?>/platform/visitors" data-tip="Who has been visiting this installation — countries, pages and devices"><i class="bi bi-people me-2"></i>Visitors</a></li>
                    <?php if ($__vendorOnly): ?>
                    <li><hr class="dropdown-divider"></li>
                    <li><h6 class="dropdown-header"><i class="bi bi-send me-1"></i>Deliverables</h6></li>
                    <li><a class="dropdown-item" href="<?= $baseUrl ?>/platform/deliverables/marketing" data-tip="Download the public ppradhan.com marketing website to deploy at your domain root"><i class="bi bi-globe2 me-2"></i>Marketing Website</a></li>
                    <li><a class="dropdown-item" href="<?= $baseUrl ?>/platform/deliverables/community" data-tip="Rebuild &amp; download the community forum as a standalone installer (install.php)"><i class="bi bi-box-seam me-2"></i>Community Installer</a></li>
                    <?php endif; ?>
                    <li>
                        <hr class="dropdown-divider">
                    </li>
                <?php endif; ?>
                <?php if (\PpPhp\Core\Security::IsAdmin()): /* superadmin + owner */ ?>
                    <li><a class="dropdown-item" href="<?= $baseUrl ?>/users" data-tip="Add, edit and remove user accounts; review trial requests"><i class="bi bi-people me-2"></i>Manage Users</a></li>
                    <?php
                    // Show "Establish Owner" only when there is no verified owner yet.
                    // On a CLIENT edition the platform owner is the vendor, not the
                    // customer's admin — so hide the shortcut by default there and
                    // surface it only for the owner themselves (e.g. after an owner
                    // recovery) or while an owner email-challenge is already running.
                    // The owner-setup page stays reachable by its recovery link regardless.
                    $ppShowEstablish = !\PpPhp\Core\Auth\OwnerVerification::isVerified();
                    if ($ppShowEstablish && \PpPhp\Core\Licensing\LicenseGate::isClientEdition()) {
                        $ppShowEstablish = \PpPhp\Core\Security::IsOwner()
                            || \PpPhp\Core\Auth\OwnerVerification::challengePending();
                    }
                    ?>
                    <?php if ($ppShowEstablish): ?>
                    <li><a class="dropdown-item text-warning" href="<?= $baseUrl ?>/platform/owner-setup" data-tip="Establish the platform owner via an email code sent to the owner mailbox"><i class="bi bi-patch-check me-2"></i>Establish Owner</a></li>
                    <?php endif; ?>
                    <?php /* Applying updates belongs to whoever runs THIS install, so it is
                             admin-level — unlike producing a bundle, which stays owner-only. */ ?>
                    <li><a class="dropdown-item" href="<?= $baseUrl ?>/platform/updates" data-tip="Check for and apply platform updates to this installation">
                        <i class="bi bi-arrow-repeat me-2"></i>Updates
                        <span class="badge bg-secondary ms-1" style="font-size:.65rem">v<?= htmlspecialchars(\PpPhp\Core\PlatformSettings::version()) ?></span>
                    </a></li>
                    <?php include constant('BASE_PATH') . '/core/views/license-menu.php'; ?>
                    <li>
                        <hr class="dropdown-divider">
                    </li>
                <?php endif; ?>

                <li><a class="dropdown-item" href="<?= $baseUrl ?>/profile" data-tip="View and edit your own account details"><i class="bi bi-person me-2"></i>Profile</a></li>
                <li><a class="dropdown-item" href="<?= $baseUrl ?>/change-password" data-tip="Change your account password"><i class="bi bi-key me-2"></i>Change Password</a></li>
                <li>
                    <hr class="dropdown-divider">
                </li>
                <li><a class="dropdown-item" href="<?= $baseUrl ?>/logout" onclick="window.location.href=this.href; return false;" data-tip="Sign out of your account"><i class="bi bi-box-arrow-right me-2"></i>Sign out</a></li>
            </ul>
            </div>
        </div>
    </nav>

    <!-- Sidebar Desktop -->
    <nav id="sidebarDesktop" class="sidebar d-none d-lg-flex flex-column py-3">
        <ul class="nav nav-pills flex-column mb-auto">
            <?php foreach ($menu as $item): ?>
                <li class="nav-item">
                    <a href="<?= htmlspecialchars($baseUrl . ($item['uri'] ?? '#')) ?>"
                        class="nav-link <?= ($item['uri'] === '/projects') ? 'active' : '' ?>">
                        <i class="bi bi-<?= $item['icon'] ?? 'circle' ?> me-2"></i>
                        <span class="sidebar-text"><?= htmlspecialchars($item['label']) ?></span>
                    </a>
                </li>
            <?php endforeach; ?>
        </ul>
        <div class="mt-auto px-3 pb-1"><?php include constant('BASE_PATH') . '/core/views/sidebar-version.php'; ?></div>
    </nav>

    <!-- Mobile Offcanvas -->
    <div class="offcanvas offcanvas-start bg-dark text-white d-lg-none" id="sidebarOffcanvas">
        <div class="offcanvas-header">
            <h5 class="offcanvas-title d-flex align-items-center gap-2"><?= \PpPhp\Core\Brand::lockup(30) ?></h5>
            <button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
        </div>
        <div class="offcanvas-body">
            <ul class="nav nav-pills flex-column">
                <?php foreach ($menu as $item): ?>
                    <li class="nav-item">
                        <a href="<?= htmlspecialchars($baseUrl . ($item['uri'] ?? '#')) ?>" class="nav-link text-white">
                            <i class="bi bi-<?= $item['icon'] ?? 'circle' ?> me-2"></i><?= htmlspecialchars($item['label']) ?>
                        </a>
                    </li>
                <?php endforeach; ?>
            </ul>
        </div>
    </div>

    <!-- Main Content -->
    <main id="mainContent" class="main-content projects-hub">
        <section class="projects-command">
            <div class="projects-command-aurora" aria-hidden="true"><span></span><span></span><span></span></div>
            <div class="projects-command-copy">
                <div class="projects-command-kicker"><i class="bi bi-grid-1x2-fill"></i> Application portfolio</div>
                <h1>Projects</h1>
                <p>Open recent work, organize active applications, and keep every database-backed build within reach.</p>
            </div>
            <div class="projects-command-actions">
                <button class="btn btn-outline-light d-none d-lg-inline-flex align-items-center" id="sidebarToggle" title="Toggle sidebar"><i class="bi bi-layout-sidebar-inset me-1"></i> Navigation</button>
                <button class="btn btn-outline-light fw-semibold" type="button" id="openProjectsGuide"><i class="bi bi-question-circle me-1"></i><span class="project-action-label">Guide</span></button>
                <?php if (in_array($userRole ?? '', ['owner', 'superadmin', 'developer'], true)): ?>
                    <button class="btn btn-outline-light fw-semibold" type="button" id="openTemplateLibrary"><i class="bi bi-layers me-1"></i><span class="project-action-label">Templates</span><?php if ($projectTemplates): ?><span class="badge rounded-pill bg-white text-primary ms-1"><?= count($projectTemplates) ?></span><?php endif; ?></button>
                    <button class="btn btn-outline-light fw-semibold" type="button" id="openProjectImport"><i class="bi bi-box-arrow-in-down me-1"></i><span class="project-action-label">Import</span></button>
                    <button class="btn btn-light text-primary fw-semibold" data-bs-toggle="modal" data-bs-target="#newProjectModal" data-project-tooltip="Create a new project and configure its database"><i class="bi bi-plus-lg me-1"></i><span class="project-action-label">New Project</span></button>
                <?php endif; ?>
            </div>
        </section>

        <?php if ($flashSuccess): ?>
            <div class="alert alert-success alert-dismissible fade show mt-3 mb-0"><?= htmlspecialchars($flashSuccess) ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>
        <?php endif; ?>
        <?php if ($flashError): ?>
            <div class="alert alert-danger alert-dismissible fade show mt-3 mb-0"><?= htmlspecialchars($flashError) ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>
        <?php endif; ?>

        <section class="projects-overview" aria-label="Project overview">
            <div class="project-metric blue"><span class="project-metric-icon"><i class="bi bi-window-stack"></i></span><span class="project-metric-copy"><strong data-project-metric="active"><?= (int)$projectCounts['active'] ?></strong><span>active projects</span></span></div>
            <div class="project-metric violet"><span class="project-metric-icon"><i class="bi bi-star-fill"></i></span><span class="project-metric-copy"><strong data-project-metric="pinned"><?= (int)$projectCounts['pinned'] ?></strong><span>pinned for quick access</span></span></div>
            <div class="project-metric green"><span class="project-metric-icon"><i class="bi bi-check2-circle"></i></span><span class="project-metric-copy"><strong data-project-metric="ready"><?= (int)$projectCounts['ready'] ?></strong><span>ready to continue</span></span></div>
            <div class="project-metric slate"><span class="project-metric-icon"><i class="bi bi-collection"></i></span><span class="project-metric-copy"><strong data-project-metric="all"><?= (int)$projectCounts['total'] ?></strong><span>projects in your catalog</span></span></div>
        </section>

        <section class="projects-toolbar" aria-label="Project filters">
            <div class="projects-search"><i class="bi bi-search"></i><input type="search" class="form-control" id="projectsSearch" placeholder="Search projects, databases, or descriptions" autocomplete="off"></div>
            <select class="form-select" id="projectsDatabaseFilter" aria-label="Filter by database">
                <option value="">All databases</option>
                <?php foreach ($databaseTypes as $type => $definition): ?>
                    <option value="<?= htmlspecialchars($type) ?>"><?= htmlspecialchars($definition['label']) ?></option>
                <?php endforeach; ?>
            </select>
            <select class="form-select" id="projectsHealthFilter" aria-label="Filter by health">
                <option value="">All health</option><option value="ready">Ready</option><option value="setup">Setup</option><option value="attention">Needs attention</option>
            </select>
            <select class="form-select" id="projectsSort" aria-label="Sort projects">
                <option value="activity">Recently opened</option><option value="modified">Recently modified</option><option value="created">Newest created</option><option value="name">Name A–Z</option>
            </select>
            <div class="projects-density-switch" aria-label="Row density">
                <button type="button" data-project-density="comfortable" class="active" aria-label="Comfortable density" aria-pressed="true" data-project-tooltip="Comfortable spacing"><i class="bi bi-arrows-expand"></i></button>
                <button type="button" data-project-density="compact" aria-label="Compact density" aria-pressed="false" data-project-tooltip="Compact — fit more on screen"><i class="bi bi-arrows-collapse"></i></button>
            </div>
            <div class="projects-view-switch" aria-label="Project view">
                <button type="button" data-project-view="grid" class="active" aria-label="Grid view" aria-pressed="true"><i class="bi bi-grid"></i></button>
                <button type="button" data-project-view="list" aria-label="List view" aria-pressed="false"><i class="bi bi-list-ul"></i></button>
            </div>
        </section>

        <section class="projects-views" id="projectsViews" aria-label="Saved views">
            <span class="pv-label"><i class="bi bi-bookmark-star"></i> Views</span>
            <div class="pv-chips" id="projectsViewChips" role="list"></div>
            <span class="pv-empty" id="projectsViewEmpty">Save a search + filter combo to jump back to it in one click.</span>
            <button type="button" class="pv-save" id="projectsSaveView" data-project-tooltip="Save the current search, filters, sort, tab &amp; layout as a reusable view"><i class="bi bi-plus-lg"></i> Save current view</button>
        </section>

        <section class="projects-tabs" role="tablist" aria-label="Project status">
            <button type="button" class="active" data-project-tab="active" role="tab" aria-selected="true">Active <span data-project-tab-count="active"><?= (int)$projectCounts['active'] ?></span></button>
            <button type="button" data-project-tab="pinned" role="tab" aria-selected="false">Pinned <span data-project-tab-count="pinned"><?= (int)$projectCounts['pinned'] ?></span></button>
            <button type="button" data-project-tab="archived" role="tab" aria-selected="false">Archived <span data-project-tab-count="archived"><?= (int)$projectCounts['archived'] ?></span></button>
            <button type="button" data-project-tab="all" role="tab" aria-selected="false">All <span data-project-tab-count="all"><?= (int)$projectCounts['total'] ?></span></button>
            <span class="projects-result-count" id="projectsResultCount"><?= (int)$projectCounts['active'] ?> projects</span>
        </section>

        <section class="projects-collection" id="projectsCollection" aria-live="polite">
            <?php foreach ($projects as $project):
                $description = trim((string)($project['description'] ?? ''));
                $searchText = strtolower(implode(' ', [$project['name'], $project['slug'], $description, $project['db_label'], $project['health_label'], (string)($project['owner_username'] ?? '')]));
                $activityIso = date(DATE_ATOM, strtotime((string)$project['activity_at']));
                $modifiedIso = date(DATE_ATOM, strtotime((string)($project['updated_at'] ?? $project['created_at'])));
                $createdIso = date(DATE_ATOM, strtotime((string)$project['created_at']));
            ?>
                <article class="project-hub-card <?= !empty($project['archived_at']) ? 'is-archived' : '' ?>"
                    data-project-card data-project-slug="<?= htmlspecialchars($project['slug']) ?>"
                    data-name="<?= htmlspecialchars((string)$project['name']) ?>"
                    data-description="<?= htmlspecialchars($description) ?>"
                    data-search="<?= htmlspecialchars($searchText) ?>"
                    data-database="<?= htmlspecialchars($project['db_type']) ?>"
                    data-database-label="<?= htmlspecialchars($project['db_label']) ?>"
                    data-database-target="<?= htmlspecialchars((string)($project['db_name'] ?? '')) ?>"
                    data-health="<?= htmlspecialchars($project['health']) ?>"
                    data-pinned="<?= !empty($project['is_pinned']) ? '1' : '0' ?>"
                    data-archived="<?= !empty($project['archived_at']) ? '1' : '0' ?>"
                    data-color="<?= htmlspecialchars($project['color']) ?>" data-icon="<?= htmlspecialchars($project['icon']) ?>"
                    data-activity="<?= htmlspecialchars($activityIso) ?>" data-modified="<?= htmlspecialchars($modifiedIso) ?>" data-created="<?= htmlspecialchars($createdIso) ?>"
                    style="--project-accent:<?= htmlspecialchars($project['color']) ?>">
                    <div class="project-card-main">
                        <div class="project-card-header">
                            <span class="project-card-mark"><i class="bi bi-<?= htmlspecialchars($project['icon']) ?>" data-card-icon></i></span>
                            <div class="project-card-heading"><h2 data-project-name><?= htmlspecialchars($project['name']) ?></h2><span class="project-card-slug">/<?= htmlspecialchars($project['slug']) ?></span></div>
                            <div class="project-card-menu">
                                <button type="button" class="project-pin <?= !empty($project['is_pinned']) ? 'active' : '' ?>" data-project-action="pin" aria-label="<?= !empty($project['is_pinned']) ? 'Unpin' : 'Pin' ?> <?= htmlspecialchars($project['name']) ?>" aria-pressed="<?= !empty($project['is_pinned']) ? 'true' : 'false' ?>" title="<?= !empty($project['is_pinned']) ? 'Unpin project' : 'Pin project' ?>"><i class="bi <?= !empty($project['is_pinned']) ? 'bi-star-fill' : 'bi-star' ?>"></i></button>
                                <div class="dropdown">
                                    <button type="button" class="project-menu-toggle" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Project actions"><span class="project-menu-glyph" aria-hidden="true"><span></span><span></span><span></span></span></button>
                                    <ul class="dropdown-menu dropdown-menu-end shadow-sm">
                                        <li><a class="dropdown-item" href="<?= $baseUrl ?>/project/<?= rawurlencode($project['slug']) ?>"><i class="bi bi-box-arrow-up-right me-2"></i>Open project</a></li>
                                        <li><button class="dropdown-item" type="button" data-edit-database data-project-name-value data-project-slug="<?= htmlspecialchars($project['slug']) ?>" data-project-name="<?= htmlspecialchars($project['name']) ?>"><i class="bi bi-database-gear me-2"></i>Database connection</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="settings"><i class="bi bi-sliders me-2"></i>Project settings</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="duplicate"><i class="bi bi-copy me-2"></i>Duplicate / Save As</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="template"><i class="bi bi-bookmark-plus me-2"></i>Save as Template</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="history"><i class="bi bi-clock-history me-2"></i>History &amp; Version Control</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="schema"><i class="bi bi-database-check me-2"></i>Schema &amp; Structure</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="script"><i class="bi bi-filetype-sql me-2"></i>Generate SQL Script</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="export"><i class="bi bi-box-arrow-up me-2"></i>Export package</button></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="pin"><i class="bi <?= !empty($project['is_pinned']) ? 'bi-star-fill' : 'bi-star' ?> me-2"></i><span data-action-label><?= !empty($project['is_pinned']) ? 'Unpin project' : 'Pin project' ?></span></button></li>
                                        <li><hr class="dropdown-divider"></li>
                                        <li><button class="dropdown-item" type="button" data-project-action="archive"><i class="bi <?= !empty($project['archived_at']) ? 'bi-arrow-counterclockwise' : 'bi-archive' ?> me-2"></i><span data-action-label><?= !empty($project['archived_at']) ? 'Restore project' : 'Archive project' ?></span></button></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                        <p class="project-card-description" data-project-description><?= htmlspecialchars($description !== '' ? $description : 'No description yet.') ?></p>
                        <div class="project-badges">
                            <?php if (!empty($isAdminViewer) && empty($project['owned_by_me'])): ?>
                                <span class="project-chip owner" title="Owned by <?= htmlspecialchars((string)$project['owner_username']) ?>"><i class="bi bi-person-badge"></i><?= htmlspecialchars((string)$project['owner_username']) ?></span>
                            <?php endif; ?>
                            <span class="project-chip database"><i class="bi <?= !empty($project['standalone']) ? 'bi-window-stack' : 'bi-database' ?>"></i><span data-project-db-label><?= htmlspecialchars($project['db_label']) ?></span></span>
                            <span class="project-chip health-<?= htmlspecialchars($project['health']) ?>"><i class="bi <?= $project['health'] === 'ready' ? 'bi-check-circle-fill' : ($project['health'] === 'attention' ? 'bi-exclamation-triangle-fill' : 'bi-clock-fill') ?>"></i><?= htmlspecialchars($project['health_label']) ?></span>
                            <?php if (!empty($project['standalone'])): ?>
                                <span class="project-chip" title="A database-free app built from Designer pages"><i class="bi bi-file-earmark-richtext"></i>Pages only</span>
                            <?php else: ?>
                                <span class="project-chip"><i class="bi bi-table"></i><?= (int)$project['table_count'] ?> tables</span>
                            <?php endif; ?>
                        </div>
                        <div class="project-readiness"><div class="project-readiness-copy"><span>Project readiness</span><strong><?= (int)$project['readiness'] ?>%</strong></div><div class="project-progress"><span style="width:<?= (int)$project['readiness'] ?>%"></span></div></div>
                    </div>
                    <footer class="project-card-footer">
                        <span class="project-activity" title="Last activity <?= htmlspecialchars(date('M j, Y, g:i a', strtotime((string)$project['activity_at']))) ?>"><i class="bi bi-clock-history"></i><span data-relative-time="<?= htmlspecialchars($activityIso) ?>"><?= htmlspecialchars(date('M j, Y', strtotime((string)$project['activity_at']))) ?></span></span>
                        <div class="project-card-actions">
                            <button type="button" class="btn btn-light border" data-project-action="settings" aria-label="Settings for <?= htmlspecialchars($project['name']) ?>" title="Project settings"><i class="bi bi-gear"></i></button>
                            <a class="btn btn-primary" href="<?= $baseUrl ?>/project/<?= rawurlencode($project['slug']) ?>">Open <i class="bi bi-arrow-up-right ms-1"></i></a>
                        </div>
                    </footer>
                </article>
            <?php endforeach; ?>
        </section>

        <section class="projects-empty <?= empty($projects) ? 'show' : '' ?>" id="projectsNoResults"><i class="bi bi-folder2-open"></i><h3>No projects match this view</h3><p>Try another search or filter, restore an archived project, or create a new application.</p></section>
    </main>

    <!-- New Project Modal: compact layout + themed footer actions -->
    <style>
        /* ── Compact the modal so it fits without scrolling ── */
        #newProjectModal .modal-header { padding: .6rem 1.2rem !important; }
        #newProjectModal .modal-body { padding: .7rem 1.2rem !important; }
        #newProjectModal .form-section { margin-bottom: .55rem !important; padding: .75rem .9rem !important; }
        #newProjectModal .form-section > .d-flex.mb-3,
        #newProjectModal .form-section > .d-flex.flex-wrap.mb-3,
        #newProjectModal .form-section > .d-flex.mb-2 { margin-bottom: .5rem !important; }
        #newProjectModal .row.g-3 { --bs-gutter-y: .5rem; --bs-gutter-x: .7rem; }
        #newProjectModal .form-label { margin-bottom: .15rem; }
        #newProjectModal .form-control, #newProjectModal .form-select { padding-top: .34rem; padding-bottom: .34rem; }
        /* Compact chips are handled by the base rules; the modal only tightens the gap. */
        #newProjectModal .database-grid { gap: .45rem; }
        #newProjectModal .connection-summary { font-size: .74rem; }
        #newProjectModal .mt-3.pt-3.border-top { margin-top: .45rem !important; padding-top: .45rem !important; }
        #newProjectModal .database-option.is-locked { opacity: .5; }

        /* ── Themed footer actions (light/dark compliant) ── */
        #newProjectModal .np-footer { background: var(--pp-surface); border-top: 1px solid var(--pp-border); gap: .5rem; }
        #newProjectModal .np-footer .btn { font-size: .875rem; padding: .45rem .95rem; border-radius: .55rem; display: inline-flex; align-items: center; }
        #newProjectModal .np-btn-ghost { background: var(--pp-surface-muted); border: 1px solid var(--pp-border); color: var(--pp-text); }
        #newProjectModal .np-btn-ghost:hover { background: var(--pp-surface-soft); color: var(--pp-text); }
        #newProjectModal .np-btn-test { background: var(--pp-surface); border: 1px solid var(--pp-border); color: var(--pp-accent); font-weight: 600; }
        #newProjectModal .np-btn-test:hover { background: var(--pp-accent-soft); border-color: var(--pp-accent); color: var(--pp-accent); }
        #newProjectModal .np-btn-create { background: var(--pp-accent); border: 1px solid var(--pp-accent); color: var(--pp-accent-contrast); font-weight: 650; transition: opacity .15s, filter .15s; }
        #newProjectModal .np-btn-create:hover:not(:disabled) { filter: brightness(1.07); color: var(--pp-accent-contrast); }
        #newProjectModal .np-btn-create:disabled { opacity: .5; cursor: not-allowed; filter: grayscale(.3); }
        /* App-type toggle (Database-backed vs Standalone) */
        #newProjectModal .np-apptype { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
        #newProjectModal .np-apptype-opt { display: flex; align-items: center; gap: .6rem; text-align: left; padding: .6rem .75rem; border-radius: .6rem;
            border: 1px solid var(--pp-border); background: var(--pp-surface); color: var(--pp-text); cursor: pointer; transition: border-color .12s, background .12s, box-shadow .12s; }
        #newProjectModal .np-apptype-opt i { font-size: 1.2rem; color: var(--pp-text-muted); flex: 0 0 auto; }
        #newProjectModal .np-apptype-opt span { display: flex; flex-direction: column; min-width: 0; }
        #newProjectModal .np-apptype-opt strong { font-size: .86rem; line-height: 1.2; }
        #newProjectModal .np-apptype-opt small { font-size: .7rem; color: var(--pp-text-muted); line-height: 1.25; }
        #newProjectModal .np-apptype-opt:hover { border-color: var(--pp-accent); }
        #newProjectModal .np-apptype-opt.is-active { border-color: var(--pp-accent); background: var(--pp-accent-soft); box-shadow: inset 0 0 0 1px var(--pp-accent); }
        #newProjectModal .np-apptype-opt.is-active i { color: var(--pp-accent); }
        #newProjectModal .np-standalone-note { display: flex; gap: .55rem; align-items: flex-start; margin: .6rem 0 0; padding: .6rem .8rem; border-radius: .6rem; font-size: .8rem; line-height: 1.45;
            background: color-mix(in srgb, var(--pp-accent) 10%, var(--pp-surface)); border: 1px solid color-mix(in srgb, var(--pp-accent) 38%, var(--pp-border)); color: var(--pp-text); }
        #newProjectModal .np-standalone-note[hidden] { display: none; }
        #newProjectModal .np-standalone-note i { color: var(--pp-accent); font-size: 1rem; margin-top: 1px; flex: 0 0 auto; }
        /* When standalone, DB engine + connection + DB-only footer buttons hide. */
        #newProjectModal.is-standalone #dbEngineSection,
        #newProjectModal.is-standalone #connectionPanel,
        #newProjectModal.is-standalone #vdbPanel,
        #newProjectModal.is-standalone .np-btn-test { display: none !important; }
        #newProjectModal #vdbPanel[hidden] { display: none; }

        /* ── Step 3 · Virtual Database picker ── */
        #newProjectModal .vdb-quota { display: flex; align-items: center; gap: .5rem; font-size: .76rem; color: var(--pp-text-muted);
            background: var(--pp-surface-muted); border: 1px solid var(--pp-border); border-radius: .5rem; padding: .4rem .7rem; margin-bottom: .6rem; }
        #newProjectModal .vdb-quota[hidden] { display: none; }
        #newProjectModal .vdb-quota .vq-bar { flex: 1; height: 6px; border-radius: 99px; background: color-mix(in srgb, var(--pp-text-muted) 22%, transparent); overflow: hidden; max-width: 160px; }
        #newProjectModal .vdb-quota .vq-fill { height: 100%; background: var(--pp-accent); border-radius: 99px; }
        #newProjectModal .vdb-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: .5rem; }
        #newProjectModal .vdb-loading { grid-column: 1/-1; color: var(--pp-text-muted); font-size: .82rem; padding: .8rem 0; }
        #newProjectModal .vdb-card { position: relative; display: flex; flex-direction: column; gap: .15rem; text-align: left; cursor: pointer;
            border: 1px solid var(--pp-border); background: var(--pp-surface); color: var(--pp-text); border-radius: .7rem; padding: .65rem .8rem; transition: border-color .12s, box-shadow .12s, background .12s; }
        #newProjectModal .vdb-card:hover:not(.is-disabled) { border-color: var(--pp-accent); }
        #newProjectModal .vdb-card.active { border-color: var(--pp-accent); background: var(--pp-accent-soft); box-shadow: inset 0 0 0 1px var(--pp-accent); }
        #newProjectModal .vdb-card.is-disabled { opacity: .55; cursor: not-allowed; }
        #newProjectModal .vdb-card .vc-title { display: flex; align-items: center; gap: .4rem; font-weight: 700; font-size: .84rem; }
        #newProjectModal .vdb-card .vc-title i { color: var(--pp-accent); }
        #newProjectModal .vdb-card .vc-meta { font-size: .7rem; color: var(--pp-text-muted); display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
        #newProjectModal .vdb-card .vc-badge { font-size: .6rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; padding: .05rem .35rem; border-radius: 99px;
            background: color-mix(in srgb, var(--pp-accent) 16%, transparent); color: var(--pp-accent); }
        #newProjectModal .vdb-card .vc-badge.ro { background: color-mix(in srgb, var(--pp-text-muted) 20%, transparent); color: var(--pp-text-muted); }
        #newProjectModal .vdb-card .vc-check { position: absolute; top: .5rem; right: .55rem; color: var(--pp-accent); opacity: 0; transition: opacity .12s; }
        #newProjectModal .vdb-card.active .vc-check { opacity: 1; }
        #newProjectModal .vdb-card.vdb-create { border-style: dashed; }
        #newProjectModal .vdb-card.vdb-create .vc-title i { color: var(--pp-accent); }
        #newProjectModal .vdb-create-name { margin-top: .45rem; }
        #newProjectModal .vdb-create-name input { font-size: .8rem; padding: .3rem .5rem; }
        #newProjectModal .vdb-create[hidden], #newProjectModal .vdb-create-name[hidden] { display: none; }
    </style>
    <div class="modal fade project-modal" id="newProjectModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
            <div class="modal-content">
                <div class="modal-header px-4 py-3">
                    <div>
                        <h5 class="modal-title mb-1"><i class="bi bi-stars me-2"></i>Create a new project</h5>
                        <div class="small text-white-50">Choose the database that best fits this application.</div>
                    </div>
                    <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <form id="projectForm" action="<?= $baseUrl ?>/projects/create" method="post">
                    <?= \PpPhp\Core\Security::CSRF()->HiddenField() ?>
                    <input type="hidden" name="db_type" id="dbType" value="mysql">
                    <input type="hidden" name="use_virtual_db" id="useVirtualDb" value="0">
                    <input type="hidden" name="standalone" id="standaloneFlag" value="0">
                    <div class="modal-body p-3 p-md-4">
                        <div class="form-section mb-3">
                            <div class="d-flex align-items-center justify-content-between mb-3">
                                <div>
                                    <div class="section-eyebrow">Project</div>
                                    <h6 class="mb-0">Name your application</h6>
                                </div>
                                <span class="badge rounded-pill text-bg-light border">Step 1</span>
                            </div>
                            <div class="row g-3">
                                <div class="col-md-5">
                                    <label class="form-label small fw-semibold">Project name <span class="text-danger">*</span></label>
                                    <input type="text" name="name" id="projectName" class="form-control" placeholder="Customer portal" maxlength="100" required>
                                </div>
                                <div class="col-md-3">
                                    <label class="form-label small fw-semibold">Project slug <span class="text-danger">*</span></label>
                                    <input type="text" name="slug" id="projectSlug" class="form-control" placeholder="customer-portal" pattern="[a-z0-9]+(?:-[a-z0-9]+)*" maxlength="100" required>
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small fw-semibold">Short description</label>
                                    <input type="text" name="description" class="form-control" placeholder="What will this application do?" maxlength="255">
                                </div>
                            </div>
                        </div>

                        <!-- App type: database-backed vs standalone (no DB) -->
                        <div class="form-section mb-3">
                            <div class="d-flex align-items-center justify-content-between mb-2">
                                <div>
                                    <div class="section-eyebrow">App type</div>
                                    <h6 class="mb-0">How will this app store data?</h6>
                                </div>
                            </div>
                            <div class="np-apptype" role="tablist" aria-label="Application type">
                                <button type="button" class="np-apptype-opt is-active" data-app-type="database" aria-pressed="true">
                                    <i class="bi bi-hdd-network"></i>
                                    <span><strong>Database-backed</strong><small>Connect a database and manage its records</small></span>
                                </button>
                                <button type="button" class="np-apptype-opt" data-app-type="standalone" aria-pressed="false">
                                    <i class="bi bi-window-stack"></i>
                                    <span><strong>Standalone</strong><small>No database — build pages with the Designer</small></span>
                                </button>
                            </div>
                            <div class="np-standalone-note" id="npStandaloneNote" hidden>
                                <i class="bi bi-info-circle"></i>
                                <div>This creates a <b>database-free</b> app. You'll design its pages in the <b>Designer</b> (standalone &amp; common pages, components, style). Tables, Query, Pages, Fields and Security stay locked — they need a database.</div>
                            </div>
                        </div>

                        <div class="form-section mb-3" id="dbEngineSection">
                            <div class="d-flex align-items-center justify-content-between mb-3">
                                <div>
                                    <div class="section-eyebrow">Database engine</div>
                                    <h6 class="mb-0">Select a connection type</h6>
                                </div>
                                <span class="badge rounded-pill text-bg-light border">Step 2</span>
                            </div>
                            <div class="database-grid" id="databaseGrid">
                                <button type="button"
                                    class="database-option db-virtual active"
                                    data-db-type="virtual" data-available="1"
                                    style="--db-color:#7c3aed;--db-tint:#f5f3ff"
                                    title="The built-in Virtual Database Engine — a private database created instantly inside your project. Nothing to install, no host, no credentials. Recommended for every new project."
                                    aria-pressed="true">
                                    <span class="db-reco">Recommended</span>
                                    <span class="db-icon"><i class="bi bi-lightning-charge-fill"></i></span>
                                    <span class="db-name">Virtual Database</span>
                                    <span class="db-state">Built-in · zero setup</span>
                                </button>
                                <?php foreach ($databaseTypes as $type => $db): ?>
                                    <button type="button"
                                        class="database-option <?= empty($db['available']) ? 'is-disabled' : '' ?>"
                                        data-db-type="<?= htmlspecialchars($type) ?>"
                                        data-available="<?= !empty($db['available']) ? '1' : '0' ?>"
                                        style="--db-color:<?= htmlspecialchars($db['color']) ?>;--db-tint:<?= htmlspecialchars($db['tint']) ?>"
                                        title="<?= htmlspecialchars($db['description'] . ' ' . $db['requirement']) ?>"
                                        aria-pressed="false">
                                        <span class="db-icon"><i class="bi bi-<?= htmlspecialchars($db['icon']) ?>"></i></span>
                                        <span class="db-name"><?= htmlspecialchars($db['label']) ?></span>
                                        <span class="db-state"><?= htmlspecialchars($db['requirement']) ?></span>
                                    </button>
                                <?php endforeach; ?>
                            </div>
                        </div>

                        <!-- Step 3 for the Virtual Database engine: pick or create a pool database. -->
                        <div class="form-section" id="vdbPanel" hidden>
                            <div class="d-flex flex-wrap align-items-start justify-content-between gap-2 mb-2">
                                <div>
                                    <div class="section-eyebrow">Your data</div>
                                    <h6 class="mb-1"><i class="bi bi-hdd-stack me-1"></i>Choose or create a database</h6>
                                    <div class="connection-summary">Your project connects to one of your private Virtual Databases — the same pool as <b>Data Studio</b>, so tables you build here show up there too.</div>
                                </div>
                                <span class="badge rounded-pill text-bg-light border">Step 3</span>
                            </div>
                            <div id="vdbQuota" class="vdb-quota" hidden></div>
                            <div id="vdbList" class="vdb-list" role="radiogroup" aria-label="Choose a database">
                                <div class="vdb-loading"><span class="spinner-border spinner-border-sm me-2"></span>Loading your databases…</div>
                            </div>
                            <input type="hidden" name="vdb_id" id="vdbId" value="0">
                            <input type="hidden" name="vdb_new_label" id="vdbNewLabel" value="">
                        </div>

                        <div class="form-section connection-panel" id="connectionPanel">
                            <div class="d-flex flex-wrap align-items-start justify-content-between gap-2 mb-3">
                                <div>
                                    <div class="section-eyebrow">Connection</div>
                                    <h6 class="mb-1">Connect to <span id="selectedDbLabel">MySQL</span></h6>
                                    <div class="connection-summary" id="selectedDbDescription">Enter the server credentials and verify them before creating the project.</div>
                                </div>
                                <span class="badge rounded-pill text-bg-light border">Step 3</span>
                            </div>

                            <div class="row g-3" id="serverConnectionFields">
                                <div class="col-md-5">
                                    <label class="form-label small fw-semibold">Host / server</label>
                                    <div class="input-group">
                                        <span class="input-group-text"><i class="bi bi-hdd-network"></i></span>
                                        <input type="text" name="db_host" class="form-control" value="127.0.0.1" autocomplete="off">
                                    </div>
                                </div>
                                <div class="col-md-2">
                                    <label class="form-label small fw-semibold">Port</label>
                                    <input type="number" name="db_port" class="form-control" value="3306" min="1" max="65535">
                                </div>
                                <div class="col-md-5" id="databaseNameField">
                                    <label class="form-label small fw-semibold" id="databaseNameLabel">Database name</label>
                                    <input type="text" name="db_name" class="form-control" placeholder="app_database" autocomplete="off">
                                </div>
                            </div>

                            <div class="row g-3 mt-0 d-none" id="sqliteConnectionFields">
                                <div class="col-12">
                                    <label class="form-label small fw-semibold">SQLite file</label>
                                    <div class="input-group">
                                        <span class="input-group-text"><i class="bi bi-file-earmark-binary"></i></span>
                                        <input type="text" name="db_path" class="form-control" value="database/app.sqlite" placeholder="database/app.sqlite">
                                    </div>
                                    <div class="form-text">Relative paths are stored inside the project folder. The file is created automatically when missing.</div>
                                </div>
                            </div>

                            <div class="row g-3 mt-0" id="credentialFields">
                                <div class="col-md-6">
                                    <label class="form-label small fw-semibold">Username</label>
                                    <div class="input-group">
                                        <span class="input-group-text"><i class="bi bi-person"></i></span>
                                        <input type="text" name="db_user" class="form-control" autocomplete="username">
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <label class="form-label small fw-semibold">Password</label>
                                    <div class="input-group">
                                        <span class="input-group-text"><i class="bi bi-key"></i></span>
                                        <input type="password" name="db_pass" id="dbPassword" class="form-control" autocomplete="new-password">
                                        <button class="btn btn-outline-secondary" type="button" id="toggleDbPassword" title="Show or hide password"><i class="bi bi-eye"></i></button>
                                    </div>
                                </div>
                            </div>

                            <div class="mt-3 pt-3 border-top">
                                <button class="btn btn-sm btn-link text-decoration-none px-0" type="button" data-bs-toggle="collapse" data-bs-target="#advancedConnection" aria-expanded="false">
                                    <i class="bi bi-sliders me-1"></i> Advanced connection options
                                </button>
                                <div class="collapse" id="advancedConnection">
                                    <div class="row g-3 pt-2">
                                        <div class="col-md-4" id="charsetField">
                                            <label class="form-label small fw-semibold">Character set</label>
                                            <input type="text" name="db_charset" class="form-control" value="utf8mb4">
                                        </div>
                                        <div class="col-md-4 d-none" id="schemaField">
                                            <label class="form-label small fw-semibold">Default schema</label>
                                            <input type="text" name="db_schema" class="form-control" value="public">
                                        </div>
                                        <div class="col-md-4 d-none" id="oracleServiceField">
                                            <label class="form-label small fw-semibold">Service name</label>
                                            <input type="text" name="db_service" class="form-control" placeholder="ORCLPDB1">
                                        </div>
                                        <div class="col-md-8 d-none" id="mysqlSslFields">
                                            <input type="hidden" name="db_ssl_enabled" value="0">
                                            <div class="form-check mb-2">
                                                <input class="form-check-input" type="checkbox" name="db_ssl_enabled" value="1" id="dbSslEnabled">
                                                <label class="form-check-label small fw-semibold" for="dbSslEnabled">Use a TLS/SSL connection</label>
                                            </div>
                                            <input type="text" name="db_ssl_ca" class="form-control form-control-sm" placeholder="Optional CA certificate path">
                                        </div>
                                        <div class="col-md-4 d-none" id="postgresSslField">
                                            <label class="form-label small fw-semibold">SSL mode</label>
                                            <select name="db_ssl_mode" class="form-select">
                                                <option value="prefer">Prefer</option>
                                                <option value="require">Require</option>
                                                <option value="verify-ca">Verify CA</option>
                                                <option value="verify-full">Verify full</option>
                                                <option value="disable">Disable</option>
                                            </select>
                                        </div>
                                        <div class="col-md-8 d-none" id="sqlServerSecurityFields">
                                            <input type="hidden" name="db_encrypt" value="0">
                                            <input type="hidden" name="db_trust_server_certificate" value="0">
                                            <div class="d-flex flex-wrap gap-4 pt-2">
                                                <div class="form-check">
                                                    <input class="form-check-input" type="checkbox" name="db_encrypt" value="1" id="dbEncrypt" checked>
                                                    <label class="form-check-label small fw-semibold" for="dbEncrypt">Encrypt connection</label>
                                                </div>
                                                <div class="form-check">
                                                    <input class="form-check-input" type="checkbox" name="db_trust_server_certificate" value="1" id="dbTrustCertificate">
                                                    <label class="form-check-label small fw-semibold" for="dbTrustCertificate">Trust server certificate</label>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>

                            <div id="testResult" class="test-result mt-3" role="status" aria-live="polite"></div>
                        </div>
                    </div>
                    <div class="modal-footer np-footer px-4 py-3">
                        <button type="button" class="btn np-btn-ghost me-auto" data-bs-dismiss="modal">Cancel</button>
                        <button type="button" class="btn np-btn-test" id="testConnBtn"><i class="bi bi-plug me-1"></i> Test connection</button>
                        <button type="submit" class="btn np-btn-create" id="createProjectBtn" title="Test the database connection first"><i class="bi bi-arrow-right-circle me-1"></i> Create project</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <?php include __DIR__ . '/partials/project_settings_modal.php'; ?>
    <?php include __DIR__ . '/partials/database_connection_modal.php'; ?>
    <?php include __DIR__ . '/partials/project_transfer_modals.php'; ?>
    <?php include __DIR__ . '/partials/project_template_modals.php'; ?>
    <?php include __DIR__ . '/partials/project_history_modal.php'; ?>
    <?php include __DIR__ . '/partials/project_schema_modal.php'; ?>
    <?php include __DIR__ . '/partials/project_script_modal.php'; ?>
    <?php include __DIR__ . '/partials/project_guide_modal.php'; ?>

    <script src="<?= $assetsUrl ?>/bootstrap/js/bootstrap.bundle.min.js"></script>
    <script>
        const databaseDefinitions = <?= json_encode($databaseTypes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
        window.projectDatabaseDefinitions = databaseDefinitions;
        window.projectsBaseUrl = <?= json_encode($baseUrl) ?>;
        window.projectsCsrfToken = <?= json_encode(\PpPhp\Core\Security::CSRF()->Token()) ?>;
        const projectForm = document.getElementById('projectForm');
        const testResult = document.getElementById('testResult');

        // ── App type: Database-backed vs Standalone (no database) ──────────────
        (function () {
            const modal = document.getElementById('newProjectModal');
            const flag = document.getElementById('standaloneFlag');
            const note = document.getElementById('npStandaloneNote');
            const opts = modal ? modal.querySelectorAll('.np-apptype-opt') : [];
            const desc = modal ? modal.querySelector('.modal-header .text-white-50') : null;
            function setType(type) {
                const standalone = type === 'standalone';
                modal.classList.toggle('is-standalone', standalone);
                if (flag) flag.value = standalone ? '1' : '0';
                if (note) note.hidden = !standalone;
                opts.forEach(function (b) {
                    var on = b.getAttribute('data-app-type') === type;
                    b.classList.toggle('is-active', on);
                    b.setAttribute('aria-pressed', on ? 'true' : 'false');
                });
                if (desc) desc.textContent = standalone
                    ? 'A database-free app — design its pages in the Designer.'
                    : 'Choose the database that best fits this application.';
                updateCreateBtn();   // standalone → Create is free; database → needs a verified connection
            }
            opts.forEach(function (b) { b.addEventListener('click', function () { setType(b.getAttribute('data-app-type')); }); });
            // Reset to database-backed each open, with the built-in Virtual
            // Database as the recommended, ready-to-create default.
            if (modal) modal.addEventListener('show.bs.modal', function () {
                connectionVerified = false;
                vdbLoaded = false;        // refetch the DB list + quota fresh each open (a just-created DB must appear)
                setType('database');
                selectVirtualDb();
            });
            // Deep-link: /projects?create=1 (e.g. from the ⌘K palette) opens the modal.
            // Deferred so it runs after this IIFE's `let`s initialize (the show.bs.modal
            // handler touches them), i.e. behaves like a real click.
            if (modal && /[?&]create=1\b/.test(location.search)) {
                setTimeout(function () { try { bootstrap.Modal.getOrCreateInstance(modal).show(); } catch (e) {} }, 0);
            }
        })();

        function setTestResult(success, message) {
            if (!testResult) return;
            testResult.className = 'test-result show mt-3 ' + (success ? 'success' : 'error');
            testResult.replaceChildren();
            const icon = document.createElement('i');
            icon.className = 'bi ' + (success ? 'bi-check-circle-fill' : 'bi-exclamation-circle-fill');
            const text = document.createElement('span');
            text.textContent = message;
            testResult.append(icon, text);
            // A verified connection is the gate for creating a DB-backed project.
            connectionVerified = !!success;
            updateCreateBtn();
        }

        // ── Guard: for a Database-backed project, "Create project" stays disabled
        // until the connection is verified (via Test connection). Standalone needs
        // no database, so it's free.
        let connectionVerified = false;
        function isStandaloneMode() { return document.getElementById('standaloneFlag')?.value === '1'; }
        function updateCreateBtn() {
            const btn = document.getElementById('createProjectBtn');
            if (!btn) return;
            const ok = isStandaloneMode() || connectionVerified;
            btn.disabled = !ok;
            btn.title = ok ? '' : 'Test the database connection first.';
        }
        function invalidateConnection() { connectionVerified = false; updateCreateBtn(); }

        function setVisible(id, visible) {
            document.getElementById(id)?.classList.toggle('d-none', !visible);
        }

        // ── Virtual Database (built-in engine) — the recommended default ────
        // No host, no credentials, nothing to verify: the engine creates a
        // private database file inside the project the moment it's created.
        function selectVirtualDb() {
            document.getElementById('useVirtualDb').value = '1';
            document.getElementById('dbType').value = 'sqlite';
            document.querySelectorAll('.database-option').forEach(o => {
                const sel = o.dataset.dbType === 'virtual';
                o.classList.toggle('active', sel);
                o.setAttribute('aria-pressed', sel ? 'true' : 'false');
            });
            document.getElementById('connectionPanel')?.classList.add('d-none');
            document.getElementById('testConnBtn')?.classList.add('d-none');
            document.getElementById('vdbPanel')?.removeAttribute('hidden');   // Step 3 for virtual DB
            connectionVerified = true;   // built-in: there is no connection to test
            loadVdbOptions();
            updateCreateBtn();
        }
        function leaveVirtualDb() {
            if (document.getElementById('useVirtualDb')?.value !== '1') return;
            document.getElementById('useVirtualDb').value = '0';
            document.getElementById('connectionPanel')?.classList.remove('d-none');
            document.getElementById('testConnBtn')?.classList.remove('d-none');
            document.getElementById('vdbPanel')?.setAttribute('hidden', '');
            const vid = document.getElementById('vdbId'); if (vid) vid.value = '0';
            const vnl = document.getElementById('vdbNewLabel'); if (vnl) vnl.value = '';
            invalidateConnection();
        }

        // ── Step 3 · Virtual Database pool picker ──────────────────────────
        let vdbLoaded = false, vdbNameEdited = false;
        function loadVdbOptions() {
            if (vdbLoaded) return;
            vdbLoaded = true;
            fetch('<?= rtrim((string) $baseUrl, '/') ?>/projects/vdb-options', { credentials: 'same-origin' })
                .then(r => r.json())
                .then(renderVdbOptions)
                .catch(() => {
                    vdbLoaded = false;
                    const el = document.getElementById('vdbList');
                    if (el) el.innerHTML = '<div class="vdb-loading text-danger">Could not load your databases. A new one will be created automatically.</div>';
                });
        }
        function renderVdbOptions(data) {
            const list = document.getElementById('vdbList');
            const quotaEl = document.getElementById('vdbQuota');
            if (!list) return;
            const dbs = (data && data.databases) || [];
            const quota = (data && data.quota) || { max: 0, used: 0, canCreate: true };

            // Quota meter (only when a finite limit is set).
            if (quotaEl) {
                if (quota.max > 0) {
                    const pct = Math.min(100, Math.round((quota.used / quota.max) * 100));
                    quotaEl.hidden = false;
                    quotaEl.innerHTML = '<i class="bi bi-hdd-stack"></i> <span><b>' + quota.used + '</b> of <b>' + quota.max +
                        '</b> databases used</span><span class="vq-bar"><span class="vq-fill" style="width:' + pct + '%"></span></span>';
                } else { quotaEl.hidden = true; }
            }

            const esc = s => String(s).replace(/[&<>"]/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;' }[c]));
            let html = '';
            dbs.forEach(db => {
                const dis = db.writable ? '' : ' is-disabled';
                const badge = db.writable ? '' : '<span class="vc-badge ro">read-only</span>';
                html += '<button type="button" class="vdb-card' + dis + '" role="radio" aria-checked="false"' +
                    (db.writable ? ' data-vdb-id="' + db.id + '"' : ' disabled title="You only have read access to this database"') + '>' +
                    '<i class="vc-check bi bi-check-circle-fill"></i>' +
                    '<span class="vc-title"><i class="bi bi-database"></i>' + esc(db.label) + '</span>' +
                    '<span class="vc-meta">' + (badge || '<span class="vc-badge">' + esc(db.access) + '</span>') +
                    (db.sizeLabel ? '<span>' + esc(db.sizeLabel) + '</span>' : '') + '</span></button>';
            });
            // "Create new" card.
            const canCreate = quota.canCreate !== false;
            html += '<button type="button" class="vdb-card vdb-create' + (canCreate ? '' : ' is-disabled') + '"' +
                (canCreate ? ' data-vdb-create="1"' : ' disabled title="You have reached your database limit — ask the owner to raise it"') + '>' +
                '<i class="vc-check bi bi-check-circle-fill"></i>' +
                '<span class="vc-title"><i class="bi bi-plus-circle"></i>Create a new database</span>' +
                '<span class="vc-meta">' + (canCreate ? 'A fresh private database, named below' : 'Quota reached — ask the owner to raise it') + '</span>' +
                '<div class="vdb-create-name" hidden><input type="text" class="form-control" id="vdbNameInput" maxlength="120" placeholder="e.g. ' + esc(document.getElementById('projectName')?.value || 'my-app') + '"></div>' +
                '</button>';
            list.innerHTML = html;
            wireVdbCards();
            // Smart default: reuse the first writable DB if any, else the create card.
            const firstWritable = list.querySelector('.vdb-card[data-vdb-id]');
            selectVdbCard(firstWritable || list.querySelector('.vdb-card[data-vdb-create]'));
        }
        function wireVdbCards() {
            document.querySelectorAll('#vdbList .vdb-card').forEach(card => {
                if (card.classList.contains('is-disabled')) return;
                card.addEventListener('click', e => {
                    if (e.target && e.target.id === 'vdbNameInput') return; // don't reselect while typing
                    selectVdbCard(card);
                    if (card.dataset.vdbCreate) document.getElementById('vdbNameInput')?.focus();
                });
            });
            const nameInput = document.getElementById('vdbNameInput');
            if (nameInput) {
                nameInput.addEventListener('input', () => {
                    vdbNameEdited = true;
                    document.getElementById('vdbNewLabel').value = nameInput.value.trim();
                });
            }
        }
        function selectVdbCard(card) {
            if (!card) return;
            document.querySelectorAll('#vdbList .vdb-card').forEach(c => { c.classList.remove('active'); c.setAttribute('aria-checked', 'false'); });
            card.classList.add('active'); card.setAttribute('aria-checked', 'true');
            const isCreate = !!card.dataset.vdbCreate;
            document.querySelectorAll('#vdbList .vdb-create-name').forEach(n => n.hidden = !isCreate);
            if (isCreate) {
                document.getElementById('vdbId').value = '0';
                const nameInput = document.getElementById('vdbNameInput');
                if (nameInput && !vdbNameEdited) nameInput.value = (document.getElementById('projectName')?.value || '').trim();
                document.getElementById('vdbNewLabel').value = (nameInput?.value || '').trim();
            } else {
                document.getElementById('vdbId').value = card.dataset.vdbId || '0';
                document.getElementById('vdbNewLabel').value = '';
            }
            updateCreateBtn();
        }

        function selectDatabase(type) {
            if (type === 'virtual') { selectVirtualDb(); return; }
            leaveVirtualDb();
            const definition = databaseDefinitions[type];
            if (!definition || !definition.available) {
                if (definition) setTestResult(false, definition.requirement + ' before this database can be used.');
                return;
            }

            document.getElementById('dbType').value = type;
            invalidateConnection();   // switching engine needs a fresh test
            document.querySelectorAll('.database-option').forEach(option => {
                const selected = option.dataset.dbType === type;
                option.classList.toggle('active', selected);
                option.setAttribute('aria-pressed', selected ? 'true' : 'false');
            });

            document.getElementById('selectedDbLabel').textContent = definition.label;
            document.getElementById('selectedDbDescription').textContent = definition.description;
            document.getElementById('connectionPanel').style.setProperty('--active-db-color', definition.color);

            const sqlite = type === 'sqlite';
            const postgres = type === 'pgsql';
            const mysqlFamily = type === 'mysql' || type === 'mariadb';
            const sqlServer = type === 'sqlsrv';
            const oracle = type === 'oci';

            setVisible('serverConnectionFields', !sqlite);
            setVisible('sqliteConnectionFields', sqlite);
            setVisible('credentialFields', !sqlite);
            setVisible('schemaField', postgres || sqlServer);
            setVisible('postgresSslField', postgres);
            setVisible('mysqlSslFields', mysqlFamily);
            setVisible('sqlServerSecurityFields', sqlServer);
            setVisible('oracleServiceField', oracle);
            setVisible('charsetField', !sqlite);

            const host = projectForm.querySelector('[name="db_host"]');
            const port = projectForm.querySelector('[name="db_port"]');
            const charset = projectForm.querySelector('[name="db_charset"]');
            const schema = projectForm.querySelector('[name="db_schema"]');
            if (host) host.value = definition.default_host || '';
            if (port) port.value = definition.default_port || '';
            if (charset) charset.value = definition.default_charset || '';
            if (schema) schema.value = postgres ? 'public' : (sqlServer ? 'dbo' : '');
            document.getElementById('databaseNameLabel').textContent = oracle ? 'Database / SID (optional)' : 'Database name';

            if (testResult) testResult.className = 'test-result mt-3';
        }

        document.querySelectorAll('.database-option').forEach(option => {
            option.addEventListener('click', () => {
                selectDatabase(option.dataset.dbType);
            });
        });

        // The Virtual Database tile is the pre-selected default — apply its state
        // (hides the connection panel, enables Create) as soon as the modal wires up.
        selectVirtualDb();

        // Auto-generate slug from name
        const nameInput = document.getElementById('projectName');
        const slugInput = document.getElementById('projectSlug');
        nameInput?.addEventListener('input', function() {
            let slug = this.value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
            slugInput.value = slug;
            // Keep the "create new database" name mirroring the project name until edited.
            const vni = document.getElementById('vdbNameInput');
            const createActive = document.querySelector('#vdbList .vdb-card.vdb-create.active');
            if (vni && createActive && !vdbNameEdited) {
                vni.value = this.value.trim();
                document.getElementById('vdbNewLabel').value = this.value.trim();
            }
        });

        document.getElementById('toggleDbPassword')?.addEventListener('click', function() {
            const password = document.getElementById('dbPassword');
            const reveal = password.type === 'password';
            password.type = reveal ? 'text' : 'password';
            this.querySelector('i').className = 'bi ' + (reveal ? 'bi-eye-slash' : 'bi-eye');
        });

        // Editing any connection field invalidates a prior successful test.
        document.getElementById('connectionPanel')?.addEventListener('input', invalidateConnection);
        // Set the initial disabled state (database mode, nothing tested yet).
        updateCreateBtn();

        // Test database connection
        document.getElementById('testConnBtn')?.addEventListener('click', async function() {
            const btn = this;
            if (!projectForm.reportValidity()) return;
            btn.disabled = true;
            const originalHtml = btn.innerHTML;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Testing…';
            const payload = Object.fromEntries(new FormData(projectForm).entries());
            try {
                const res = await fetch('<?= $baseUrl ?>/projects/test-connection', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(payload)
                });
                const data = await res.json();
                setTestResult(Boolean(data.success), data.message || (data.success ? 'Connection successful.' : 'Connection failed.'));
            } catch (err) {
                setTestResult(false, 'The connection could not be tested. Check the server details and try again.');
            } finally {
                btn.disabled = false;
                btn.innerHTML = originalHtml;
            }
        });

        selectVirtualDb();   // the Virtual Database tile is the recommended default

        document.querySelectorAll('[data-bs-toggle="tooltip"], .database-option[title]').forEach(element => {
            bootstrap.Tooltip.getOrCreateInstance(element);
        });

        // Sidebar toggle (copy from dashboard)
        document.addEventListener('DOMContentLoaded', function() {
            const toggleBtn = document.getElementById('sidebarToggle');
            const sidebar = document.getElementById('sidebarDesktop');
            const main = document.getElementById('mainContent');
            if (toggleBtn && sidebar && main) {
                const collapsed = localStorage.getItem('sidebarCollapsed') === 'true';
                if (collapsed) {
                    sidebar.classList.add('collapsed');
                    main.classList.add('expanded');
                    toggleBtn.querySelector('i').classList.replace('bi-layout-sidebar-inset', 'bi-layout-sidebar');
                }
                toggleBtn.addEventListener('click', function() {
                    const isCollapsed = sidebar.classList.contains('collapsed');
                    if (isCollapsed) {
                        sidebar.classList.remove('collapsed');
                        main.classList.remove('expanded');
                        toggleBtn.querySelector('i').classList.replace('bi-layout-sidebar', 'bi-layout-sidebar-inset');
                        localStorage.setItem('sidebarCollapsed', 'false');
                    } else {
                        sidebar.classList.add('collapsed');
                        main.classList.add('expanded');
                        toggleBtn.querySelector('i').classList.replace('bi-layout-sidebar-inset', 'bi-layout-sidebar');
                        localStorage.setItem('sidebarCollapsed', 'true');
                    }
                });
            }
        });
    </script>

    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/databaseConnection.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectsHub.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectTransfer.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectTemplates.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectHistory.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectSchema.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectScript.js') ?>
    <?= \PpPhp\Core\ModuleAssets::script('Projects', 'Views/scripts/projectPolish.js') ?>
    <?php include constant('BASE_PATH') . '/core/views/flash-alert.php'; ?>
</body>

</html>
