403Webshell
Server IP : 72.60.21.38  /  Your IP : 216.73.217.140
Web Server : LiteSpeed
System : Linux uk-fast-web1372.main-hosting.eu 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User : u390967363 ( 390967363)
PHP Version : 8.2.30
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/u390967363/domains/aibenproperties.com/public_html/app/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/u390967363/domains/aibenproperties.com/public_html/app/client-dashboard.php
<?php
include 'includes/header.php';
require_once 'includes/db.php';
require_once 'includes/functions.php';

function renderGuzapeFaq() { ?>
    <div class="glass card shadow mb-4" id="faq">
        <div class="card-header bg-white py-3">
            <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-circle-question me-2"></i>MOST FAQ</h6>
        </div>
        <div class="card-body">
            <div class="text-muted small mb-3">25 FREQUENTLY ASKED QUESTIONS (FAQ) Regarding all our Properties</div>
            <div class="accordion" id="guzapeFaqAccordion">
                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH1">
                        <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#faqC1" aria-expanded="true" aria-controls="faqC1">
                            1. Why has it taken so long to prepare the land? I have paid for nearly two years.
                        </button>
                    </h2>
                    <div id="faqC1" class="accordion-collapse collapse show" aria-labelledby="faqH1" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We genuinely understand your patience is wearing thin, and we share your urgency. The primary reason, especially for Guzape, is the difficult, mountainous terrain. We are not dealing with flat soil; we are carving a high-value neighborhood out of solid rock. This requires precision blasting, which is a meticulous, time-consuming process we are executing daily to ensure safety and quality. Great things take time, and we are building a legacy.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH2">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC2" aria-expanded="false" aria-controls="faqC2">
                            2. Why can’t I just move onto my land now if 60% is already cleared?
                        </button>
                    </h2>
                    <div id="faqC2" class="accordion-collapse collapse" aria-labelledby="faqH2" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Your safety is our absolute, non-negotiable priority. While 60% of the land is prepared, we are actively blasting the remaining 40% for reclamation. The vibrations and debris from these ongoing activities pose a direct safety risk to anyone living on site. We will never compromise your safety for speed.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH3">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC3" aria-expanded="false" aria-controls="faqC3">
                            3. What are you doing right now to move things forward?
                        </button>
                    </h2>
                    <div id="faqC3" class="accordion-collapse collapse" aria-labelledby="faqH3" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We are on site every single day. Our team is actively engaged in clearing, blasting rocks, and preparing the land for a premium address. We are not resting on our oars; we are investing every effort and resource to transform this challenging terrain into the valuable community you invested in.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH4">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC4" aria-expanded="false" aria-controls="faqC4">
                            4. When will the land be fully ready?
                        </button>
                    </h2>
                    <div id="faqC4" class="accordion-collapse collapse" aria-labelledby="faqH4" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We are asking for your trust for just one more year. We believe this final phase is crucial to prepare the land properly, ensuring you receive the best possible value and a completely safe environment to build your future.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH5">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC5" aria-expanded="false" aria-controls="faqC5">
                            5. The delay is costing me money. What about my Return on Investment (ROI)?
                        </button>
                    </h2>
                    <div id="faqC5" class="accordion-collapse collapse" aria-labelledby="faqH5" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We understand that time is money. While the physical development has taken time, look at the market forces at play: The value of land in Guzape increases by approximately 20% every quarter. This means that despite the wait, the asset you hold has been significantly appreciating. Your patience is currently translating into equity.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH6">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC6" aria-expanded="false" aria-controls="faqC6">
                            6. Is it true that the land value has increased?
                        </button>
                    </h2>
                    <div id="faqC6" class="accordion-collapse collapse" aria-labelledby="faqH6" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Absolutely. The silver lining in this situation is the remarkable appreciation. Guzape remains a highbrow area, and the scarcity of land here, combined with the work we are doing, has driven values up significantly. Your investment is worth substantially more today than when you started.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH7">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC7" aria-expanded="false" aria-controls="faqC7">
                            7. What happens if I can’t wait another year?
                        </button>
                    </h2>
                    <div id="faqC7" class="accordion-collapse collapse" aria-labelledby="faqH7" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We value your partnership above all else. If you cannot wait, we have structured flexible, fair options to ensure you are not left at a loss and can still achieve your property goals.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH8">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC8" aria-expanded="false" aria-controls="faqC8">
                            8. Can I transfer my investment (divest) to another AIBEN project?
                        </button>
                    </h2>
                    <div id="faqC8" class="accordion-collapse collapse" aria-labelledby="faqH8" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Yes, we offer a Divestment option. You can transfer your investment to any of our other Site &amp; Services Projects (like MAR-A-LAGO, HUTU, VICTORY PARK) as they share the same concept. You will receive land of equal value to your current plot, allowing you to realize your dream on a different timeline.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH9">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC9" aria-expanded="false" aria-controls="faqC9">
                            9. What if I want to swap my Guzape land for a plot in One of the Built AIBEN Properties?
                        </button>
                    </h2>
                    <div id="faqC9" class="accordion-collapse collapse" aria-labelledby="faqH9" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            To be transparent, these are different concepts. Kapital Villa and City of Bahrain are “Site and Services” projects, while AIBEN Towers is a “Built-to-Sell” project. However, If you insist on moving there, we can accommodate you, but it would be on a “land for building” basis—meaning we exchange the value for a built unit, not raw land—subject to the specific terms of that project.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH10">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC10" aria-expanded="false" aria-controls="faqC10">
                            10. Can I swap my land for a plot in HECTARE VEST?
                        </button>
                    </h2>
                    <div id="faqC10" class="accordion-collapse collapse" aria-labelledby="faqH10" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Hectare purchases are a specialized investment portfolio targeted at large-scale fundraising. However, should you insist, we value your loyalty. In this specific case, we would admit the amount you originally paid, plus a 10% increase, rather than the current market value of the property.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH11">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC11" aria-expanded="false" aria-controls="faqC11">
                            11. What if I just want my money back?
                        </button>
                    </h2>
                    <div id="faqC11" class="accordion-collapse collapse" aria-labelledby="faqH11" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            While we don't believe a refund is in your best interest—given the significant appreciation your land has experienced—we will not hold you captive. Should you insist on a refund, we will process the amount paid, less a 20% administrative charge, within 90 working days.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH12">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC12" aria-expanded="false" aria-controls="faqC12">
                            12. What if I want to sell my land on the open market and cash out?
                        </button>
                    </h2>
                    <div id="faqC12" class="accordion-collapse collapse" aria-labelledby="faqH12" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We can facilitate the sale of your asset. Given the high demand in Guzape, we are confident we can find a buyer for your plot within 90 working days at the prevailing market price.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH13">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC13" aria-expanded="false" aria-controls="faqC13">
                            13. If AIBEN sells my land, what are the terms?
                        </button>
                    </h2>
                    <div id="faqC13" class="accordion-collapse collapse" aria-labelledby="faqH13" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            <div class="mb-2">We offer two pathways:</div>
                            <ul class="mb-0">
                                <li>If you haven't paid the infrastructure fee: AIBEN will handle the sale, retain a 5% commission on the sales value, and perfect the change of ownership for the new buyer at no extra cost to you.</li>
                                <li>If you have paid the infrastructure fee: To cover marketing and transaction costs, AIBEN will retain a 20% commission on the sale price. You will receive 80% of the appreciated market value in cash.</li>
                            </ul>
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH13b">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC13b" aria-expanded="false" aria-controls="faqC13b">
                            13. Why is the infrastructure fee 20%? Isn't that high?
                        </button>
                    </h2>
                    <div id="faqC13b" class="accordion-collapse collapse" aria-labelledby="faqH13b" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Compared to the market reality, it is actually quite fair. Other top-tier developers tackling similar rocky terrain typically charge up to 35% for infrastructure. We charge only 20% because we view you not just as a customer, but as a true partner in this progress.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH14">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC14" aria-expanded="false" aria-controls="faqC14">
                            14. What exactly does the infrastructure fee cover?
                        </button>
                    </h2>
                    <div id="faqC14" class="accordion-collapse collapse" aria-labelledby="faqH14" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            This fee covers the massive cost of land reclamation—the blasting of rocks, excavation, grading, and primary road network that turns a mountain into a buildable, accessible, and valuable piece of real estate.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH15">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC15" aria-expanded="false" aria-controls="faqC15">
                            15. Why is the infrastructure fee reviewed twice a year? Is this just for Guzape?
                        </button>
                    </h2>
                    <div id="faqC15" class="accordion-collapse collapse" aria-labelledby="faqH15" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            This is now a standard policy across all our projects to ensure we can deliver high-quality infrastructure without fail. It creates a win-win situation: it protects AIBEN from being crippled by inflation (diesel, explosives, machinery costs), which would stall the project, while giving you the flexibility to pay when funds are available.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH16">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC16" aria-expanded="false" aria-controls="faqC16">
                            16. How does AIBEN arrive at the "current land value" for the fee adjustment?
                        </button>
                    </h2>
                    <div id="faqC16" class="accordion-collapse collapse" aria-labelledby="faqH16" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We engage in a formal market survey and land valuation twice every year (effective January 1st and July 1st). This ensures our pricing reflects the true market. If you ever feel our valuation is inaccurate, you are welcome to conduct your own valuation through an accredited/licensed valuer at your convenience.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH18">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC18" aria-expanded="false" aria-controls="faqC18">
                            18. How can I avoid the bi-annual infrastructure increase?
                        </button>
                    </h2>
                    <div id="faqC18" class="accordion-collapse collapse" aria-labelledby="faqH18" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            The best way to avoid the increase is to commit to your infrastructure payments promptly. By paying early, you lock in the current cost and help us keep the project moving forward for everyone.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH19">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC19" aria-expanded="false" aria-controls="faqC19">
                            19. Is the fee adjustment a penalty for defaulters?
                        </button>
                    </h2>
                    <div id="faqC19" class="accordion-collapse collapse" aria-labelledby="faqH19" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Not at all. It is a protection mechanism, not a penalty. It ensures the project's financial health against inflation. Those who settle their fees promptly are essentially future-proofing their own investment at today's costs.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH20">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC20" aria-expanded="false" aria-controls="faqC20">
                            20. How can I be sure you will finish in one year?
                        </button>
                    </h2>
                    <div id="faqC20" class="accordion-collapse collapse" aria-labelledby="faqH20" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We have already conquered 60% of the site. We have the equipment, the team, and the expertise on the ground. Our request for one year is based on realistic, professional projections of the remaining work, not a guess.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH21">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC21" aria-expanded="false" aria-controls="faqC21">
                            21. Is the land safe to build on after blasting?
                        </button>
                    </h2>
                    <div id="faqC21" class="accordion-collapse collapse" aria-labelledby="faqH21" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Yes, absolutely. The blasting process, while intensive, is a form of engineering that creates a solid, stable foundation. Once we finish and give the all-clear, the land will be perfectly suited for construction.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH22">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC22" aria-expanded="false" aria-controls="faqC22">
                            22. I've heard stories of people losing money in land. Is my money safe?
                        </button>
                    </h2>
                    <div id="faqC22" class="accordion-collapse collapse" aria-labelledby="faqH22" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Your money is safe in the appreciating asset you hold. While the timeline has been a challenge, the fundamental value of your investment has grown significantly. We are a top-tier developer committed to delivering a premium product, not walking away from a project.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH23">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC23" aria-expanded="false" aria-controls="faqC23">
                            23. What is the long-term vision for Guzape and these other communities?
                        </button>
                    </h2>
                    <div id="faqC23" class="accordion-collapse collapse" aria-labelledby="faqH23" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We are not just selling plots; we are developing communities. From the luxury of Maralago Lake City to the vision of City of Bahrain, and the prime location of Guzape, our goal is to create spaces that offer not just a home, but a lifestyle and a legacy of value.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH24">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC24" aria-expanded="false" aria-controls="faqC24">
                            24. Why should I trust AIBEN Properties with my investment?
                        </button>
                    </h2>
                    <div id="faqC24" class="accordion-collapse collapse" aria-labelledby="faqH24" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            Because we are here. We are on site, we are being transparent about our challenges, and we are offering you control through flexible solutions—whether you choose to wait and reap the rewards of appreciation, divest, or sell. We are partners in this journey.
                        </div>
                    </div>
                </div>

                <div class="accordion-item">
                    <h2 class="accordion-header" id="faqH25">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqC25" aria-expanded="false" aria-controls="faqC25">
                            25. I feel like I'm being given options that all benefit the company. What is the best option for me?
                        </button>
                    </h2>
                    <div id="faqC25" class="accordion-collapse collapse" aria-labelledby="faqH25" data-bs-parent="#guzapeFaqAccordion">
                        <div class="accordion-body">
                            We believe the best option for you is to hold and wait for that one year. The 20% quarterly appreciation means your patience is directly building your wealth. The other options are safety nets for different circumstances, but the highest potential return lies in seeing this project through to completion with us.
                        </div>
                    </div>
                </div>
            </div>
            <div class="text-center mt-3 fw-bold">THANK YOU FOR YOUR PARTNERSHIP</div>
        </div>
    </div>
<?php }

// Access Control & Admin Viewer
if (!isset($_SESSION['user_id'])) {
    header("Location: index.php");
    exit;
}
$role = $_SESSION['user_role'] ?? 'guest';
$isAdminTier = in_array($role, ['super_admin','admin']);
$isFaqView = (($_GET['view'] ?? '') === 'faq');
$user_id = 0;
$clientIdParam = (isset($_GET['client_id']) && ctype_digit($_GET['client_id'])) ? (int)$_GET['client_id'] : 0;
if ($role === 'client') {
    $user_id = (int)$_SESSION['user_id'];
    $welcome_name = $_SESSION['user_name'] ?? 'Client';
} elseif ($isAdminTier && $clientIdParam > 0) {
    $user_id = $clientIdParam;
    try {
        $stName = $pdo->prepare("SELECT name FROM users WHERE id = ? AND role = 'client'");
        $stName->execute([$user_id]);
        $welcome_name = $stName->fetchColumn() ?: 'Client';
    } catch (Exception $e) {
        $welcome_name = 'Client';
    }
} elseif ($isAdminTier) {
    $welcome_name = 'Client Viewer';
    ?>
    <div class="container-fluid px-4 journey-dashboard-shell">
        <div class="d-flex justify-content-between align-items-center mt-4 mb-4">
            <div>
                <h1 class="h3 mb-0 text-navy">Client Portal</h1>
                <p class="text-muted">Select a client to open their dashboard</p>
            </div>
        </div>
        <div class="glass card shadow-sm">
            <div class="card-header bg-white">
                <strong>Select Client</strong>
            </div>
            <div class="card-body">
                <form method="GET" class="row g-3 align-items-end">
                    <div class="col-md-6">
                        <label class="form-label">Client</label>
                        <select name="client_id" class="form-select" required>
                            <option value="">-- Choose Client --</option>
                            <?php
                            try {
                                $q = $pdo->query("SELECT id, name, email FROM users WHERE role = 'client' ORDER BY created_at DESC LIMIT 200");
                                while ($c = $q->fetch(PDO::FETCH_ASSOC)) {
                                    $label = htmlspecialchars($c['name'] . ' — ' . ($c['email'] ?? ''));
                                    echo '<option value="' . (int)$c['id'] . '">' . $label . '</option>';
                                }
                            } catch (Exception $e) {}
                            ?>
                        </select>
                    </div>
                    <div class="col-md-3">
                        <button class="btn btn-primary" type="submit"><i class="fa-solid fa-eye me-2"></i>View Dashboard</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
    <?php
    include 'includes/footer.php';
    exit;
} else {
    header("Location: index.php");
    exit;
}

if ($isFaqView && ($role === 'client' || ($isAdminTier && $user_id > 0))) {
    ?>
    <div class="container-fluid px-4">
        <div class="d-flex justify-content-between align-items-center mt-4 mb-4">
            <div>
                <h1 class="h3 mb-0 text-navy">FAQ</h1>
                <p class="text-muted"><?= $isAdminTier ? 'Admin Viewer of Client FAQ' : 'Frequently Asked Questions' ?></p>
            </div>
            <div>
                <a href="client-dashboard.php" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-arrow-left me-2"></i>Back</a>
            </div>
        </div>
        <?php renderGuzapeFaq(); ?>
    </div>
    <?php
    include 'includes/footer.php';
    exit;
}

// Client lockdown view (use same UI when admin is viewing a specific client)
if ($role === 'client' || ($isAdminTier && $user_id > 0)) {
    // Determine client payments page
    $clientPaymentsPage = file_exists(__DIR__ . '/client-payments.php') ? 'client-payments.php' : (file_exists(__DIR__ . '/my-invoices.php') ? 'my-invoices.php' : null);
    // Allocation letter gating: only show when document has been released to client
    $allocation_letter_url = null;
    $transfer_certificate_url = null;
    $showChairmanMessage = false;
    try {
        $hasDocsTbl = $pdo->query("SHOW TABLES LIKE 'documents'")->rowCount() > 0;
        if ($hasDocsTbl) {
            $hasType = function_exists('tableHasColumn') && tableHasColumn('documents', 'type');
            $hasStatus = function_exists('tableHasColumn') && tableHasColumn('documents', 'status');
            $hasUpdatedAt = function_exists('tableHasColumn') && tableHasColumn('documents', 'updated_at');
            $hasCreatedAt = function_exists('tableHasColumn') && tableHasColumn('documents', 'created_at');
            $hasDocAllocId = function_exists('tableHasColumn') && tableHasColumn('documents', 'allocation_id');
            $orderExpr = 'id DESC';
            if ($hasUpdatedAt && $hasCreatedAt) { $orderExpr = "COALESCE(updated_at, created_at) DESC, id DESC"; }
            elseif ($hasUpdatedAt) { $orderExpr = "updated_at DESC, id DESC"; }
            elseif ($hasCreatedAt) { $orderExpr = "created_at DESC, id DESC"; }

            $latestAllocId = 0;
            try {
                $hasAllocsTbl = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
                if ($hasAllocsTbl) {
                    $allocWhere = "user_id = ?";
                    if (function_exists('tableHasColumn') && tableHasColumn('allocations', 'status')) { $allocWhere .= " AND LOWER(TRIM(status)) <> 'transferred'"; }
                    $stA = $pdo->prepare("SELECT id FROM allocations WHERE {$allocWhere} ORDER BY id DESC LIMIT 1");
                    $stA->execute([$user_id]);
                    $latestAllocId = (int)($stA->fetchColumn() ?: 0);
                }
            } catch (Throwable $e) { $latestAllocId = 0; }

            $whereAlloc = "user_id = ?";
            $paramsAlloc = [$user_id];
            if ($hasType) { $whereAlloc .= " AND (type IN ('allocation_letter','allocation','letter') OR file_path LIKE '%Allocation_Letter_%')"; }
            else { $whereAlloc .= " AND file_path LIKE '%Allocation_Letter_%'"; }
            if ($hasStatus) { $whereAlloc .= " AND LOWER(TRIM(status)) IN ('released','issued','signed','approved','draft','pending')"; }
            if ($latestAllocId > 0 && $hasDocAllocId) {
                $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereAlloc} AND allocation_id = ? ORDER BY {$orderExpr} LIMIT 1");
                $st->execute(array_merge($paramsAlloc, [$latestAllocId]));
                $allocation_letter_url = $st->fetchColumn() ?: null;
            }
            if (!$allocation_letter_url) {
                $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereAlloc} ORDER BY {$orderExpr} LIMIT 1");
                $st->execute($paramsAlloc);
                $allocation_letter_url = $st->fetchColumn() ?: null;
            }

            $whereCert = "user_id = ?";
            $paramsCert = [$user_id];
            if ($hasType) { $whereCert .= " AND (type IN ('transfer_certificate') OR file_path LIKE '%Transfer_Certificate_%')"; }
            else { $whereCert .= " AND file_path LIKE '%Transfer_Certificate_%'"; }
            if ($hasStatus) { $whereCert .= " AND LOWER(TRIM(status)) IN ('released','issued','signed','approved','draft','pending')"; }
            if ($latestAllocId > 0 && $hasDocAllocId) {
                $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereCert} AND allocation_id = ? ORDER BY {$orderExpr} LIMIT 1");
                $st->execute(array_merge($paramsCert, [$latestAllocId]));
                $transfer_certificate_url = $st->fetchColumn() ?: null;
            }
            if (!$transfer_certificate_url) {
                $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereCert} ORDER BY {$orderExpr} LIMIT 1");
                $st->execute($paramsCert);
                $transfer_certificate_url = $st->fetchColumn() ?: null;
            }
        }
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT status FROM client_forms WHERE client_id = ? ORDER BY updated_at DESC, created_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $onboardingStatus = strtolower((string)($st->fetchColumn() ?: ''));
        $showChairmanMessage = in_array($onboardingStatus, ['approved', 'payment_verified'], true);
    } catch (Exception $e) {}
    $journeyFormRow = null;
    $journeyOfferLetterPath = null;
    $journeyPaymentVerified = false;
    $journeyPendingCount = 0;
    $journeyAllocApproved = false;
    try {
        $st = $pdo->prepare("SELECT * FROM client_forms WHERE client_id = ? ORDER BY updated_at DESC, created_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyFormRow = $st->fetch(PDO::FETCH_ASSOC) ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT file_path FROM documents WHERE user_id = ? AND type = 'offer_letter' AND status IN ('draft','approved','issued','signed') ORDER BY updated_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyOfferLetterPath = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT COUNT(*) FROM payments WHERE user_id = ? AND status IN ('verified','approved','completed','paid','success')");
        $st->execute([$user_id]);
        $journeyPaymentVerified = ((int)$st->fetchColumn() > 0);
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT COUNT(*) FROM payments WHERE user_id = ? AND status IN ('pending','submitted','awaiting_verification','pending_verification')");
        $st->execute([$user_id]);
        $journeyPendingCount = (int)$st->fetchColumn();
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT status FROM allocations WHERE user_id = ? AND status <> 'transferred' ORDER BY updated_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyAllocApproved = in_array(strtolower((string)($st->fetchColumn() ?: '')), ['approved', 'executive_approved', 'allocated', 'completed', 'finalized', 'active'], true);
    } catch (Exception $e) {}
    $journeyFormStatus = strtolower(trim((string)($journeyFormRow['status'] ?? '')));
    $journeyHasDraft = !empty($journeyFormRow);
    $journeyHasForm = in_array($journeyFormStatus, ['payment_verification', 'payment_verified', 'approved'], true);
    $journeyFormInProgress = $journeyHasDraft && !$journeyHasForm;
    $journeyHasReceipt = !empty($journeyFormRow['receipt_path']);
    $journeyOfferApproved = !empty($journeyOfferLetterPath);
    $journeyAllocationReady = $journeyAllocApproved || !empty($allocation_letter_url);

    $latestTransfer = null;
    try {
        $hasTransfersTbl = $pdo->query("SHOW TABLES LIKE 'ownership_transfers'")->rowCount() > 0;
        if ($hasTransfersTbl) {
            $companyIdT = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : (int)($_SESSION['company_id'] ?? 0);
            $paramsT = [$user_id, $user_id];
            $qT = "SELECT t.*, p.title AS property_title
                   FROM ownership_transfers t
                   LEFT JOIN properties p ON t.property_id = p.id
                   WHERE (t.seller_id = ? OR t.buyer_id = ?)";
            if ($companyIdT && function_exists('tableHasColumn') && tableHasColumn('ownership_transfers', 'company_id')) {
                $qT .= " AND (t.company_id = ? OR t.company_id IS NULL OR t.company_id = 0)";
                $paramsT[] = $companyIdT;
            }
            $qT .= " ORDER BY t.id DESC LIMIT 1";
            $stT = $pdo->prepare($qT);
            $stT->execute($paramsT);
            $latestTransfer = $stT->fetch(PDO::FETCH_ASSOC) ?: null;
        }
    } catch (Throwable $e) { $latestTransfer = null; }
    $myCelebrations = null;
    $myCelebrationCards = [];
    $celebrationPopup = null;
    try {
        if (function_exists('ap_get_client_celebrations')) {
            $myCelebrations = ap_get_client_celebrations($pdo, $user_id, 30);
            if (!empty($myCelebrations['birthday']) && is_array($myCelebrations['birthday'])) {
                $myCelebrationCards[] = [
                    'kind' => 'birthday',
                    'icon' => 'fa-solid fa-cake-candles',
                    'title' => 'Your Birthday',
                    'meta' => (string)($myCelebrations['birthday']['label'] ?? ''),
                    'date' => (string)($myCelebrations['birthday']['occurs_on'] ?? ''),
                ];
            }
            if (!empty($myCelebrations['anniversary']) && is_array($myCelebrations['anniversary'])) {
                $myCelebrationCards[] = [
                    'kind' => 'anniversary',
                    'icon' => 'fa-solid fa-heart',
                    'title' => 'Your Anniversary',
                    'meta' => (string)($myCelebrations['anniversary']['label'] ?? ''),
                    'date' => (string)($myCelebrations['anniversary']['occurs_on'] ?? ''),
                ];
            }
            $birthdayToday = is_array($myCelebrations['birthday'] ?? null)
                && is_array($myCelebrations['birthday'])
                && array_key_exists('days_until', $myCelebrations['birthday'])
                && (int)$myCelebrations['birthday']['days_until'] === 0;
            $anniversaryToday = is_array($myCelebrations['anniversary'] ?? null)
                && is_array($myCelebrations['anniversary'] ?? [])
                && array_key_exists('days_until', $myCelebrations['anniversary'] ?? [])
                && isset($myCelebrations['anniversary']['days_until']) && (int)$myCelebrations['anniversary']['days_until'] === 0;
            if ($birthdayToday || $anniversaryToday) {
                $companyDisplayName = function_exists('getSetting')
                    ? trim((string)getSetting('company_name', 'Aiben Properties'))
                    : 'Aiben Properties';
                if ($companyDisplayName === '') {
                    $companyDisplayName = 'Aiben Properties';
                }
                $kinds = [];
                $headline = '';
                $detail = '';
                if ($birthdayToday && $anniversaryToday) {
                    $kinds = ['birthday', 'anniversary'];
                    $headline = 'Today we celebrate you!';
                    $detail = 'Happy Birthday and Happy Anniversary from everyone at ' . $companyDisplayName . '.';
                } elseif ($birthdayToday) {
                    $kinds = ['birthday'];
                    $headline = 'Happy Birthday, ' . trim((string)$welcome_name) . '!';
                    $detail = 'Wishing you a wonderful day from everyone at ' . $companyDisplayName . '.';
                } else {
                    $kinds = ['anniversary'];
                    $headline = 'Happy Anniversary, ' . trim((string)$welcome_name) . '!';
                    $detail = 'Congratulations and best wishes from everyone at ' . $companyDisplayName . '.';
                }
                $celebrationPopup = [
                    'kinds' => $kinds,
                    'headline' => $headline,
                    'detail' => $detail,
                ];
            }
        }
    } catch (Throwable $e) {
        $myCelebrations = null;
        $myCelebrationCards = [];
        $celebrationPopup = null;
    }
    $journeyCurrentStep = 'profile';
    $journeyMessage = 'Complete your onboarding form to proceed.';
    $journeyMessageDetail = 'This helps us verify your details and prepare your offer.';
    if (!$journeyHasForm) {
        $journeyCurrentStep = 'onboarding';
        $journeyMessage = $journeyFormInProgress
            ? 'Continue your onboarding form to proceed.'
            : 'Complete your onboarding form to proceed.';
        $journeyMessageDetail = $journeyFormInProgress
            ? 'Your saved draft is ready. Return to the form and continue from where you stopped.'
            : 'This helps us verify your details and prepare your offer.';
    } elseif (!$journeyPaymentVerified) {
        $journeyCurrentStep = 'form_payment';
        $journeyMessage = $journeyHasReceipt || $journeyPendingCount > 0
            ? 'Your form payment is under review. Our team will confirm it shortly.'
            : 'Complete your onboarding form to proceed.';
        $journeyMessageDetail = $journeyHasReceipt || $journeyPendingCount > 0
            ? 'We are checking your payment details before moving you to the next stage.'
            : 'This helps us verify your details and prepare your offer.';
    } elseif (!$journeyOfferApproved) {
        $journeyCurrentStep = 'offer_letter';
        $journeyMessage = 'Your onboarding is complete. Await your offer letter.';
        $journeyMessageDetail = 'Our team is reviewing your details and preparing the next document for you.';
    } elseif (!$journeyAllocationReady) {
        $journeyCurrentStep = 'property_payment';
        $journeyMessage = 'Your offer letter has been shared. Our team will guide your next payment.';
        if ($journeyPendingCount > 0) {
            $journeyCurrentStep = 'allocation';
            $journeyMessage = 'Await allocation confirmation from management.';
            $journeyMessageDetail = 'Your records are being finalized while management confirms the next update.';
        } else {
            $journeyMessage = 'Your payment will be processed offline by our team.';
            $journeyMessageDetail = 'Our team will contact you directly and guide you through the next payment stage.';
        }
    } else {
        $journeyCurrentStep = 'allocation';
        $journeyMessage = 'Await allocation confirmation from management.';
        $journeyMessageDetail = 'Your records are being finalized while management confirms the next update.';
    }
    $journeySteps = [
        ['key' => 'profile', 'label' => 'Profile', 'icon' => 'fa-solid fa-user', 'helper' => 'Your account is set up'],
        ['key' => 'onboarding', 'label' => 'Onboarding Form', 'icon' => 'fa-solid fa-id-card', 'helper' => 'Submit your onboarding details'],
        ['key' => 'form_payment', 'label' => 'Form Payment', 'icon' => 'fa-solid fa-wallet', 'helper' => 'Pay for your onboarding form'],
        ['key' => 'offer_letter', 'label' => 'Offer Letter', 'icon' => 'fa-solid fa-file-lines', 'helper' => 'Prepared by our team'],
        ['key' => 'property_payment', 'label' => 'Property Payment', 'icon' => 'fa-solid fa-building-columns', 'helper' => 'Handled offline with our team'],
        ['key' => 'allocation', 'label' => 'Allocation', 'icon' => 'fa-solid fa-key', 'helper' => 'Assigned after approval'],
    ];
    $journeyStateMap = [
        'profile' => 'completed',
        'onboarding' => $journeyHasForm ? 'completed' : ($journeyCurrentStep === 'onboarding' ? 'current' : 'pending'),
        'form_payment' => $journeyPaymentVerified ? 'completed' : ($journeyCurrentStep === 'form_payment' ? 'current' : 'pending'),
        'offer_letter' => $journeyOfferApproved ? 'completed' : ($journeyCurrentStep === 'offer_letter' ? 'current' : 'pending'),
        'property_payment' => $journeyAllocationReady ? 'completed' : ($journeyCurrentStep === 'property_payment' ? 'current' : 'pending'),
        'allocation' => $journeyAllocationReady ? 'completed' : ($journeyCurrentStep === 'allocation' ? 'current' : 'pending'),
    ];
    $journeyCurrentDescriptions = [
        'profile' => 'Your account is ready to begin the process.',
        'onboarding' => $journeyFormInProgress
            ? 'Continue your saved onboarding form to proceed.'
            : 'Complete your onboarding form to proceed.',
        'form_payment' => 'Pay for your onboarding form to move to the next stage.',
        'offer_letter' => 'Your offer letter is being prepared by our team.',
        'property_payment' => 'Your next payment stage is handled directly with our team.',
        'allocation' => 'Allocation is pending final confirmation and release.',
    ];
    $journeyCurrentLinks = [
        'onboarding' => 'client-onboarding.php?view=form',
    ];
    $journeyCompletedCount = 0;
    foreach ($journeyStateMap as $journeyState) {
        if ($journeyState === 'completed') {
            $journeyCompletedCount++;
        }
    }
    $journeyProgressPercent = (int) round(($journeyCompletedCount / max(count($journeySteps), 1)) * 100);
    $journeyProfileDate = null;
    $journeyVerifiedPaymentDate = null;
    $journeyLatestPaymentDate = null;
    $journeyPaymentCount = 0;
    $journeyOfferDate = null;
    $journeyAllocationDate = null;
    try {
        $st = $pdo->prepare("SELECT created_at FROM users WHERE id = ? LIMIT 1");
        $st->execute([$user_id]);
        $journeyProfileDate = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT IFNULL(updated_at, created_at) FROM payments WHERE user_id = ? AND status IN ('verified','approved','completed','paid','success') ORDER BY IFNULL(updated_at, created_at) DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyVerifiedPaymentDate = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT COUNT(*) FROM payments WHERE user_id = ? AND status <> 'rejected'");
        $st->execute([$user_id]);
        $journeyPaymentCount = (int)$st->fetchColumn();
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT IFNULL(updated_at, created_at) FROM payments WHERE user_id = ? AND status <> 'rejected' ORDER BY IFNULL(updated_at, created_at) DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyLatestPaymentDate = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT IFNULL(updated_at, created_at) FROM documents WHERE user_id = ? AND type = 'offer_letter' AND status IN ('draft','approved','issued','signed') ORDER BY updated_at DESC, created_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyOfferDate = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    try {
        $st = $pdo->prepare("SELECT IFNULL(updated_at, created_at) FROM allocations WHERE user_id = ? AND status IN ('approved','completed','active') ORDER BY updated_at DESC LIMIT 1");
        $st->execute([$user_id]);
        $journeyAllocationDate = $st->fetchColumn() ?: null;
    } catch (Exception $e) {}
    if (!$journeyAllocationDate && $journeyAllocationReady) {
        try {
            $st = $pdo->prepare("SELECT IFNULL(updated_at, created_at) FROM documents WHERE user_id = ? AND type IN ('allocation_letter','allocation') AND status IN ('approved','issued','signed','released') ORDER BY updated_at DESC, created_at DESC LIMIT 1");
            $st->execute([$user_id]);
            $journeyAllocationDate = $st->fetchColumn() ?: null;
        } catch (Exception $e) {}
    }
    $journeyWhatNext = 'Once you complete your onboarding form, our team will review your details and prepare your offer letter.';
    if ($journeyCurrentStep === 'form_payment') {
        $journeyWhatNext = $journeyHasReceipt || $journeyPendingCount > 0
            ? 'After your payment is verified, your offer letter will be issued.'
            : 'Upload your form payment and our team will verify it before issuing your offer letter.';
    } elseif ($journeyCurrentStep === 'offer_letter') {
        $journeyWhatNext = 'Your offer letter is being prepared. Once it is ready, our team will guide you through the next payment stage.';
    } elseif ($journeyCurrentStep === 'property_payment') {
        $journeyWhatNext = 'You can proceed with property payment. Allocation will follow management approval.';
    } elseif ($journeyCurrentStep === 'allocation') {
        $journeyWhatNext = 'Management is reviewing your records. Once approved, your allocation will be confirmed on your dashboard.';
    }
    $journeyFormPaymentUploaded = $journeyHasReceipt || $journeyPendingCount > 0 || $journeyPaymentVerified;
    $journeyPaymentUploadCurrent = ($journeyCurrentStep === 'form_payment' && !$journeyFormPaymentUploaded);
    $journeyPaymentReviewCurrent = ($journeyCurrentStep === 'form_payment' && $journeyFormPaymentUploaded && !$journeyPaymentVerified);
    $journeyPropertyPaymentRecorded = ($journeyCurrentStep === 'allocation') || $journeyAllocationReady;
    $journeyTimelineItems = [
        [
            'key' => 'profile_created',
            'title' => 'Profile Created',
            'description' => 'Your account was successfully set up.',
            'icon' => 'fa-solid fa-user-check',
            'state' => 'completed',
            'date' => $journeyProfileDate,
        ],
        [
            'key' => 'onboarding_submitted',
            'title' => $journeyHasForm ? 'Onboarding Form Submitted' : ($journeyFormInProgress ? 'Onboarding Form (Draft Saved)' : 'Onboarding Form (In Progress)'),
            'description' => $journeyHasForm
                ? 'Your onboarding form has been received.'
                : ($journeyFormInProgress
                    ? 'Your draft is saved. Return to the form and continue until submission.'
                    : 'Complete your onboarding form to continue.'),
            'icon' => 'fa-solid fa-id-card',
            'state' => $journeyHasForm ? 'completed' : ($journeyCurrentStep === 'onboarding' ? 'current' : 'pending'),
            'date' => $journeyHasForm
                ? ($journeyFormRow['updated_at'] ?? ($journeyFormRow['created_at'] ?? null))
                : ($journeyFormInProgress ? ($journeyFormRow['updated_at'] ?? ($journeyFormRow['created_at'] ?? null)) : null),
        ],
        [
            'key' => 'form_payment_uploaded',
            'title' => 'Form Payment Uploaded',
            'description' => $journeyFormPaymentUploaded ? 'Your form payment proof has been received.' : 'Upload your form payment receipt to continue.',
            'icon' => 'fa-solid fa-wallet',
            'state' => $journeyFormPaymentUploaded ? 'completed' : ($journeyPaymentUploadCurrent ? 'current' : 'pending'),
            'date' => $journeyFormPaymentUploaded ? ($journeyFormRow['updated_at'] ?? ($journeyFormRow['created_at'] ?? null)) : null,
        ],
        [
            'key' => 'payment_verified',
            'title' => 'Payment Verified',
            'description' => $journeyPaymentVerified ? 'Your form payment has been verified.' : ($journeyPaymentReviewCurrent ? 'We are reviewing your uploaded form payment.' : 'Payment verification will appear here once review is complete.'),
            'icon' => 'fa-solid fa-badge-check',
            'state' => $journeyPaymentVerified ? 'completed' : ($journeyPaymentReviewCurrent ? 'current' : 'pending'),
            'date' => $journeyPaymentVerified ? $journeyVerifiedPaymentDate : null,
        ],
        [
            'key' => 'offer_letter_sent',
            'title' => 'Offer Letter Sent',
            'description' => $journeyOfferApproved ? 'Your offer letter has been shared with you.' : ($journeyCurrentStep === 'offer_letter' ? 'Your offer letter is being prepared by our team.' : 'Offer letter will be issued after verification.'),
            'icon' => 'fa-solid fa-file-lines',
            'state' => $journeyOfferApproved ? 'completed' : ($journeyCurrentStep === 'offer_letter' ? 'current' : 'pending'),
            'date' => $journeyOfferApproved ? $journeyOfferDate : null,
        ],
        [
            'key' => 'property_payment_recorded',
            'title' => 'Property Payment Recorded',
            'description' => $journeyPropertyPaymentRecorded ? 'Your property payment has been recorded by our team.' : ($journeyCurrentStep === 'property_payment' ? 'Your next payment will be coordinated offline with our team.' : 'Property payment will appear after your offer letter.'),
            'icon' => 'fa-solid fa-building-columns',
            'state' => $journeyPropertyPaymentRecorded ? 'completed' : ($journeyCurrentStep === 'property_payment' ? 'current' : 'pending'),
            'date' => $journeyPropertyPaymentRecorded ? $journeyLatestPaymentDate : null,
        ],
        [
            'key' => 'allocation_approved',
            'title' => 'Allocation Approved',
            'description' => $journeyAllocationReady ? 'Your property allocation has been approved.' : ($journeyCurrentStep === 'allocation' ? 'Allocation is awaiting management approval.' : 'Allocation follows payment confirmation and approval.'),
            'icon' => 'fa-solid fa-key',
            'state' => $journeyAllocationReady ? 'completed' : ($journeyCurrentStep === 'allocation' ? 'current' : 'pending'),
            'date' => $journeyAllocationReady ? $journeyAllocationDate : null,
        ],
    ];
    $journeyRecentKey = '';
    $journeyRecentTs = 0;
    foreach ($journeyTimelineItems as $journeyTimelineItem) {
        $timelineTs = !empty($journeyTimelineItem['date']) ? (int)strtotime((string)$journeyTimelineItem['date']) : 0;
        if ($timelineTs >= $journeyRecentTs && in_array($journeyTimelineItem['state'], ['completed', 'current'], true)) {
            $journeyRecentTs = $timelineTs;
            $journeyRecentKey = $journeyTimelineItem['key'];
        }
    }
    if ($journeyRecentKey === '') {
        foreach ($journeyTimelineItems as $journeyTimelineItem) {
            if ($journeyTimelineItem['state'] === 'current') {
                $journeyRecentKey = $journeyTimelineItem['key'];
                break;
            }
        }
    }
    foreach ($journeyTimelineItems as &$journeyTimelineItem) {
        $journeyTimelineItem['is_recent'] = ($journeyTimelineItem['key'] === $journeyRecentKey);
    }
    unset($journeyTimelineItem);
    $journeyNotifications = [];
    if (!$journeyHasForm) {
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-hourglass-half',
            'title' => 'Your onboarding is in progress',
            'detail' => $journeyFormInProgress
                ? 'Your saved draft is waiting for you. Open the form to continue from where you stopped.'
                : 'Your onboarding is active and the dashboard is guiding you through the next step.'
        ];
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-list-check',
            'title' => $journeyFormInProgress ? 'Continue your onboarding form' : 'Complete your onboarding form',
            'detail' => $journeyFormInProgress
                ? 'Your card will stay in progress until you submit the form.'
                : 'Submit your onboarding form to unlock payment and the next milestone.'
        ];
    }
    if ($journeyCurrentStep === 'form_payment') {
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-wallet',
            'title' => $journeyHasReceipt || $journeyPendingCount > 0 ? 'Your form payment is under review' : 'Upload your form payment',
            'detail' => $journeyHasReceipt || $journeyPendingCount > 0 ? 'We are reviewing your payment before issuing your offer letter.' : 'Your payment upload will appear here once submitted.'
        ];
    }
    if (!$journeyOfferApproved) {
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-file-signature',
            'title' => 'Offer letter will be issued soon',
            'detail' => 'Our team prepares this after your verification stage is complete.'
        ];
    }
    if ($journeyOfferApproved && !$journeyAllocationReady) {
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-key',
            'title' => 'Allocation will follow approval',
            'detail' => 'Property payment is handled offline and allocation follows management confirmation.'
        ];
    }
    if ($journeyAllocationReady) {
        $journeyNotifications[] = [
            'icon' => 'fa-solid fa-circle-check',
            'title' => 'Allocation update available',
            'detail' => 'Your dashboard now reflects your allocation progress.'
        ];
    }
    $journeyNotificationCount = count($journeyNotifications);
    $journeyTimelineEmpty = !$journeyHasDraft && !$journeyFormPaymentUploaded && !$journeyPaymentVerified && !$journeyOfferApproved && !$journeyAllocationReady;
    $journeyNotificationLabel = $journeyNotificationCount === 1
        ? '1 new update'
        : ($journeyNotificationCount > 1 ? $journeyNotificationCount . ' new updates' : 'No new updates');
    $journeyInsightBadge = 'System Insight';
    $journeyInsights = [];
    if (!$journeyHasForm) {
        $journeyInsights = [
            ['tone' => 'info', 'icon' => 'fa-solid fa-circle-info', 'text' => $journeyFormInProgress ? 'Your onboarding draft is saved and ready to continue.' : 'Your onboarding is currently in progress.'],
            ['tone' => 'pending', 'icon' => 'fa-solid fa-list-check', 'text' => $journeyFormInProgress ? 'Return to the form and submit it to move to payment and offer preparation.' : 'Complete your form to move to payment and offer preparation.'],
            ['tone' => 'positive', 'icon' => 'fa-solid fa-shield-check', 'text' => 'No payment is required until onboarding is completed.'],
        ];
    } elseif (!$journeyFormPaymentUploaded && !$journeyPaymentVerified) {
        $journeyInsights = [
            ['tone' => 'positive', 'icon' => 'fa-solid fa-file-circle-check', 'text' => 'Your onboarding has been received.'],
            ['tone' => 'pending', 'icon' => 'fa-solid fa-wallet', 'text' => 'Upload your payment receipt to proceed.'],
            ['tone' => 'info', 'icon' => 'fa-solid fa-hourglass-half', 'text' => 'Our team will verify your payment once submitted.'],
        ];
    } elseif ($journeyFormPaymentUploaded && !$journeyPaymentVerified) {
        $journeyInsights = [
            ['tone' => 'pending', 'icon' => 'fa-solid fa-magnifying-glass-chart', 'text' => 'Your payment is under review.'],
            ['tone' => 'info', 'icon' => 'fa-solid fa-clock', 'text' => 'Verification usually takes a short time.'],
            ['tone' => 'positive', 'icon' => 'fa-solid fa-file-signature', 'text' => 'Your offer letter will be issued after confirmation.'],
        ];
    } elseif ($journeyCurrentStep === 'allocation' && !$journeyAllocationReady) {
        $journeyInsights = [
            ['tone' => 'pending', 'icon' => 'fa-solid fa-location-dot', 'text' => 'Your property allocation is in progress.'],
            ['tone' => 'info', 'icon' => 'fa-solid fa-user-shield', 'text' => 'Management approval is required before allocation.'],
            ['tone' => 'positive', 'icon' => 'fa-solid fa-bell', 'text' => 'You will be notified once completed.'],
        ];
    } elseif ($journeyOfferApproved && !$journeyAllocationReady) {
        $journeyInsights = [
            ['tone' => 'positive', 'icon' => 'fa-solid fa-file-circle-check', 'text' => 'Your offer letter is ready.'],
            ['tone' => 'info', 'icon' => 'fa-solid fa-building-columns', 'text' => 'You can proceed with property payment.'],
            ['tone' => 'pending', 'icon' => 'fa-solid fa-key', 'text' => 'Allocation will follow management approval.'],
        ];
    } else {
        $journeyInsights = [
            ['tone' => 'positive', 'icon' => 'fa-solid fa-chart-line', 'text' => 'Your dashboard reflects the latest progress in your property journey.'],
            ['tone' => 'info', 'icon' => 'fa-solid fa-sparkles', 'text' => 'Each completed step unlocks the next stage automatically in the interface.'],
            ['tone' => 'pending', 'icon' => 'fa-solid fa-bell', 'text' => 'Keep watching your notifications for the next important update.'],
        ];
    }
    ?>
    <div class="container-fluid px-4">
        <div class="d-flex justify-content-between align-items-center flex-wrap gap-3 mt-4 mb-4">
            <div>
                <h1 class="h3 mb-0 text-navy">Welcome, <?= htmlspecialchars($welcome_name) ?></h1>
                <p class="text-muted">Your onboarding and payment status</p>
            </div>
            <div class="d-flex align-items-center flex-wrap gap-2">
                <?php if (file_exists(__DIR__ . '/client-transfers.php')): ?>
                    <a href="client-transfers.php" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-right-left me-2"></i>Transfer History</a>
                <?php endif; ?>
                <div class="dropdown">
                    <button
                        id="journeyNotifyToggle"
                        class="btn journey-notify-btn dropdown-toggle"
                        type="button"
                        data-bs-toggle="dropdown"
                        data-bs-auto-close="outside"
                        aria-expanded="false"
                        aria-controls="journeyNotifyMenu"
                    >
                        <span class="journey-notify-icon">
                            <i class="fa-solid fa-bell"></i>
                            <?php if ($journeyNotificationCount > 0): ?>
                                <span class="journey-notify-badge"><?= (int)$journeyNotificationCount ?></span>
                            <?php endif; ?>
                        </span>
                        <span class="journey-notify-text"><?= htmlspecialchars($journeyNotificationLabel) ?></span>
                    </button>
                    <div class="dropdown-menu dropdown-menu-end journey-notify-menu" id="journeyNotifyMenu">
                        <div class="journey-notify-menu-header">
                            <strong>Notifications</strong>
                            <span><?= htmlspecialchars($journeyNotificationLabel) ?></span>
                        </div>
                        <?php if (empty($journeyNotifications)): ?>
                            <div class="journey-notify-empty">No new journey updates right now.</div>
                        <?php else: ?>
                            <?php foreach ($journeyNotifications as $journeyNotification): ?>
                                <div class="journey-notify-item">
                                    <div class="journey-notify-item-icon" aria-hidden="true">
                                        <i class="<?= htmlspecialchars($journeyNotification['icon'] ?? 'fa-solid fa-bell') ?>"></i>
                                    </div>
                                    <div class="journey-notify-item-body">
                                        <div class="journey-notify-item-title"><?= htmlspecialchars($journeyNotification['title']) ?></div>
                                        <div class="journey-notify-item-detail"><?= htmlspecialchars($journeyNotification['detail']) ?></div>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
        </div>
        <?php if (!empty($myCelebrationCards)): ?>
            <div class="row g-3 mb-4">
                <?php foreach ($myCelebrationCards as $card): ?>
                    <div class="col-12 col-md-6">
                        <div class="glass card shadow-sm h-100">
                            <div class="card-body d-flex gap-3 align-items-start">
                                <div class="rounded-circle d-flex align-items-center justify-content-center" style="width:44px;height:44px;background:rgba(13,110,253,0.10);color:#0d6efd;">
                                    <i class="<?= htmlspecialchars($card['icon']) ?>"></i>
                                </div>
                                <div class="flex-grow-1">
                                    <div class="d-flex justify-content-between align-items-center">
                                        <h6 class="mb-1 text-navy"><?= htmlspecialchars($card['title']) ?></h6>
                                        <span class="badge bg-success-subtle text-success"><?= htmlspecialchars($card['meta']) ?></span>
                                    </div>
                                    <div class="text-muted small">Occurs on <?= htmlspecialchars($card['date']) ?></div>
                                </div>
                            </div>
                        </div>
                    </div>
                <?php endforeach; ?>
            </div>
        <?php endif; ?>
        <?php if ($showChairmanMessage): ?>
        <style>
        .chairman-welcome-card{
            background: linear-gradient(135deg, #0b2545 0%, #133b5c 100%);
            color: #ffffff;
            border-radius: 14px;
            box-shadow: 0 18px 40px rgba(11, 37, 69, 0.22);
            padding: 24px;
            position: relative;
            overflow: hidden;
            opacity: 0;
            transform: translateY(-12px);
            transition: opacity .3s ease, transform .3s ease, box-shadow .2s ease;
        }
        .chairman-welcome-card.is-visible{
            opacity: 1;
            transform: translateY(0);
        }
        .chairman-welcome-card:hover{
            box-shadow: 0 22px 44px rgba(11, 37, 69, 0.28);
            transform: translateY(-2px);
        }
        .chairman-welcome-card::before{
            content: "";
            position: absolute;
            inset: 0;
            background: linear-gradient(120deg, rgba(255,255,255,0.08), rgba(255,255,255,0));
            pointer-events: none;
        }
        .chairman-welcome-card::after{
            content: "";
            position: absolute;
            inset: auto -70px -70px auto;
            width: 240px;
            height: 240px;
            background: radial-gradient(circle, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0) 72%);
            pointer-events: none;
        }
        .chairman-welcome-layout{
            position: relative;
            z-index: 1;
            display: grid;
            grid-template-columns: minmax(160px, 220px) minmax(0, 1fr);
            gap: 24px;
            align-items: start;
        }
        .chairman-welcome-profile{
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            gap: 12px;
        }
        .chairman-welcome-avatar{
            width: 84px;
            height: 84px;
            border-radius: 50%;
            object-fit: cover;
            border: 3px solid rgba(255,255,255,0.72);
            box-shadow: 0 10px 24px rgba(0,0,0,0.22);
            background: rgba(255,255,255,0.14);
        }
        .chairman-welcome-name{
            color: #ffffff;
            font-size: 1rem;
            font-weight: 700;
            margin-bottom: 2px;
        }
        .chairman-welcome-role{
            color: rgba(255,255,255,0.74);
            font-size: .92rem;
        }
        .chairman-welcome-eyebrow{
            color: rgba(255,255,255,0.7);
            text-transform: uppercase;
            letter-spacing: .14em;
            font-size: .74rem;
            font-weight: 700;
            margin-bottom: 10px;
        }
        .chairman-welcome-title{
            color: #ffffff !important;
            font-weight: 700;
            margin-bottom: 14px;
        }
        .chairman-welcome-body p{
            margin-bottom: 1rem;
            color: rgba(255,255,255,0.94);
            line-height: 1.6;
            font-size: 15px;
            max-width: 980px;
        }
        .chairman-welcome-signature{
            margin-top: 1.5rem;
            padding-top: .75rem;
        }
        .chairman-welcome-signature-greeting{
            font-style: italic;
            color: rgba(255,255,255,0.88);
            margin-bottom: .35rem;
        }
        .chairman-welcome-signature-name{
            color: #ffffff;
            font-weight: 700;
            margin-bottom: .1rem;
        }
        .chairman-welcome-signature-role{
            color: rgba(255,255,255,0.76);
            margin-bottom: 0;
        }
        .chairman-welcome-actions{
            display: flex;
            justify-content: flex-end;
            margin-top: 1.25rem;
        }
        .chairman-welcome-dismiss{
            border-radius: 999px;
            padding: .68rem 1.3rem;
            font-weight: 600;
            border: 1px solid rgba(255,255,255,0.28);
            background: rgba(255,255,255,0.16);
            color: #ffffff;
            backdrop-filter: blur(4px);
        }
        .chairman-welcome-dismiss:hover,
        .chairman-welcome-dismiss:focus{
            background: rgba(255,255,255,0.24);
            color: #ffffff;
            border-color: rgba(255,255,255,0.45);
        }
        @media (max-width: 767.98px){
            .chairman-welcome-card{
                padding: 20px;
            }
            .chairman-welcome-layout{
                grid-template-columns: 1fr;
                gap: 18px;
            }
            .chairman-welcome-profile{
                align-items: flex-start;
                text-align: left;
            }
            .chairman-welcome-body p{
                font-size: 14px;
            }
            .chairman-welcome-actions{
                justify-content: flex-start;
            }
        }
        </style>
        <div class="row g-3 mb-4" id="chairmanWelcomeSection">
            <div class="col-12">
                <div class="chairman-welcome-card" id="chairmanWelcomeCard">
                    <div class="chairman-welcome-layout">
                        <div class="chairman-welcome-profile">
                            <img
                                src="https://aibenproperties.com/wp-content/uploads/2025/08/IMG_2340-1229x1536.jpg"
                                alt="Chairman / CEO"
                                class="chairman-welcome-avatar"
                            >
                            <div>
                                <div class="chairman-welcome-name">Chairman / CEO</div>
                                <div class="chairman-welcome-role">Aiben Properties Ltd</div>
                            </div>
                        </div>
                        <div class="chairman-welcome-body">
                            <div class="chairman-welcome-eyebrow">Executive Welcome</div>
                            <h2 class="h4 chairman-welcome-title">Message from the Chairman</h2>
                            <p>Welcome to Aiben Properties,</p>
                            <p>I am personally delighted to have you join our growing community of valued clients.</p>
                            <p>At Aiben, we are committed to delivering transparency, security, and excellence in every aspect of your real estate journey. Whether you are acquiring your first property or expanding your portfolio, our team is here to ensure that your experience is seamless, reliable, and rewarding.</p>
                            <p>This platform has been designed to give you full visibility and control — from tracking your payments to managing your property allocations — all in one place.</p>
                            <p>We do not just sell properties; we build trust, long-term relationships, and lasting value.</p>
                            <p>Thank you for choosing Aiben Properties. We look forward to serving you.</p>
                            <div class="chairman-welcome-signature">
                                <div class="chairman-welcome-signature-greeting">Warm regards,</div>
                                <div class="chairman-welcome-signature-name">Chairman / CEO</div>
                                <p class="chairman-welcome-signature-role">Aiben Properties Ltd</p>
                            </div>
                            <div class="chairman-welcome-actions">
                                <button type="button" class="btn chairman-welcome-dismiss" id="chairmanWelcomeDismiss">Got it</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <script>
        (function () {
            const storageKey = 'chairmanMessageSeen_v2_<?= (int)$user_id ?>';
            const section = document.getElementById('chairmanWelcomeSection');
            const card = document.getElementById('chairmanWelcomeCard');
            const dismissButton = document.getElementById('chairmanWelcomeDismiss');
            if (!section || !card || !dismissButton) {
                return;
            }
            if (window.localStorage.getItem(storageKey) === 'true') {
                section.style.display = 'none';
                return;
            }
            window.requestAnimationFrame(function () {
                card.classList.add('is-visible');
            });
            dismissButton.addEventListener('click', function () {
                window.localStorage.setItem(storageKey, 'true');
                section.style.display = 'none';
            });
        }());
        </script>
        <?php endif; ?>
        <style>
        .journey-dashboard-shell{
            opacity: 0;
            animation: journeyDashboardFade .65s cubic-bezier(.22, 1, .36, 1) forwards;
        }
        @keyframes journeyDashboardFade{
            from{
                opacity: 0;
                transform: translateY(12px);
            }
            to{
                opacity: 1;
                transform: translateY(0);
            }
        }
        html{
            scroll-behavior: smooth;
        }
        .container-fluid > .row{
            opacity: 0;
            animation: journeySectionFade .45s ease forwards;
        }
        .container-fluid > .row:nth-of-type(1){ animation-delay: .04s; }
        .container-fluid > .row:nth-of-type(2){ animation-delay: .09s; }
        .container-fluid > .row:nth-of-type(3){ animation-delay: .14s; }
        .container-fluid > .row:nth-of-type(4){ animation-delay: .19s; }
        .container-fluid > .row:nth-of-type(5){ animation-delay: .24s; }
        .container-fluid > .row:nth-of-type(6){ animation-delay: .29s; }
        .container-fluid > .row:nth-of-type(7){ animation-delay: .34s; }
        .container-fluid > .row:nth-of-type(8){ animation-delay: .39s; }
        @keyframes journeySectionFade{
            from{
                opacity: 0;
                transform: translateY(14px);
            }
            to{
                opacity: 1;
                transform: translateY(0);
            }
        }
        .journey-card{
            background: #ffffff;
            border: 1px solid #e7edf5;
            border-radius: 18px;
            box-shadow: 0 12px 28px rgba(15, 23, 42, 0.06);
            padding: 24px;
        }
        .journey-card,
        .glass.card.shadow-sm,
        .glass.card.shadow,
        .glass.p-3.shadow-sm{
            animation: journeyFadeInUp .3s ease both;
            transition: transform .32s cubic-bezier(.22, 1, .36, 1), box-shadow .32s cubic-bezier(.22, 1, .36, 1), border-color .32s ease, background-color .32s ease;
            will-change: transform, box-shadow;
        }
        .journey-card:hover,
        .glass.card.shadow-sm:hover,
        .glass.card.shadow:hover,
        .glass.p-3.shadow-sm:hover{
            transform: translateY(-6px);
            box-shadow: 0 22px 40px rgba(15, 23, 42, 0.13);
        }
        @keyframes journeyFadeInUp{
            from{
                opacity: 0;
                transform: translateY(10px);
            }
            to{
                opacity: 1;
                transform: translateY(0);
            }
        }
        .journey-title{
            color: #0f172a;
            font-weight: 700;
            margin-bottom: 6px;
        }
        .journey-subtitle{
            color: #64748b;
            margin-bottom: 18px;
        }
        .journey-progress-label{
            color: #334155;
            font-weight: 600;
            margin-bottom: 10px;
        }
        .journey-progress-track{
            width: 100%;
            height: 10px;
            border-radius: 999px;
            overflow: hidden;
            position: relative;
            background: linear-gradient(90deg, rgba(219, 234, 254, 0.72) 0%, rgba(226, 232, 240, 0.95) 100%);
            box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.08);
        }
        .journey-progress-track::after{
            content: "";
            position: absolute;
            inset: 0;
            background: linear-gradient(90deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.14) 100%);
            pointer-events: none;
        }
        .journey-progress-bar{
            height: 100%;
            border-radius: inherit;
            position: relative;
            background: linear-gradient(90deg, #1d4ed8 0%, #3b82f6 45%, #60a5fa 70%, #facc15 100%);
            transition: width 1.1s cubic-bezier(.22, 1, .36, 1);
            transform-origin: left center;
            box-shadow: 0 0 16px rgba(37, 99, 235, 0.24);
        }
        .journey-progress-bar::after{
            content: "";
            position: absolute;
            inset: 0;
            background: linear-gradient(110deg, rgba(255,255,255,0) 18%, rgba(255,255,255,0.45) 50%, rgba(255,255,255,0) 82%);
            transform: translateX(-120%);
            animation: journeyProgressSheen 2.8s ease-in-out infinite;
        }
        @keyframes journeyProgressSheen{
            from{
                transform: translateX(-120%);
            }
            to{
                transform: translateX(120%);
            }
        }
        .journey-steps{
            display: grid;
            grid-template-columns: repeat(6, minmax(0, 1fr));
            gap: 14px;
            margin-top: 22px;
        }
        .journey-step{
            position: relative;
            padding: 16px 14px;
            border-radius: 16px;
            background: #f8fafc;
            border: 1px solid #e2e8f0;
            min-height: 144px;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            overflow: hidden;
            transition: transform .3s cubic-bezier(.22, 1, .36, 1), box-shadow .3s cubic-bezier(.22, 1, .36, 1), border-color .3s ease, background .3s ease;
        }
        .journey-step::before{
            content: "";
            position: absolute;
            inset: 0;
            background: radial-gradient(circle at top right, rgba(255,255,255,0.65) 0%, rgba(255,255,255,0) 56%);
            opacity: .85;
            pointer-events: none;
        }
        .journey-step:hover{
            transform: translateY(-4px) scale(1.01);
            box-shadow: 0 18px 30px rgba(15, 23, 42, 0.12);
        }
        .journey-step.is-completed{
            background: linear-gradient(180deg, #effaf3 0%, #f8fffb 100%);
            border-color: #9ed8b4;
        }
        .journey-step.is-current{
            background: linear-gradient(135deg, rgba(37, 99, 235, 0.1) 0%, rgba(250, 204, 21, 0.18) 100%);
            border-color: #2563eb;
            box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.16), 0 0 0 7px rgba(37, 99, 235, 0.08), 0 16px 30px rgba(37, 99, 235, 0.18);
            transform: scale(1.025);
            animation: journeyCurrentGlow 3.4s ease-in-out infinite, journeyCurrentFloat 4.8s ease-in-out infinite;
        }
        .journey-step.is-current:hover{
            transform: scale(1.04) translateY(-3px);
            box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.2), 0 0 0 9px rgba(59, 130, 246, 0.1), 0 22px 38px rgba(37, 99, 235, 0.2);
        }
        .journey-step.is-current::after{
            content: "";
            position: absolute;
            inset: -2px;
            border-radius: inherit;
            border: 1px solid rgba(255,255,255,0.45);
            opacity: .8;
            pointer-events: none;
        }
        @keyframes journeyCurrentGlow{
            0%, 100%{
                box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.16), 0 0 0 7px rgba(37, 99, 235, 0.08), 0 16px 30px rgba(37, 99, 235, 0.18);
            }
            50%{
                box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.22), 0 0 0 10px rgba(59, 130, 246, 0.12), 0 18px 34px rgba(37, 99, 235, 0.2);
            }
        }
        @keyframes journeyCurrentFloat{
            0%, 100%{
                transform: translateY(0) scale(1.025);
            }
            50%{
                transform: translateY(-3px) scale(1.035);
            }
        }
        .journey-step.is-pending{
            background: #f8fafc;
            border-color: #e2e8f0;
        }
        .journey-step-top{
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            margin-bottom: 12px;
        }
        .journey-icon{
            width: 40px;
            height: 40px;
            border-radius: 12px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            background: #e2e8f0;
            color: #475569;
        }
        .journey-step.is-completed .journey-icon{
            background: #16a34a;
            color: #ffffff;
        }
        .journey-step.is-current .journey-icon{
            background: #2563eb;
            color: #ffffff;
        }
        .journey-status{
            font-size: 12px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: .06em;
        }
        .journey-step.is-completed .journey-status{
            color: #15803d;
        }
        .journey-step.is-current .journey-status{
            color: #1d4ed8;
        }
        .journey-step.is-pending .journey-status{
            color: #94a3b8;
        }
        .journey-label{
            color: #0f172a;
            font-weight: 600;
            line-height: 1.4;
        }
        .journey-helper{
            color: #64748b;
            font-size: .88rem;
            line-height: 1.45;
            margin-top: 8px;
        }
        .journey-step.is-current .journey-helper{
            color: #1e3a8a;
        }
        .journey-current-note{
            margin-top: 10px;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            color: #1d4ed8;
            font-size: .8rem;
            font-weight: 700;
        }
        .journey-current-link{
            color: inherit;
            text-decoration: underline;
            text-decoration-color: rgba(29, 78, 216, 0.35);
            text-underline-offset: 3px;
            transition: color .2s ease, text-decoration-color .2s ease, opacity .2s ease;
        }
        .journey-current-link:hover,
        .journey-current-link:focus{
            color: #1e40af;
            text-decoration-color: rgba(30, 64, 175, 0.65);
            opacity: 1;
        }
        .journey-message{
            margin-top: 22px;
            padding: 16px 18px;
            border-radius: 14px;
            background: linear-gradient(135deg, rgba(15, 23, 42, 0.04) 0%, rgba(37, 99, 235, 0.06) 100%);
            border: 1px solid #dbe6f3;
            color: #334155;
            display: flex;
            align-items: flex-start;
            gap: 10px;
        }
        .journey-message i{
            color: #2563eb;
            margin-top: 2px;
        }
        .journey-message-title{
            color: #0f172a;
            font-weight: 600;
            margin-bottom: 4px;
        }
        .journey-message-detail{
            color: #64748b;
            font-size: .92rem;
            line-height: 1.5;
        }
        .journey-zero-note{
            color: #94a3b8;
            font-size: .85rem;
            margin-top: 4px;
            line-height: 1.5;
        }
        .journey-notify-btn{
            display: inline-flex;
            align-items: center;
            gap: 12px;
            border-radius: 999px;
            border: 1px solid #dbe6f3;
            background: #ffffff;
            color: #0f172a;
            font-weight: 600;
            padding: 10px 14px;
            box-shadow: 0 8px 22px rgba(15, 23, 42, 0.08);
            transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease, background-color .2s ease, color .2s ease;
        }
        .journey-notify-btn.is-active{
            border-color: #93c5fd;
            background: linear-gradient(135deg, #eff6ff 0%, #ffffff 100%);
            box-shadow: 0 18px 32px rgba(37, 99, 235, 0.16);
        }
        .journey-notify-btn:hover,
        .journey-notify-btn:focus{
            color: #0f172a;
            border-color: #bfdbfe;
            background: #f8fbff;
            transform: translateY(-1px);
            box-shadow: 0 14px 28px rgba(37, 99, 235, 0.12);
        }
        .journey-notify-icon{
            position: relative;
            width: 42px;
            height: 42px;
            border-radius: 50%;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
            color: #2563eb;
            font-size: 1rem;
        }
        .journey-notify-icon::after{
            content: "";
            position: absolute;
            inset: -4px;
            border-radius: 50%;
            border: 1px solid rgba(59, 130, 246, 0.25);
            opacity: 0;
            transform: scale(.9);
            animation: journeyBellPulse 3.2s ease-in-out infinite;
        }
        .journey-notify-badge{
            position: absolute;
            top: -2px;
            right: -2px;
            min-width: 20px;
            height: 20px;
            padding: 0 6px;
            border-radius: 999px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: #ef4444;
            color: #ffffff;
            font-size: .72rem;
            font-weight: 700;
            border: 2px solid #ffffff;
            box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.36);
            animation: journeyBadgePulse 2.4s ease-in-out infinite;
        }
        .journey-notify-text{
            color: #334155;
            font-size: .92rem;
        }
        .journey-notify-menu{
            width: min(360px, calc(100vw - 24px));
            padding: 0;
            border: 1px solid #dbe6f3;
            border-radius: 18px;
            overflow: hidden;
            box-shadow: 0 22px 46px rgba(15, 23, 42, 0.14);
            transform-origin: top right;
            background: rgba(255,255,255,0.98);
            backdrop-filter: blur(12px);
        }
        .journey-notify-menu.show{
            animation: journeyDropdownIn .28s cubic-bezier(.22, 1, .36, 1);
        }
        @keyframes journeyDropdownIn{
            from{
                opacity: 0;
                transform: translateY(-14px) scale(.98);
            }
            to{
                opacity: 1;
                transform: translateY(0) scale(1);
            }
        }
        @keyframes journeyNotifyItemIn{
            from{
                opacity: 0;
                transform: translateY(-10px);
            }
            to{
                opacity: 1;
                transform: translateY(0);
            }
        }
        @keyframes journeyBellPulse{
            0%, 100%{
                opacity: 0;
                transform: scale(.92);
            }
            35%{
                opacity: .65;
                transform: scale(1.12);
            }
            60%{
                opacity: 0;
                transform: scale(1.22);
            }
        }
        @keyframes journeyBadgePulse{
            0%, 100%{
                transform: scale(1);
                box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.36);
            }
            50%{
                transform: scale(1.08);
                box-shadow: 0 0 0 8px rgba(239, 68, 68, 0);
            }
        }
        .journey-notify-menu-header{
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding: 14px 16px;
            background: #f8fafc;
            border-bottom: 1px solid #e2e8f0;
            color: #475569;
            font-size: .85rem;
        }
        .journey-notify-item{
            display: flex;
            align-items: flex-start;
            gap: 12px;
            padding: 14px 16px;
            border-bottom: 1px solid #eef2f7;
            transition: background-color .25s ease, transform .25s ease;
        }
        .journey-notify-item:last-child{
            border-bottom: 0;
        }
        .journey-notify-item:hover{
            background: linear-gradient(135deg, rgba(239, 246, 255, 0.9) 0%, rgba(255, 255, 255, 1) 100%);
            transform: translateY(-1px);
        }
        .journey-notify-item-icon{
            width: 36px;
            height: 36px;
            border-radius: 12px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, #dbeafe 0%, #eff6ff 100%);
            color: #2563eb;
            flex: 0 0 auto;
        }
        .journey-notify-item-body{
            min-width: 0;
        }
        .journey-notify-item-title{
            color: #0f172a;
            font-weight: 700;
            margin-bottom: 4px;
        }
        .journey-notify-item-detail,
        .journey-notify-empty{
            color: #64748b;
            font-size: .88rem;
            line-height: 1.5;
        }
        .journey-notify-empty{
            padding: 16px;
        }
        .journey-timeline-card,
        .journey-insights-card,
        .journey-what-next-card{
            height: 100%;
        }
        .journey-insights-card{
            position: relative;
            overflow: hidden;
            background: linear-gradient(135deg, #f8fbff 0%, #ffffff 58%, #fefce8 100%);
            border-color: #dbe6f3;
        }
        .journey-insights-card::before{
            content: "";
            position: absolute;
            inset: auto -60px -70px auto;
            width: 220px;
            height: 220px;
            background: radial-gradient(circle, rgba(37, 99, 235, 0.12) 0%, rgba(37, 99, 235, 0) 72%);
            pointer-events: none;
        }
        .journey-insights-head{
            position: relative;
            z-index: 1;
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 16px;
            margin-bottom: 20px;
        }
        .journey-insights-badge{
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 8px 12px;
            border-radius: 999px;
            background: rgba(37, 99, 235, 0.1);
            color: #1d4ed8;
            font-size: .78rem;
            font-weight: 700;
            letter-spacing: .04em;
            text-transform: uppercase;
            white-space: nowrap;
        }
        .journey-insights-grid{
            position: relative;
            z-index: 1;
            display: grid;
            grid-template-columns: repeat(3, minmax(0, 1fr));
            gap: 14px;
        }
        .journey-insight{
            display: flex;
            align-items: flex-start;
            gap: 12px;
            padding: 16px;
            border-radius: 16px;
            background: rgba(255,255,255,0.88);
            border: 1px solid #e2e8f0;
            box-shadow: 0 12px 24px rgba(15, 23, 42, 0.05);
            transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
        }
        .journey-insight:hover{
            transform: translateY(-4px);
            border-color: #bfdbfe;
            box-shadow: 0 18px 30px rgba(37, 99, 235, 0.12);
        }
        .journey-insight-icon{
            width: 40px;
            height: 40px;
            border-radius: 12px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-size: .95rem;
            flex: 0 0 auto;
        }
        .journey-insight.is-info .journey-insight-icon{
            background: #dbeafe;
            color: #2563eb;
        }
        .journey-insight.is-positive .journey-insight-icon{
            background: #dcfce7;
            color: #16a34a;
        }
        .journey-insight.is-pending .journey-insight-icon{
            background: #ffedd5;
            color: #ea580c;
        }
        .journey-insight-text{
            color: #334155;
            line-height: 1.55;
            margin: 0;
        }
        .journey-section-title{
            color: #0f172a;
            font-weight: 700;
            margin-bottom: 4px;
        }
        .journey-section-subtitle{
            color: #64748b;
            margin-bottom: 0;
        }
        .journey-empty-state{
            display: flex;
            align-items: flex-start;
            gap: 12px;
            margin-top: 18px;
            padding: 16px 18px;
            border-radius: 16px;
            background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(248, 250, 252, 0.95) 100%);
            border: 1px solid #dbeafe;
            color: #334155;
        }
        .journey-empty-state i{
            color: #2563eb;
            margin-top: 2px;
        }
        .journey-timeline{
            position: relative;
            margin-top: 22px;
            padding-left: 18px;
        }
        .journey-timeline::before{
            content: "";
            position: absolute;
            left: 22px;
            top: 10px;
            bottom: 10px;
            width: 2px;
            background: linear-gradient(180deg, #cbd5e1 0%, #e2e8f0 100%);
        }
        .journey-timeline-item{
            position: relative;
            display: grid;
            grid-template-columns: 56px minmax(0, 1fr);
            gap: 14px;
            padding-bottom: 18px;
            opacity: 0;
            transform: translateY(10px);
            animation: journeyFadeInUp .35s ease forwards;
            animation-delay: calc(var(--timeline-index, 0) * .08s);
        }
        .journey-timeline-item:last-child{
            padding-bottom: 0;
        }
        .journey-timeline-node{
            position: relative;
            z-index: 1;
            width: 48px;
            height: 48px;
            border-radius: 50%;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            border: 3px solid #e2e8f0;
            background: #ffffff;
            color: #94a3b8;
            box-shadow: 0 8px 18px rgba(15, 23, 42, 0.05);
        }
        .journey-timeline-item.is-completed .journey-timeline-node{
            background: #16a34a;
            border-color: #bbf7d0;
            color: #ffffff;
        }
        .journey-timeline-item.is-current .journey-timeline-node{
            background: #2563eb;
            border-color: #bfdbfe;
            color: #ffffff;
            animation: journeyTimelinePulse 2.6s ease-in-out infinite;
        }
        .journey-timeline-item.is-pending .journey-timeline-node{
            background: #f8fafc;
            border-color: #e2e8f0;
            color: #94a3b8;
        }
        .journey-timeline-item.is-completed .journey-timeline-node i{
            animation: journeyCheckPop .45s ease both;
            animation-delay: calc(var(--timeline-index, 0) * .08s + .12s);
        }
        @keyframes journeyTimelinePulse{
            0%, 100%{
                box-shadow: 0 8px 18px rgba(15, 23, 42, 0.05), 0 0 0 0 rgba(37, 99, 235, 0.18);
            }
            50%{
                box-shadow: 0 10px 20px rgba(15, 23, 42, 0.06), 0 0 0 8px rgba(37, 99, 235, 0.08);
            }
        }
        @keyframes journeyCheckPop{
            0%{
                transform: scale(.4);
                opacity: 0;
            }
            70%{
                transform: scale(1.15);
                opacity: 1;
            }
            100%{
                transform: scale(1);
                opacity: 1;
            }
        }
        .journey-timeline-content{
            padding: 4px 0 0;
            border-radius: 16px;
            transition: transform .2s ease, background-color .2s ease, box-shadow .2s ease;
        }
        .journey-timeline-item:hover .journey-timeline-content{
            transform: translateX(4px);
            background: linear-gradient(135deg, rgba(248, 250, 252, 0.95) 0%, rgba(239, 246, 255, 0.95) 100%);
            box-shadow: 0 10px 22px rgba(15, 23, 42, 0.06);
        }
        .journey-timeline-item:hover .journey-timeline-node{
            transform: translateY(-2px) scale(1.04);
            box-shadow: 0 14px 26px rgba(37, 99, 235, 0.12);
        }
        .journey-timeline-meta{
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 6px;
        }
        .journey-timeline-title{
            color: #0f172a;
            font-weight: 600;
            margin: 0;
        }
        .journey-timeline-item.is-recent .journey-timeline-title{
            font-weight: 800;
        }
        .journey-timeline-date{
            color: #64748b;
            font-size: .83rem;
            white-space: nowrap;
        }
        .journey-timeline-description{
            color: #64748b;
            font-size: .92rem;
            line-height: 1.55;
            margin: 0;
        }
        .journey-timeline-state{
            display: inline-flex;
            align-items: center;
            gap: 6px;
            margin-top: 8px;
            color: #64748b;
            font-size: .8rem;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: .05em;
        }
        .journey-timeline-item.is-completed .journey-timeline-state{
            color: #15803d;
        }
        .journey-timeline-item.is-current .journey-timeline-state{
            color: #1d4ed8;
        }
        .journey-timeline-item.is-recent .journey-timeline-content{
            padding: 14px 16px;
            margin-left: -16px;
            border-radius: 16px;
            background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(255, 255, 255, 0.96) 100%);
            box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.08), 0 14px 30px rgba(37, 99, 235, 0.12);
        }
        .journey-what-next-card{
            background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
        }
        .journey-what-next-icon{
            width: 54px;
            height: 54px;
            border-radius: 16px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, #dbeafe 0%, #eff6ff 100%);
            color: #2563eb;
            font-size: 1.15rem;
            margin-bottom: 16px;
        }
        .journey-what-next-text{
            color: #334155;
            line-height: 1.7;
            margin-bottom: 0;
        }
        .journey-what-next-hint{
            margin-top: 16px;
            padding-top: 16px;
            border-top: 1px solid #e2e8f0;
            color: #64748b;
            font-size: .88rem;
        }
        .journey-trust-note,
        .journey-status-note{
            margin-top: 16px;
            display: flex;
            align-items: flex-start;
            gap: 10px;
            padding: 14px 16px;
            border-radius: 14px;
            font-size: .9rem;
            line-height: 1.55;
        }
        .journey-trust-note{
            background: linear-gradient(135deg, rgba(240, 253, 244, 0.96) 0%, rgba(255, 255, 255, 1) 100%);
            border: 1px solid #bbf7d0;
            color: #166534;
        }
        .journey-status-note{
            background: linear-gradient(135deg, rgba(239, 246, 255, 0.92) 0%, rgba(255, 255, 255, 1) 100%);
            border: 1px solid #bfdbfe;
            color: #1e40af;
        }
        .journey-trust-note i,
        .journey-status-note i{
            margin-top: 2px;
        }
        .journey-card .btn,
        .glass .btn{
            transition: transform .2s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease, color .2s ease;
        }
        .journey-card .btn:hover,
        .journey-card .btn:focus,
        .glass .btn:hover,
        .glass .btn:focus{
            transform: translateY(-1px);
            box-shadow: 0 12px 24px rgba(15, 23, 42, 0.12);
        }
        .journey-card .btn-primary:hover,
        .journey-card .btn-primary:focus,
        .glass .btn-primary:hover,
        .glass .btn-primary:focus{
            background-color: #1d4ed8;
            border-color: #1d4ed8;
        }
        .journey-card .btn-success:hover,
        .journey-card .btn-success:focus,
        .glass .btn-success:hover,
        .glass .btn-success:focus{
            background-color: #15803d;
            border-color: #15803d;
        }
        .journey-card .btn-outline-primary:hover,
        .journey-card .btn-outline-primary:focus,
        .glass .btn-outline-primary:hover,
        .glass .btn-outline-primary:focus{
            background-color: #2563eb;
            border-color: #2563eb;
            color: #ffffff;
        }
        .journey-card .btn-outline-secondary:hover,
        .journey-card .btn-outline-secondary:focus,
        .glass .btn-outline-secondary:hover,
        .glass .btn-outline-secondary:focus{
            background-color: #334155;
            border-color: #334155;
            color: #ffffff;
        }
        @media (max-width: 1199.98px){
            .journey-insights-grid{
                grid-template-columns: 1fr;
            }
            .journey-steps{
                grid-template-columns: repeat(3, minmax(0, 1fr));
            }
        }
        @media (max-width: 767.98px){
            .journey-notify-btn{
                padding: 10px 12px;
            }
            .journey-notify-text{
                display: none;
            }
            .journey-card{
                padding: 18px;
            }
            .journey-status-note,
            .journey-trust-note,
            .journey-empty-state{
                padding: 14px;
            }
            .journey-insights-head{
                flex-direction: column;
                align-items: flex-start;
            }
            .journey-steps{
                grid-template-columns: 1fr;
            }
            .journey-step{
                min-height: auto;
                transform: none;
            }
            .journey-step.is-current{
                transform: none;
            }
            .journey-step.is-current:hover{
                transform: translateY(-2px);
            }
            .journey-timeline{
                padding-left: 8px;
            }
            .journey-timeline::before{
                left: 16px;
            }
            .journey-timeline-item{
                grid-template-columns: 40px minmax(0, 1fr);
                gap: 12px;
            }
            .journey-timeline-node{
                width: 34px;
                height: 34px;
                font-size: .85rem;
                border-width: 2px;
            }
            .journey-timeline-meta{
                flex-direction: column;
                align-items: flex-start;
            }
            .journey-timeline-date{
                white-space: normal;
            }
        }
        @media (prefers-reduced-motion: reduce){
            html{
                scroll-behavior: auto;
            }
            .journey-dashboard-shell,
            .container-fluid > .row,
            .journey-card,
            .glass.card.shadow-sm,
            .glass.card.shadow,
            .glass.p-3.shadow-sm,
            .journey-progress-bar,
            .journey-progress-bar::after,
            .journey-step.is-current,
            .journey-timeline-item,
            .journey-timeline-item.is-current .journey-timeline-node,
            .journey-timeline-item.is-completed .journey-timeline-node i,
            .journey-notify-icon::after,
            .journey-notify-badge,
            .journey-notify-menu.show{
                animation: none !important;
            }
            .journey-step,
            .journey-insight,
            .journey-notify-btn,
            .journey-notify-item,
            .container-fluid > .row,
            .journey-progress-bar,
            .journey-card .btn,
            .glass .btn,
            .journey-timeline-content{
                transition: none !important;
            }
        }
        </style>
        <script>
        (function () {
            function onReady(fn){
                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', fn, { once: true });
                    return;
                }
                fn();
            }
            onReady(function () {
                var reduceMotion = false;
                try { reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; } catch(e) {}

                var progressBar = document.getElementById('journeyProgressBar');
                if (progressBar) {
                    var target = Math.max(0, Math.min(100, parseInt(progressBar.getAttribute('data-progress') || '0', 10)));
                    if (reduceMotion) {
                        progressBar.style.width = target + '%';
                    } else {
                        progressBar.style.width = '0%';
                        window.requestAnimationFrame(function () {
                            window.requestAnimationFrame(function () {
                                progressBar.style.width = target + '%';
                            });
                        });
                    }
                }

                var notifyToggle = document.getElementById('journeyNotifyToggle');
                var notifyMenu = document.getElementById('journeyNotifyMenu');
                if (notifyToggle && notifyMenu) {
                    var animateItems = function () {
                        if (reduceMotion) { return; }
                        var items = notifyMenu.querySelectorAll('.journey-notify-item');
                        items.forEach(function (item, index) {
                            item.style.opacity = '0';
                            item.style.transform = 'translateY(-10px)';
                            item.style.animation = 'none';
                            window.requestAnimationFrame(function () {
                                item.style.animation = 'journeyNotifyItemIn .32s cubic-bezier(.22, 1, .36, 1) both';
                                item.style.animationDelay = (index * 0.06) + 's';
                            });
                        });
                    };

                    notifyToggle.addEventListener('show.bs.dropdown', function () {
                        notifyToggle.classList.add('is-active');
                        animateItems();
                    });
                    notifyToggle.addEventListener('hide.bs.dropdown', function () {
                        notifyToggle.classList.remove('is-active');
                    });
                }
            });
        }());
        </script>
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="journey-card">
                    <h2 class="h4 journey-title">Your Property Journey</h2>
                    <p class="journey-subtitle mb-0">Track your current position in the process and see what comes next.</p>
                    <div class="journey-progress-label mt-3">Progress: <?= (int)$journeyProgressPercent ?>% Complete</div>
                    <div class="journey-progress-track" aria-hidden="true">
                        <div class="journey-progress-bar" id="journeyProgressBar" data-progress="<?= (int)$journeyProgressPercent ?>" style="width: <?= (int)$journeyProgressPercent ?>%;"></div>
                    </div>
                    <div class="journey-steps">
                        <?php foreach ($journeySteps as $step): ?>
                            <?php $state = $journeyStateMap[$step['key']] ?? 'pending'; ?>
                            <div class="journey-step is-<?= htmlspecialchars($state) ?>">
                                <div class="journey-step-top">
                                    <span class="journey-icon">
                                        <?php if ($state === 'completed'): ?>
                                            <i class="fa-solid fa-check"></i>
                                        <?php else: ?>
                                            <i class="<?= htmlspecialchars($step['icon']) ?>"></i>
                                        <?php endif; ?>
                                    </span>
                                    <span class="journey-status"><?= htmlspecialchars($state) ?></span>
                                </div>
                                <div>
                                    <div class="journey-label"><?= htmlspecialchars($step['label']) ?></div>
                                    <div class="journey-helper"><?= htmlspecialchars($step['helper']) ?></div>
                                    <?php if ($state === 'current'): ?>
                                        <div class="journey-current-note">
                                            <i class="fa-solid fa-sparkles"></i>
                                            <?php if (!empty($journeyCurrentLinks[$step['key']] ?? '')): ?>
                                                <a href="<?= htmlspecialchars($journeyCurrentLinks[$step['key']]) ?>" class="journey-current-link">
                                                    <?= htmlspecialchars($journeyCurrentDescriptions[$step['key']] ?? '') ?>
                                                </a>
                                            <?php else: ?>
                                                <span><?= htmlspecialchars($journeyCurrentDescriptions[$step['key']] ?? '') ?></span>
                                            <?php endif; ?>
                                        </div>
                                    <?php endif; ?>
                                </div>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <div class="journey-message">
                        <i class="fa-solid fa-circle-info"></i>
                        <div>
                            <div class="journey-message-title"><?= htmlspecialchars($journeyMessage) ?></div>
                            <div class="journey-message-detail"><?= htmlspecialchars($journeyMessageDetail) ?></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="journey-card journey-insights-card">
                    <div class="journey-insights-head">
                        <div>
                            <h2 class="h4 journey-section-title">Smart Insights</h2>
                            <p class="journey-section-subtitle">A guided summary based on your current dashboard status.</p>
                        </div>
                        <span class="journey-insights-badge">
                            <i class="fa-solid fa-sparkles"></i>
                            <?= htmlspecialchars($journeyInsightBadge) ?>
                        </span>
                    </div>
                    <div class="journey-insights-grid">
                        <?php foreach ($journeyInsights as $journeyInsight): ?>
                            <div class="journey-insight is-<?= htmlspecialchars($journeyInsight['tone']) ?>">
                                <div class="journey-insight-icon" aria-hidden="true">
                                    <i class="<?= htmlspecialchars($journeyInsight['icon']) ?>"></i>
                                </div>
                                <p class="journey-insight-text"><?= htmlspecialchars($journeyInsight['text']) ?></p>
                            </div>
                        <?php endforeach; ?>
                    </div>
                </div>
            </div>
        </div>
        <div class="row g-3 mb-4">
            <div class="col-xl-8">
                <div class="journey-card journey-timeline-card">
                    <h2 class="h4 journey-section-title">Activity Timeline</h2>
                    <p class="journey-section-subtitle">See the milestones already completed and the step currently in progress.</p>
                    <?php if ($journeyTimelineEmpty): ?>
                        <div class="journey-empty-state">
                            <i class="fa-solid fa-seedling"></i>
                            <div>Your journey has just started. Complete your onboarding to proceed.</div>
                        </div>
                    <?php endif; ?>
                    <div class="journey-timeline">
                        <?php foreach ($journeyTimelineItems as $timelineIndex => $journeyTimelineItem): ?>
                            <?php
                                $timelineState = $journeyTimelineItem['state'] ?? 'pending';
                                $timelineDate = !empty($journeyTimelineItem['date']) ? date('M d, Y', strtotime((string)$journeyTimelineItem['date'])) : 'Date pending';
                                $timelineStateLabel = $timelineState === 'current'
                                    ? 'Current step'
                                    : ($timelineState === 'completed' ? 'Completed' : 'Pending');
                            ?>
                            <div class="journey-timeline-item is-<?= htmlspecialchars($timelineState) ?><?= !empty($journeyTimelineItem['is_recent']) ? ' is-recent' : '' ?>" style="--timeline-index: <?= (int)$timelineIndex ?>;">
                                <div class="journey-timeline-node" aria-hidden="true">
                                    <?php if ($timelineState === 'completed'): ?>
                                        <i class="fa-solid fa-check"></i>
                                    <?php elseif ($timelineState === 'current'): ?>
                                        <i class="fa-solid fa-circle"></i>
                                    <?php else: ?>
                                        <i class="<?= htmlspecialchars($journeyTimelineItem['icon']) ?>"></i>
                                    <?php endif; ?>
                                </div>
                                <div class="journey-timeline-content">
                                    <div class="journey-timeline-meta">
                                        <h3 class="h6 journey-timeline-title"><?= htmlspecialchars($journeyTimelineItem['title']) ?></h3>
                                        <span class="journey-timeline-date"><?= htmlspecialchars($timelineDate) ?></span>
                                    </div>
                                    <p class="journey-timeline-description"><?= htmlspecialchars($journeyTimelineItem['description']) ?></p>
                                    <div class="journey-timeline-state">
                                        <i class="fa-solid fa-wave-square"></i>
                                        <span><?= htmlspecialchars($timelineStateLabel) ?></span>
                                    </div>
                                </div>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <div class="journey-status-note">
                        <i class="fa-solid fa-rotate"></i>
                        <span>Your dashboard updates automatically as each step is completed.</span>
                    </div>
                </div>
            </div>
            <div class="col-xl-4">
                <div class="journey-card journey-what-next-card">
                    <div class="journey-what-next-icon">
                        <i class="fa-solid fa-sparkles"></i>
                    </div>
                    <h2 class="h4 journey-section-title">What Happens Next</h2>
                    <p class="journey-section-subtitle">A quick guide based on your current dashboard status.</p>
                    <p class="journey-what-next-text mt-3"><?= htmlspecialchars($journeyWhatNext) ?></p>
                    <div class="journey-what-next-hint">
                        Your dashboard updates automatically as each stage is completed by you or our team.
                    </div>
                    <div class="journey-trust-note">
                        <i class="fa-solid fa-shield-halved"></i>
                        <span>Your information is securely handled by Aiben Properties.</span>
                    </div>
                </div>
            </div>
        </div>
        <div class="row g-3">
            <div class="col-lg-6">
                <div class="glass card shadow-sm">
                    <div class="card-header bg-white d-flex justify-content-between align-items-center">
                        <strong><i class="fa-solid fa-id-card me-2"></i>Onboarding Form</strong>
                        <a href="client-onboarding.php?view=form" class="btn btn-sm btn-primary"><i class="fa-solid fa-pen-to-square me-1"></i>Open</a>
                    </div>
                    <div class="card-body">
                        <p class="text-muted mb-2">Complete your onboarding and upload your form receipt.</p>
                    </div>
                </div>
            </div>
            <div class="col-lg-6">
                <div class="glass card shadow-sm">
                    <div class="card-header bg-white d-flex justify-content-between align-items-center">
                        <strong><i class="fa-solid fa-file-invoice-dollar me-2"></i>Form Payment Status</strong>
                        <?php if ($clientPaymentsPage): ?>
                        <div class="d-flex gap-2 flex-wrap">
                            <a href="<?= $clientPaymentsPage ?>?open_upload=1" class="btn btn-sm btn-outline-dark"><i class="fa-solid fa-upload me-1"></i>Upload Proof</a>
                            <a href="<?= $clientPaymentsPage ?>" class="btn btn-sm btn-success"><i class="fa-solid fa-wallet me-1"></i>View Payments</a>
                        </div>
                        <?php endif; ?>
                    </div>
                    <div class="card-body">
                        <p class="text-muted mb-0">Track your form payments and verification status. Commission and internal workflows are not visible here.</p>
                    </div>
                </div>
            </div>
        </div>
        <?php
        $planPreview = [];
        $planPreviewMode = 'none';
        $companyIdPlan = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : (int)($_SESSION['company_id'] ?? 0);
        try {
            $hasAllocTbl = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
            $hasPropsTbl = $pdo->query("SHOW TABLES LIKE 'properties'")->rowCount() > 0;
            $hasInstTbl = $pdo->query("SHOW TABLES LIKE 'installments'")->rowCount() > 0;
            $hasPaySchedules = $pdo->query("SHOW TABLES LIKE 'payment_schedules'")->rowCount() > 0;
            $hasAllocCompany = function_exists('tableHasColumn') && $hasAllocTbl && tableHasColumn('allocations','company_id');
            if ($hasInstTbl && function_exists('tableHasColumn') && tableHasColumn('installments','due_date')) {
                $amtCol = tableHasColumn('installments','amount_due') ? 'amount_due' : (tableHasColumn('installments','amount') ? 'amount' : null);
                if ($amtCol) {
                    $titleCol = tableHasColumn('installments','plan_name') ? 'plan_name' : (tableHasColumn('installments','title') ? 'title' : null);
                    $statusCol = tableHasColumn('installments','status') ? 'status' : null;
                    $sql = "SELECT i.{$amtCol} AS amount, i.due_date, " . ($titleCol ? "i.{$titleCol} AS title" : "'' AS title") . ", p.title AS property_title
                            FROM installments i
                            JOIN allocations a ON i.allocation_id = a.id
                            LEFT JOIN properties p ON a.property_id = p.id
                            WHERE a.user_id = ? AND i.due_date IS NOT NULL AND i.due_date >= CURDATE()";
                    $params = [$user_id];
                    if ($statusCol) { $sql .= " AND LOWER(TRIM(i.{$statusCol})) IN ('pending','unpaid','due','part_paid')"; }
                    if ($companyIdPlan && $hasAllocCompany) { $sql .= " AND (a.company_id = ? OR a.company_id IS NULL)"; $params[] = $companyIdPlan; }
                    $sql .= " ORDER BY i.due_date ASC LIMIT 3";
                    $st = $pdo->prepare($sql);
                    $st->execute($params);
                    $planPreview = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
                    if (!empty($planPreview)) { $planPreviewMode = 'scheduled'; }
                }
            }
            if (empty($planPreview) && $hasPaySchedules && function_exists('tableHasColumn') && tableHasColumn('payment_schedules','due_date')) {
                $amtCol = tableHasColumn('payment_schedules','amount_due') ? 'amount_due' : (tableHasColumn('payment_schedules','amount') ? 'amount' : null);
                if ($amtCol) {
                    $titleCol = tableHasColumn('payment_schedules','title') ? 'title' : null;
                    $statusCol = tableHasColumn('payment_schedules','status') ? 'status' : null;
                    $sql = "SELECT ps.{$amtCol} AS amount, ps.due_date, " . ($titleCol ? "ps.{$titleCol} AS title" : "'' AS title") . ", p.title AS property_title
                            FROM payment_schedules ps
                            JOIN allocations a ON ps.allocation_id = a.id
                            LEFT JOIN properties p ON a.property_id = p.id
                            WHERE a.user_id = ? AND ps.due_date IS NOT NULL AND ps.due_date >= CURDATE()";
                    $params = [$user_id];
                    if ($statusCol) { $sql .= " AND LOWER(TRIM(ps.{$statusCol})) IN ('pending','unpaid','due','part_paid')"; }
                    if ($companyIdPlan && $hasAllocCompany) { $sql .= " AND (a.company_id = ? OR a.company_id IS NULL)"; $params[] = $companyIdPlan; }
                    $sql .= " ORDER BY ps.due_date ASC LIMIT 3";
                    $st = $pdo->prepare($sql);
                    $st->execute($params);
                    $planPreview = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
                    if (!empty($planPreview)) { $planPreviewMode = 'scheduled'; }
                }
            }
            if (empty($planPreview) && $hasAllocTbl && $hasPropsTbl) {
                $sql = "SELECT p.title AS property_title, NULL AS due_date, NULL AS amount, '' AS title
                        FROM allocations a
                        LEFT JOIN properties p ON a.property_id = p.id
                        WHERE a.user_id = ?";
                $params = [$user_id];
                if ($companyIdPlan && $hasAllocCompany) { $sql .= " AND (a.company_id = ? OR a.company_id IS NULL)"; $params[] = $companyIdPlan; }
                $sql .= " ORDER BY a.id DESC LIMIT 3";
                $st = $pdo->prepare($sql);
                $st->execute($params);
                $planPreview = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
                if (!empty($planPreview)) { $planPreviewMode = 'legacy'; }
            }
        } catch (Throwable $e) { $planPreview = []; $planPreviewMode = 'none'; }
        ?>
        <div class="row g-3 mt-1">
            <div class="col-12">
                <div class="glass card shadow-sm">
                    <div class="card-header bg-white d-flex justify-content-between align-items-center">
                        <strong><i class="fa-solid fa-calendar-check me-2"></i>Payment Plan</strong>
                        <?php if ($clientPaymentsPage): ?>
                        <div class="d-flex gap-2 flex-wrap">
                            <a href="<?= $clientPaymentsPage ?>#installment-plans" class="btn btn-sm btn-outline-secondary">View Plan</a>
                            <a href="<?= $clientPaymentsPage ?>?open_upload=1" class="btn btn-sm btn-outline-dark"><i class="fa-solid fa-upload me-1"></i>Upload Proof</a>
                        </div>
                        <?php endif; ?>
                    </div>
                    <div class="list-group list-group-flush">
                        <?php if (empty($planPreview)): ?>
                            <div class="list-group-item text-muted text-center py-4">No payment plan found yet.</div>
                        <?php else: ?>
                            <?php foreach ($planPreview as $row): ?>
                                <?php
                                    $pt = trim((string)($row['property_title'] ?? ''));
                                    $title = trim((string)($row['title'] ?? ''));
                                    $due = $row['due_date'] ?? null;
                                    $amt = isset($row['amount']) ? (float)$row['amount'] : 0.0;
                                    if (!is_finite($amt)) $amt = 0.0;
                                    $left = '';
                                    if ($due) {
                                        try { $left = (string)((new DateTime('today'))->diff(new DateTime((string)$due))->format('%r%a')); } catch (Throwable $e) { $left = ''; }
                                    }
                                ?>
                                <div class="list-group-item d-flex justify-content-between align-items-center">
                                    <div>
                                        <div class="fw-bold"><?= htmlspecialchars($title !== '' ? $title : ($pt !== '' ? $pt : 'Payment')) ?></div>
                                        <div class="small text-muted">
                                            <?php if ($due): ?>
                                                Due: <?= htmlspecialchars(date('M d, Y', strtotime((string)$due))) ?>
                                            <?php else: ?>
                                                Not scheduled yet
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                    <div class="text-end">
                                        <div class="fw-bold"><?= $amt > 0 ? ('₦' . number_format($amt, 2)) : '-' ?></div>
                                        <?php if ($due && $left !== '' && is_numeric($left)): ?>
                                            <?php $dl = (int)$left; ?>
                                            <?php if ($dl === 0): ?>
                                                <span class="badge bg-danger">Due Today</span>
                                            <?php elseif ($dl > 0 && $dl <= 7): ?>
                                                <span class="badge bg-warning text-dark">Due in <?= $dl ?> days</span>
                                            <?php elseif ($dl > 7): ?>
                                                <span class="badge bg-info text-dark">In <?= $dl ?> days</span>
                                            <?php else: ?>
                                                <span class="badge bg-danger"><?= abs($dl) ?> days late</span>
                                            <?php endif; ?>
                                        <?php elseif ($planPreviewMode === 'legacy'): ?>
                                            <span class="badge bg-secondary">Awaiting schedule</span>
                                        <?php endif; ?>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
        </div>
        <?php if (($allocation_letter_url || $transfer_certificate_url) || !empty($latestTransfer)): ?>
        <div class="row g-3 mt-1">
            <div class="col-12">
                <div class="glass card shadow-sm">
                    <div class="card-header bg-white"><strong><i class="fa-solid fa-folder-open me-2"></i>Documents</strong></div>
                    <div class="card-body">
                        <?php if (!empty($latestTransfer) && is_array($latestTransfer)): ?>
                            <?php
                                $tStatus = strtolower((string)($latestTransfer['status'] ?? 'pending'));
                                $isSeller = ((int)($latestTransfer['seller_id'] ?? 0) === (int)$user_id);
                                $tDir = $isSeller ? 'Outgoing' : 'Incoming';
                                $tProp = (string)($latestTransfer['property_title'] ?? ('Property #' . (int)($latestTransfer['property_id'] ?? 0)));
                                $badge = ($tStatus === 'approved') ? 'bg-success' : (($tStatus === 'rejected') ? 'bg-danger' : 'bg-warning text-dark');
                            ?>
                            <div class="mb-3">
                                <div class="d-flex flex-wrap justify-content-between align-items-center gap-2">
                                    <div>
                                        <div class="fw-bold"><i class="fa-solid fa-right-left me-2"></i>Ownership Transfer</div>
                                        <div class="small text-muted"><?= htmlspecialchars($tDir) ?> • <?= htmlspecialchars($tProp) ?></div>
                                    </div>
                                    <span class="badge <?= $badge ?>"><?= htmlspecialchars(ucfirst($tStatus)) ?></span>
                                </div>
                                <div class="mt-2">
                                    <a class="btn btn-outline-primary btn-sm" href="client-transfer-view.php?id=<?= (int)($latestTransfer['id'] ?? 0) ?>">View Transfer</a>
                                    <a class="btn btn-outline-secondary btn-sm ms-2" href="client-transfers.php">All Transfers</a>
                                </div>
                            </div>
                        <?php endif; ?>
                        <?php if ($allocation_letter_url): ?>
                        <a href="<?= htmlspecialchars($allocation_letter_url) ?>" target="_blank" class="btn btn-outline-secondary"><i class="fa-solid fa-file-signature me-2"></i>View Allocation Letter</a>
                        <?php endif; ?>
                        <?php if ($transfer_certificate_url): ?>
                        <a href="<?= htmlspecialchars($transfer_certificate_url) ?>" target="_blank" class="btn btn-outline-secondary ms-2"><i class="fa-solid fa-certificate me-2"></i>View Transfer Certificate</a>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
        </div>
        <?php endif; ?>
        <?php
        // Dashboard Overview metrics for client
        try {
            $total_paid = function_exists('kpiSumPayments')
                ? kpiSumPayments($pdo, kpiPaymentFinalizedStatuses(), null, null, null, null, false, " AND user_id = ?", [$user_id])
                : 0.0;
        } catch (Exception $e) { $total_paid = 0.0; }
        try {
            $invUserCol = (function_exists('tableHasColumn') && tableHasColumn('invoices','tenant_id')) ? 'tenant_id' : 'user_id';
            $outstanding_balance = function_exists('kpiSumInvoiceReceivables')
                ? kpiSumInvoiceReceivables($pdo, null, $user_id, $invUserCol)
                : 0.0;
        } catch (Exception $e) { $outstanding_balance = 0.0; }
        try {
            $active_properties = function_exists('kpiCountAllocations')
                ? kpiCountAllocations($pdo, array_merge(kpiAllocationStatuses('approved'), kpiAllocationStatuses('active'), kpiAllocationStatuses('completed')), null, false, " AND user_id = ?", [$user_id])
                : 0;
        } catch (Exception $e) { $active_properties = 0; }

        $propertyBalances = [];
        $propertyBalancesTotals = [
            'land' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
            'infrastructure' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
            'excavation' => ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
        ];
        try {
            $companyIdPB = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : (int)($_SESSION['company_id'] ?? 0);
            $propertyIds = [];
            try {
                if ($pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('allocations', 'property_id') && tableHasColumn('allocations', 'user_id')) {
                    $q = "SELECT DISTINCT property_id FROM allocations WHERE user_id = ? AND property_id IS NOT NULL";
                    $p = [$user_id];
                    if ($companyIdPB && tableHasColumn('allocations', 'company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyIdPB; }
                    $st = $pdo->prepare($q);
                    $st->execute($p);
                    foreach (($st->fetchAll(PDO::FETCH_COLUMN) ?: []) as $pid) {
                        $pid = (int)$pid;
                        if ($pid > 0) $propertyIds[$pid] = true;
                    }
                }
            } catch (Throwable $e) {}
            try {
                if ($pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('payments', 'property_id')) {
                    $where = [];
                    $params = [];
                    $userWhere = (tableHasColumn('payments', 'user_id') ? "user_id = ?" : "1=0");
                    $clientWhere = (tableHasColumn('payments', 'client_id') ? "client_id = ?" : "1=0");
                    $where[] = "(($userWhere) OR ($clientWhere))";
                    $params[] = $user_id;
                    $params[] = $user_id;
                    $where[] = "property_id IS NOT NULL";
                    if ($companyIdPB && tableHasColumn('payments', 'company_id')) { $where[] = "(company_id = ? OR company_id IS NULL)"; $params[] = $companyIdPB; }
                    $q = "SELECT DISTINCT property_id FROM payments WHERE " . implode(" AND ", $where) . " ORDER BY property_id DESC LIMIT 200";
                    $st = $pdo->prepare($q);
                    $st->execute($params);
                    foreach (($st->fetchAll(PDO::FETCH_COLUMN) ?: []) as $pid) {
                        $pid = (int)$pid;
                        if ($pid > 0) $propertyIds[$pid] = true;
                    }
                }
            } catch (Throwable $e) {}
            try {
                if ($pdo->query("SHOW TABLES LIKE 'deals_submit'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('deals_submit', 'meta_json') && tableHasColumn('deals_submit', 'user_id')) {
                    $q = "SELECT meta_json FROM deals_submit WHERE user_id = ?";
                    $p = [$user_id];
                    if ($companyIdPB && tableHasColumn('deals_submit', 'company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyIdPB; }
                    $q .= " ORDER BY created_at DESC LIMIT 80";
                    $st = $pdo->prepare($q);
                    $st->execute($p);
                    foreach (($st->fetchAll(PDO::FETCH_COLUMN) ?: []) as $mjRaw) {
                        if (!$mjRaw) continue;
                        $mj = json_decode((string)$mjRaw, true);
                        if (!is_array($mj)) continue;
                        $pid = (int)($mj['property_id'] ?? 0);
                        if ($pid > 0) $propertyIds[$pid] = true;
                    }
                }
            } catch (Throwable $e) {}

            $propertyIds = array_keys($propertyIds);
            sort($propertyIds);
            $propertyNameById = [];
            if (!empty($propertyIds) && $pdo->query("SHOW TABLES LIKE 'properties'")->rowCount() > 0 && function_exists('tableHasColumn') && tableHasColumn('properties', 'id')) {
                $nameCol = tableHasColumn('properties', 'title') ? 'title' : (tableHasColumn('properties', 'property_name') ? 'property_name' : 'id');
                $in = implode(',', array_fill(0, count($propertyIds), '?'));
                $q = "SELECT id, $nameCol AS nm FROM properties WHERE id IN ($in)";
                $p = $propertyIds;
                if ($companyIdPB && tableHasColumn('properties', 'company_id')) { $q .= " AND (company_id = ? OR company_id IS NULL)"; $p[] = $companyIdPB; }
                $st = $pdo->prepare($q);
                $st->execute($p);
                foreach (($st->fetchAll(PDO::FETCH_ASSOC) ?: []) as $r) {
                    $propertyNameById[(int)($r['id'] ?? 0)] = (string)($r['nm'] ?? '');
                }
            }

            foreach ($propertyIds as $pid) {
                $pid = (int)$pid;
                if ($pid <= 0) continue;
                $b = function_exists('getClientPropertyBalances') ? getClientPropertyBalances($pdo, $user_id, $pid, ($companyIdPB ?: null)) : null;
                if (!is_array($b)) continue;
                $propertyBalances[] = [
                    'property_id' => $pid,
                    'property_name' => (string)($propertyNameById[$pid] ?? ('Property #' . $pid)),
                    'land' => $b['land'] ?? ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
                    'infrastructure' => $b['infrastructure'] ?? ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
                    'excavation' => $b['excavation'] ?? ['total' => 0.0, 'paid' => 0.0, 'balance' => 0.0],
                ];
                foreach (['land','infrastructure','excavation'] as $t) {
                    $propertyBalancesTotals[$t]['total'] += (float)($b[$t]['total'] ?? 0);
                    $propertyBalancesTotals[$t]['paid'] += (float)($b[$t]['paid'] ?? 0);
                    $propertyBalancesTotals[$t]['balance'] += (float)($b[$t]['balance'] ?? 0);
                }
            }
        } catch (Throwable $e) { $propertyBalances = []; }
        $dealOverdueCount = 0;
        $dealOverdueAmount = 0.0;
        $dealDueTodayCount = 0;
        $dealDueTodayAmount = 0.0;
        $dealDue7Count = 0;
        $dealDue7Amount = 0.0;
        try {
            $companyIdTmp = function_exists('getCurrentCompanyId') ? getCurrentCompanyId() : ($_SESSION['company_id'] ?? null);
            $dealDue = function_exists('kpiDealPaymentDueSummary')
                ? kpiDealPaymentDueSummary($pdo, $companyIdTmp, true, $user_id)
                : ['overdue_count' => 0, 'overdue_amount' => 0.0, 'due_today_count' => 0, 'due_today_amount' => 0.0, 'due_7_count' => 0, 'due_7_amount' => 0.0];
            $dealOverdueCount = (int)($dealDue['overdue_count'] ?? 0);
            $dealOverdueAmount = (float)($dealDue['overdue_amount'] ?? 0);
            $dealDueTodayCount = (int)($dealDue['due_today_count'] ?? 0);
            $dealDueTodayAmount = (float)($dealDue['due_today_amount'] ?? 0);
            $dealDue7Count = (int)($dealDue['due_7_count'] ?? 0);
            $dealDue7Amount = (float)($dealDue['due_7_amount'] ?? 0);
        } catch (Throwable $e) { $dealOverdueCount = 0; $dealOverdueAmount = 0.0; $dealDueTodayCount = 0; $dealDueTodayAmount = 0.0; $dealDue7Count = 0; $dealDue7Amount = 0.0; }
        try {
            $stmt = $pdo->prepare("SELECT COALESCE(SUM(p.price),0) FROM allocations a JOIN properties p ON a.property_id = p.id WHERE a.user_id = ?");
            $stmt->execute([$user_id]);
            $total_investment = (float)$stmt->fetchColumn();
        } catch (Exception $e) { $total_investment = 0.0; }
        // Document status mapping
        $offerRaw = null; $allocRaw = null;
        try { $stO = $pdo->prepare("SELECT status FROM documents WHERE user_id = ? AND title LIKE '%Offer%' ORDER BY updated_at DESC, created_at DESC LIMIT 1"); $stO->execute([$user_id]); $offerRaw = strtolower((string)($stO->fetchColumn() ?: '')); } catch (Exception $e) {}
        try { $stA = $pdo->prepare("SELECT status FROM documents WHERE user_id = ? AND title LIKE '%Allocation%' ORDER BY updated_at DESC, created_at DESC LIMIT 1"); $stA->execute([$user_id]); $allocRaw = strtolower((string)($stA->fetchColumn() ?: '')); } catch (Exception $e) {}
        $mapLabel = function($raw) {
            $raw = strtolower((string)$raw);
            if (in_array($raw, ['approved','issued','signed','released'], true)) return ['Available','bg-success'];
            if (in_array($raw, ['rejected','revoked'], true)) return ['Rejected','bg-danger'];
            if (in_array($raw, ['archived'], true)) return ['Archived','bg-secondary'];
            if (in_array($raw, ['draft'], true)) return ['Draft','bg-light text-dark border'];
            if (in_array($raw, ['pending','pending_chairman_signature','awaiting_approval'], true)) return ['Awaiting Approval','bg-warning text-dark'];
            return [$raw ? ucfirst($raw) : 'Pending','bg-warning text-dark'];
        };
        [$offerLbl, $offerBadge] = $mapLabel($offerRaw);
        [$allocLbl, $allocBadge] = $mapLabel($allocRaw);
        if (!$offerRaw) { $offerLbl = 'Not yet issued'; }
        if (!$allocRaw) { $allocLbl = 'Not yet available'; }
        ?>
        <div class="row g-3 mt-3">
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Total Paid</div>
                            <div class="h4 mb-0"><?= formatCurrency($total_paid) ?></div>
                            <?php if ((float)$total_paid <= 0): ?>
                                <div class="journey-zero-note">You haven't made any payments yet. This will update once you proceed.</div>
                            <?php endif; ?>
                        </div>
                        <div class="icon-pill"><i class="fa-regular fa-circle-check"></i></div>
                    </div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Outstanding Balance</div>
                            <div class="h4 mb-0"><?= formatCurrency($outstanding_balance) ?></div>
                        </div>
                        <div class="icon-pill"><i class="fa-solid fa-wallet"></i></div>
                    </div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Number of Properties</div>
                            <div class="h4 mb-0"><?= (int)$active_properties ?></div>
                        </div>
                        <div class="icon-pill"><i class="fa-solid fa-house"></i></div>
                    </div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Investment Value</div>
                            <div class="h4 mb-0"><?= formatCurrency($total_investment) ?></div>
                        </div>
                        <div class="icon-pill accent"><i class="fa-solid fa-chart-line"></i></div>
                    </div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Deal Payments Overdue</div>
                            <div class="h4 mb-0"><?= number_format($dealOverdueCount) ?></div>
                            <div class="small text-muted">₦<?= number_format($dealOverdueAmount, 2) ?></div>
                        </div>
                        <div class="icon-pill"><i class="fa-solid fa-triangle-exclamation"></i></div>
                    </div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="glass p-3 shadow-sm h-100">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <div class="small text-muted">Deal Payments Due Today</div>
                            <div class="h4 mb-0"><?= number_format($dealDueTodayCount) ?></div>
                            <div class="small text-muted">₦<?= number_format($dealDueTodayAmount, 2) ?></div>
                        </div>
                        <div class="icon-pill"><i class="fa-solid fa-calendar-day"></i></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="row g-3 mt-1">
            <div class="col-12">
                <div class="glass card shadow-sm">
                    <div class="card-header bg-white d-flex justify-content-between align-items-center flex-wrap gap-2">
                        <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-coins me-2"></i>Property Payment Summary</h6>
                        <?php if ($clientPaymentsPage): ?>
                            <a href="<?= $clientPaymentsPage ?>" class="btn btn-sm btn-outline-secondary">View Payments</a>
                        <?php endif; ?>
                    </div>
                    <div class="card-body">
                        <?php if (empty($propertyBalances)): ?>
                            <div class="text-muted">No property payment records yet.</div>
                        <?php else: ?>
                            <div class="row g-2 mb-3">
                                <div class="col-12 col-lg-4"><div class="alert alert-light border mb-0 small">Land: <strong><?= formatCurrency((float)$propertyBalancesTotals['land']['paid']) ?></strong> / <?= formatCurrency((float)$propertyBalancesTotals['land']['total']) ?> (Bal: <?= formatCurrency((float)$propertyBalancesTotals['land']['balance']) ?>)</div></div>
                                <div class="col-12 col-lg-4"><div class="alert alert-light border mb-0 small">Infrastructure: <strong><?= formatCurrency((float)$propertyBalancesTotals['infrastructure']['paid']) ?></strong> / <?= formatCurrency((float)$propertyBalancesTotals['infrastructure']['total']) ?> (Bal: <?= formatCurrency((float)$propertyBalancesTotals['infrastructure']['balance']) ?>)</div></div>
                                <div class="col-12 col-lg-4"><div class="alert alert-light border mb-0 small">Excavation: <strong><?= formatCurrency((float)$propertyBalancesTotals['excavation']['paid']) ?></strong> / <?= formatCurrency((float)$propertyBalancesTotals['excavation']['total']) ?> (Bal: <?= formatCurrency((float)$propertyBalancesTotals['excavation']['balance']) ?>)</div></div>
                            </div>
                            <div class="table-responsive">
                                <table class="table table-sm align-middle mb-0">
                                    <thead>
                                        <tr>
                                            <th>Property</th>
                                            <th class="text-end">Land Paid / Total</th>
                                            <th class="text-end">Infra Paid / Total</th>
                                            <th class="text-end">Excav Paid / Total</th>
                                            <th class="text-end">Total Balance</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <?php foreach ($propertyBalances as $r): ?>
                                            <?php
                                                $land = $r['land'] ?? ['total'=>0,'paid'=>0,'balance'=>0];
                                                $infra = $r['infrastructure'] ?? ['total'=>0,'paid'=>0,'balance'=>0];
                                                $excav = $r['excavation'] ?? ['total'=>0,'paid'=>0,'balance'=>0];
                                                $balAll = (float)($land['balance'] ?? 0) + (float)($infra['balance'] ?? 0) + (float)($excav['balance'] ?? 0);
                                            ?>
                                            <tr>
                                                <td class="fw-semibold"><?= htmlspecialchars((string)($r['property_name'] ?? 'Property')) ?></td>
                                                <td class="text-end"><?= formatCurrency((float)($land['paid'] ?? 0)) ?> / <?= formatCurrency((float)($land['total'] ?? 0)) ?></td>
                                                <td class="text-end"><?= formatCurrency((float)($infra['paid'] ?? 0)) ?> / <?= formatCurrency((float)($infra['total'] ?? 0)) ?></td>
                                                <td class="text-end"><?= formatCurrency((float)($excav['paid'] ?? 0)) ?> / <?= formatCurrency((float)($excav['total'] ?? 0)) ?></td>
                                                <td class="text-end fw-bold"><?= formatCurrency($balAll) ?></td>
                                            </tr>
                                        <?php endforeach; ?>
                                    </tbody>
                                </table>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
            <div class="col-12 col-lg-6">
                <div class="glass card shadow-sm h-100">
                    <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
                        <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-file-contract me-2"></i>Document Status</h6>
                        <a href="client-documents.php" class="btn btn-sm btn-outline-secondary">View Documents</a>
                    </div>
                    <div class="list-group list-group-flush">
                        <div class="list-group-item d-flex justify-content-between align-items-center">
                            <div>Offer Letter</div>
                            <span class="badge <?= $offerBadge ?>"><?= htmlspecialchars($offerLbl) ?></span>
                        </div>
                        <div class="list-group-item d-flex justify-content-between align-items-center">
                            <div>Allocation Letter</div>
                            <span class="badge <?= $allocBadge ?>"><?= htmlspecialchars($allocLbl) ?></span>
                        </div>
                    </div>
                </div>
            </div>
            
            <?php
            // Upcoming Payments
            $upcomingInstallments = [];
            try {
                // Check if installments exists
                $hasInstTbl = $pdo->query("SHOW TABLES LIKE 'installments'")->rowCount() > 0;
                if ($hasInstTbl) {
                    $instQuery = "SELECT i.amount_due as amount, i.due_date, i.title, DATEDIFF(i.due_date, CURDATE()) as days_left 
                                  FROM installments i 
                                  JOIN allocations a ON i.allocation_id = a.id 
                                  WHERE a.user_id = ? AND i.status = 'pending' AND i.due_date >= CURDATE()
                                  ORDER BY i.due_date ASC LIMIT 3";
                    $stU = $pdo->prepare($instQuery);
                    $stU->execute([$user_id]);
                    $upcomingInstallments = $stU->fetchAll(PDO::FETCH_ASSOC);
                }
            } catch (Exception $e) {}
            ?>
            <div class="col-12 col-lg-6">
                <div class="glass card shadow-sm h-100">
                    <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
                        <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-calendar-clock me-2"></i>Upcoming Payments</h6>
                        <?php if ($clientPaymentsPage): ?>
                        <a href="<?= $clientPaymentsPage ?>" class="btn btn-sm btn-outline-secondary">View All</a>
                        <?php endif; ?>
                    </div>
                    <div class="list-group list-group-flush">
                        <?php if (empty($upcomingInstallments)): ?>
                            <div class="list-group-item text-muted text-center py-4">No upcoming payments found.</div>
                        <?php else: ?>
                            <?php foreach ($upcomingInstallments as $inst): ?>
                                <div class="list-group-item d-flex justify-content-between align-items-center">
                                    <div>
                                        <div class="fw-bold"><?= htmlspecialchars($inst['title'] ?? 'Installment') ?></div>
                                        <div class="small text-muted">Due: <?= date('M d, Y', strtotime($inst['due_date'])) ?></div>
                                    </div>
                                    <div class="text-end">
                                        <div class="fw-bold">₦<?= number_format((float)$inst['amount'], 2) ?></div>
                                        <?php if ($inst['days_left'] == 0): ?>
                                            <span class="badge bg-danger">Due Today</span>
                                        <?php elseif ($inst['days_left'] <= 7): ?>
                                            <span class="badge bg-warning text-dark">Due in <?= $inst['days_left'] ?> days</span>
                                        <?php else: ?>
                                            <span class="badge bg-info text-dark">In <?= $inst['days_left'] ?> days</span>
                                        <?php endif; ?>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <?php
    include 'includes/footer.php';
    exit;
}

// 1. Fetch Key Stats
// Total Paid
$total_paid = function_exists('kpiSumPayments')
    ? kpiSumPayments($pdo, kpiPaymentFinalizedStatuses(), null, null, null, null, false, " AND user_id = ?", [$user_id])
    : 0;

// Outstanding Balance (from Invoices)
$invUserCol = tableHasColumn('invoices', 'tenant_id') ? 'tenant_id' : 'user_id';
$outstanding_balance = function_exists('kpiSumInvoiceReceivables')
    ? kpiSumInvoiceReceivables($pdo, null, $user_id, $invUserCol)
    : 0;

// Active Allocations
$active_properties = function_exists('kpiCountAllocations')
    ? kpiCountAllocations($pdo, array_merge(kpiAllocationStatuses('active'), kpiAllocationStatuses('completed')), null, false, " AND user_id = ?", [$user_id])
    : 0;

// Total Investment Value
try {
    $stmt = $pdo->prepare("SELECT COALESCE(SUM(p.price),0) FROM allocations a JOIN properties p ON a.property_id = p.id WHERE a.user_id = ?");
    $stmt->execute([$user_id]);
    $total_investment = (float)$stmt->fetchColumn();
} catch (Exception $e) { $total_investment = 0.0; }

// Latest Allocation Status and Progress
$alloc_status = null;
$alloc_progress = 0;
try {
    $stmt = $pdo->prepare("SELECT status FROM allocations WHERE user_id = ? ORDER BY updated_at DESC LIMIT 1");
    $stmt->execute([$user_id]);
    $alloc_status = $stmt->fetchColumn() ?: null;
} catch (Exception $e) {}
$status_map = [
    'draft' => 10,
    'pending customer care' => 20,
    'pending finance' => 40,
    'ready for allocation' => 60,
    'pending executive' => 80,
    'approved' => 100,
    'completed' => 100,
    'revoked' => 0,
    'rejected' => 0
];
if ($alloc_status) {
    $k = strtolower($alloc_status);
    $alloc_progress = $status_map[$k] ?? (in_array($k, ['active']) ? 100 : 0);
}

// Next Payment Due Date
$next_due_date = null;
$next_start_date = null;
try {
    $hasInstTbl = $pdo->query("SHOW TABLES LIKE 'installments'")->rowCount() > 0;
    if ($hasInstTbl && function_exists('tableHasColumn') && tableHasColumn('installments', 'due_date')) {
        $amountDueCol = tableHasColumn('installments', 'amount_due') ? 'amount_due' : (tableHasColumn('installments', 'amount') ? 'amount' : null);
        $amountPaidCol = tableHasColumn('installments', 'paid_amount') ? 'paid_amount' : (tableHasColumn('installments', 'amount_paid') ? 'amount_paid' : null);
        
        $sql = "SELECT i.due_date, a.created_at as start_date 
                FROM installments i 
                JOIN allocations a ON i.allocation_id = a.id 
                WHERE a.user_id = ? AND LOWER(TRIM(i.status)) != 'paid'";
                
        if ($amountDueCol && $amountPaidCol) {
            $sql .= " AND COALESCE(i.$amountPaidCol,0) < COALESCE(i.$amountDueCol,0)";
        }
        
        $sql .= " ORDER BY i.due_date ASC LIMIT 1";
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$user_id]);
        $res = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($res) {
            $next_due_date = $res['due_date'];
            $next_start_date = $res['start_date'];
        }
    } else if (tableHasColumn('invoices', 'due_date')) {
        $invUserCol2 = tableHasColumn('invoices', 'tenant_id') ? 'tenant_id' : 'user_id';
        $stmt = $pdo->prepare("SELECT MIN(due_date) FROM invoices WHERE $invUserCol2 = ? AND status != 'paid'");
        $stmt->execute([$user_id]);
        $next_due_date = $stmt->fetchColumn() ?: null;
    }
} catch (Exception $e) {}
$virtualNext = null;
if (!$next_due_date) {
    try {
        $companyIdV = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : 0;
        $hasAllocTblV = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
        $hasPayTblV = $pdo->query("SHOW TABLES LIKE 'payments'")->rowCount() > 0;
        $hasDealsTblV = $pdo->query("SHOW TABLES LIKE 'deals'")->rowCount() > 0;
        $hasPropsTblV = $pdo->query("SHOW TABLES LIKE 'properties'")->rowCount() > 0;
        if ($hasAllocTblV && function_exists('tableHasColumn')) {
            $propCol = tableHasColumn('allocations','property_id') ? 'property_id' : null;
            $dealCol = tableHasColumn('allocations','deal_id') ? 'deal_id' : null;
            $createdCol = tableHasColumn('allocations','created_at') ? 'created_at' : (tableHasColumn('allocations','updated_at') ? 'updated_at' : null);
            $sel = ["id"];
            $sel[] = $propCol ? $propCol : "0 AS property_id";
            $sel[] = $dealCol ? "COALESCE($dealCol,0) AS deal_id" : "0 AS deal_id";
            $sel[] = $createdCol ? "$createdCol AS created_at" : "'' AS created_at";
            $qA = "SELECT " . implode(',', $sel) . " FROM allocations WHERE user_id = ?";
            $pA = [(int)$user_id];
            if ($companyIdV && tableHasColumn('allocations','company_id')) { $qA .= " AND (company_id = ? OR company_id IS NULL)"; $pA[] = $companyIdV; }
            $qA .= " ORDER BY id DESC LIMIT 200";
            $stA = $pdo->prepare($qA);
            $stA->execute($pA);
            $allocRowsV = $stA->fetchAll(PDO::FETCH_ASSOC) ?: [];

            $approvedByAllocV = [];
            if ($hasPayTblV && tableHasColumn('payments','allocation_id')) {
                $statusApproved = function_exists('kpiSqlList') ? kpiSqlList(kpiPaymentFinalizedStatuses()) : "('verified','approved','paid','completed','success')";
                $qP = "SELECT allocation_id, COALESCE(SUM(amount),0) AS total_paid FROM payments WHERE status IN $statusApproved AND allocation_id IS NOT NULL AND allocation_id > 0";
                $pP = [];
                if (tableHasColumn('payments','user_id') && tableHasColumn('payments','client_id')) { $qP .= " AND (user_id = ? OR client_id = ?)"; $pP[] = (int)$user_id; $pP[] = (int)$user_id; }
                elseif (tableHasColumn('payments','user_id')) { $qP .= " AND user_id = ?"; $pP[] = (int)$user_id; }
                elseif (tableHasColumn('payments','client_id')) { $qP .= " AND client_id = ?"; $pP[] = (int)$user_id; }
                else { $qP .= " AND 1=0"; }
                if ($companyIdV && tableHasColumn('payments','company_id')) { $qP .= " AND (company_id = ? OR company_id IS NULL)"; $pP[] = $companyIdV; }
                $qP .= " GROUP BY allocation_id";
                $stP = $pdo->prepare($qP);
                $stP->execute($pP);
                foreach (($stP->fetchAll(PDO::FETCH_ASSOC) ?: []) as $r) {
                    $aid = (int)($r['allocation_id'] ?? 0);
                    if ($aid > 0) { $approvedByAllocV[$aid] = (float)($r['total_paid'] ?? 0); }
                }
            }

            $best = null;
            foreach ($allocRowsV as $ar) {
                $aid = (int)($ar['id'] ?? 0);
                if ($aid <= 0) continue;
                $propId = (int)($ar['property_id'] ?? 0);
                $dealId = (int)($ar['deal_id'] ?? 0);
                $createdAt = (string)($ar['created_at'] ?? '');
                $startDate = (preg_match('/^\d{4}-\d{2}-\d{2}/', $createdAt) ? substr($createdAt, 0, 10) : '');
                $paidApproved = (float)($approvedByAllocV[$aid] ?? 0);
                if (!is_finite($paidApproved) || $paidApproved < 0) { $paidApproved = 0.0; }

                $planType = '';
                if ($hasPayTblV && tableHasColumn('payments','allocation_id')) {
                    $metaCol = tableHasColumn('payments','meta_json') ? 'meta_json' : null;
                    $planCol = tableHasColumn('payments','plan_type') ? 'plan_type' : (tableHasColumn('payments','payment_plan') ? 'payment_plan' : null);
                    $selP = ["id"];
                    if ($metaCol) { $selP[] = $metaCol; }
                    if ($planCol) { $selP[] = $planCol; }
                    $qPL = "SELECT " . implode(',', $selP) . " FROM payments WHERE allocation_id = ?";
                    $pPL = [$aid];
                    if (tableHasColumn('payments','user_id') && tableHasColumn('payments','client_id')) { $qPL .= " AND (user_id = ? OR client_id = ?)"; $pPL[] = (int)$user_id; $pPL[] = (int)$user_id; }
                    elseif (tableHasColumn('payments','user_id')) { $qPL .= " AND user_id = ?"; $pPL[] = (int)$user_id; }
                    elseif (tableHasColumn('payments','client_id')) { $qPL .= " AND client_id = ?"; $pPL[] = (int)$user_id; }
                    else { $qPL .= " AND 1=0"; }
                    if ($companyIdV && tableHasColumn('payments','company_id')) { $qPL .= " AND (company_id = ? OR company_id IS NULL)"; $pPL[] = $companyIdV; }
                    $qPL .= " ORDER BY id DESC LIMIT 1";
                    $stPL = $pdo->prepare($qPL);
                    $stPL->execute($pPL);
                    $rp = $stPL->fetch(PDO::FETCH_ASSOC) ?: null;
                    if ($rp) {
                        $customMonths = 0;
                        $planRaw = '';
                        if ($metaCol && !empty($rp[$metaCol])) {
                            $mj = json_decode((string)$rp[$metaCol], true);
                            if (is_array($mj)) {
                                $planRaw = (string)($mj['plan_type'] ?? ($mj['payment_plan'] ?? ''));
                                $s0 = (string)($mj['installment_start_date'] ?? '');
                                if ($startDate === '' && $s0 !== '' && preg_match('/^\d{4}-\d{2}-\d{2}/', $s0)) { $startDate = substr($s0, 0, 10); }
                                $customMonths = (int)($mj['custom_months'] ?? 0);
                            }
                        }
                        if ($planRaw === '' && $planCol && !empty($rp[$planCol])) { $planRaw = (string)$rp[$planCol]; }
                        $planN = strtolower(trim((string)$planRaw));
                        $planN = str_replace([' ', '-'], '_', $planN);
                        $planN = preg_replace('/_+/', '_', $planN);
                        if ($planN === 'custom' && $customMonths > 0) { $planN = 'custom_' . (int)$customMonths . '_months'; }
                        if (preg_match('/(\d+)_?months?/', $planN, $m)) { $planN = (int)$m[1] . '_months'; }
                        if ($planN !== '') { $planType = $planN; }
                    }
                }

                if ($planType === '' && $dealId > 0 && $hasDealsTblV && tableHasColumn('deals','payment_plan')) {
                    $stD = $pdo->prepare("SELECT payment_plan FROM deals WHERE id = ? LIMIT 1");
                    $stD->execute([$dealId]);
                    $planRaw = (string)($stD->fetchColumn() ?: '');
                    $planN = strtolower(trim($planRaw));
                    $planN = str_replace([' ', '-'], '_', $planN);
                    $planN = preg_replace('/_+/', '_', $planN);
                    if (preg_match('/(\d+)_?months?/', $planN, $m)) { $planN = (int)$m[1] . '_months'; }
                    if ($planN !== '') { $planType = $planN; }
                }

                $totalAmt = 0.0;
                if ($dealId > 0 && $hasDealsTblV && tableHasColumn('deals','amount_offered')) {
                    $discCol = tableHasColumn('deals','discount_amount') ? 'discount_amount' : null;
                    $qD = "SELECT amount_offered" . ($discCol ? ", $discCol AS discount_amount" : ", 0 AS discount_amount") . " FROM deals WHERE id = ? LIMIT 1";
                    $stD = $pdo->prepare($qD);
                    $stD->execute([$dealId]);
                    $rD = $stD->fetch(PDO::FETCH_ASSOC) ?: null;
                    if ($rD) {
                        $off = (float)($rD['amount_offered'] ?? 0);
                        $disc = (float)($rD['discount_amount'] ?? 0);
                        if (!is_finite($off)) $off = 0.0;
                        if (!is_finite($disc)) $disc = 0.0;
                        $totalAmt = max(0.0, $off - max(0.0, $disc));
                    }
                }
                if (($totalAmt <= 0.01) && $propId > 0 && $hasPropsTblV && tableHasColumn('properties','price')) {
                    $stPr = $pdo->prepare("SELECT price FROM properties WHERE id = ? LIMIT 1");
                    $stPr->execute([$propId]);
                    $pr = (float)($stPr->fetchColumn() ?: 0);
                    if (!is_finite($pr)) $pr = 0.0;
                    $totalAmt = max(0.0, $pr);
                }

                if ($totalAmt > 0.01 && $planType !== '' && function_exists('computeVirtualNextDueFromPlan')) {
                    $v = computeVirtualNextDueFromPlan($totalAmt, $planType, $startDate, $paidApproved);
                    if (is_array($v) && !empty($v['date']) && $v['date'] instanceof DateTime) {
                        if (!$best || ($v['date'] < $best['date'])) {
                            $best = $v;
                            $best['start_date'] = $startDate;
                        }
                    }
                }
            }

            if ($best && !empty($best['date']) && $best['date'] instanceof DateTime) {
                $virtualNext = $best;
                $next_due_date = $best['date']->format('Y-m-d');
                $next_start_date = (string)($best['start_date'] ?? '');
            }
        }
    } catch (Throwable $e) {}
}

// Allocation Letter link
$allocation_letter_url = null;
$transfer_certificate_url = null;
try {
    $hasDocsTbl = $pdo->query("SHOW TABLES LIKE 'documents'")->rowCount() > 0;
    if ($hasDocsTbl) {
        $hasType = function_exists('tableHasColumn') && tableHasColumn('documents', 'type');
        $hasStatus = function_exists('tableHasColumn') && tableHasColumn('documents', 'status');
        $hasUpdatedAt = function_exists('tableHasColumn') && tableHasColumn('documents', 'updated_at');
        $hasCreatedAt = function_exists('tableHasColumn') && tableHasColumn('documents', 'created_at');
        $hasDocAllocId = function_exists('tableHasColumn') && tableHasColumn('documents', 'allocation_id');
        $orderExpr = 'id DESC';
        if ($hasUpdatedAt && $hasCreatedAt) { $orderExpr = "COALESCE(updated_at, created_at) DESC, id DESC"; }
        elseif ($hasUpdatedAt) { $orderExpr = "updated_at DESC, id DESC"; }
        elseif ($hasCreatedAt) { $orderExpr = "created_at DESC, id DESC"; }

        $latestAllocId = 0;
        try {
            $hasAllocsTbl = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
            if ($hasAllocsTbl) {
                $allocWhere = "user_id = ?";
                if (function_exists('tableHasColumn') && tableHasColumn('allocations', 'status')) { $allocWhere .= " AND LOWER(TRIM(status)) <> 'transferred'"; }
                $stA = $pdo->prepare("SELECT id FROM allocations WHERE {$allocWhere} ORDER BY id DESC LIMIT 1");
                $stA->execute([$user_id]);
                $latestAllocId = (int)($stA->fetchColumn() ?: 0);
            }
        } catch (Throwable $e) { $latestAllocId = 0; }

        $whereAlloc = "user_id = ?";
        $paramsAlloc = [$user_id];
        if ($hasType) { $whereAlloc .= " AND (type IN ('allocation_letter','allocation','letter') OR file_path LIKE '%Allocation_Letter_%')"; }
        else { $whereAlloc .= " AND file_path LIKE '%Allocation_Letter_%'"; }
        if ($hasStatus) { $whereAlloc .= " AND LOWER(TRIM(status)) IN ('released','issued','signed','approved','draft','pending')"; }
        if ($latestAllocId > 0 && $hasDocAllocId) {
            $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereAlloc} AND allocation_id = ? ORDER BY {$orderExpr} LIMIT 1");
            $st->execute(array_merge($paramsAlloc, [$latestAllocId]));
            $allocation_letter_url = $st->fetchColumn() ?: null;
        }
        if (!$allocation_letter_url) {
            $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereAlloc} ORDER BY {$orderExpr} LIMIT 1");
            $st->execute($paramsAlloc);
            $allocation_letter_url = $st->fetchColumn() ?: null;
        }

        $whereCert = "user_id = ?";
        $paramsCert = [$user_id];
        if ($hasType) { $whereCert .= " AND (type IN ('transfer_certificate') OR file_path LIKE '%Transfer_Certificate_%')"; }
        else { $whereCert .= " AND file_path LIKE '%Transfer_Certificate_%'"; }
        if ($hasStatus) { $whereCert .= " AND LOWER(TRIM(status)) IN ('released','issued','signed','approved','draft','pending')"; }
        if ($latestAllocId > 0 && $hasDocAllocId) {
            $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereCert} AND allocation_id = ? ORDER BY {$orderExpr} LIMIT 1");
            $st->execute(array_merge($paramsCert, [$latestAllocId]));
            $transfer_certificate_url = $st->fetchColumn() ?: null;
        }
        if (!$transfer_certificate_url) {
            $st = $pdo->prepare("SELECT file_path FROM documents WHERE {$whereCert} ORDER BY {$orderExpr} LIMIT 1");
            $st->execute($paramsCert);
            $transfer_certificate_url = $st->fetchColumn() ?: null;
        }
    }
} catch (Exception $e) {}

// 2. Fetch Recent Allocations
$propLocationCol = tableHasColumn('properties', 'location') ? 'location' 
    : (tableHasColumn('properties', 'address') ? 'address' 
    : (tableHasColumn('properties', 'city') ? 'city' : null));
$selectLocation = $propLocationCol ? ", p.$propLocationCol as property_location" : "";
$recent_allocs = $pdo->prepare("
    SELECT a.*, p.title as property_title $selectLocation
    FROM allocations a 
    JOIN properties p ON a.property_id = p.id 
    WHERE a.user_id = ? 
    ORDER BY a.created_at DESC LIMIT 3
");
$recent_allocs->execute([$user_id]);
$allocations = $recent_allocs->fetchAll();

// 3. Fetch Recent Documents
$docs_stmt = $pdo->prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC LIMIT 5");
$docs_stmt->execute([$user_id]);
$documents = $docs_stmt->fetchAll();

// 4. Fetch Recent Payments
$pay_stmt = $pdo->prepare("SELECT * FROM payments WHERE user_id = ? ORDER BY created_at DESC LIMIT 5");
$pay_stmt->execute([$user_id]);
$payments = $pay_stmt->fetchAll();

// 5. Fetch Recent Tickets
$ticket_stmt = $pdo->prepare("SELECT * FROM support_tickets WHERE user_id = ? ORDER BY updated_at DESC LIMIT 3");
$ticket_stmt->execute([$user_id]);
$recent_tickets = $ticket_stmt->fetchAll();

$my_properties = $allocations; // Fix variable name mismatch
?>

<div class="container-fluid px-4 homy-skin">
    <?php 
         $dealDue = function_exists('kpiDealPaymentDueSummary') ? kpiDealPaymentDueSummary($pdo, null, true, $user_id) : [];
         $extraOverdueCount = 0;
         $extraOverdueAmount = 0.0;
         try {
             $hasAllocTbl = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
             $hasInstTbl = $pdo->query("SHOW TABLES LIKE 'installments'")->rowCount() > 0;
             $hasPsTbl = $pdo->query("SHOW TABLES LIKE 'payment_schedules'")->rowCount() > 0;
             if ($hasAllocTbl) {
                 $stA = $pdo->prepare("SELECT id, COALESCE(deal_id,0) AS deal_id FROM allocations WHERE user_id = ? ORDER BY id DESC");
                 $stA->execute([(int)$user_id]);
                 $allocRows = $stA->fetchAll(PDO::FETCH_ASSOC) ?: [];
                 $dealAlloc = [];
                 $allocIds = [];
                 foreach ($allocRows as $ar) {
                     $aid = (int)($ar['id'] ?? 0);
                     if ($aid <= 0) continue;
                     $allocIds[] = $aid;
                     if ((int)($ar['deal_id'] ?? 0) > 0) { $dealAlloc[$aid] = true; }
                 }
                 $allocIds = array_values(array_unique($allocIds));
                 if (!empty($allocIds)) {
                     $nonDealAllocIds = [];
                     foreach ($allocIds as $aid) { if (empty($dealAlloc[$aid])) { $nonDealAllocIds[] = $aid; } }
                     $allocHasInst = [];
                     if ($hasInstTbl && function_exists('tableHasColumn') && tableHasColumn('installments','allocation_id')) {
                         $ph = implode(',', array_fill(0, count($allocIds), '?'));
                         $sqlC = "SELECT allocation_id, COUNT(*) c FROM installments WHERE allocation_id IN ($ph)";
                         if (tableHasColumn('installments','kind')) { $sqlC .= " AND kind = 'installment'"; }
                         $sqlC .= " GROUP BY allocation_id";
                         $stC = $pdo->prepare($sqlC);
                         $stC->execute($allocIds);
                         foreach (($stC->fetchAll(PDO::FETCH_ASSOC) ?: []) as $r) {
                             if ((int)($r['c'] ?? 0) > 0) { $allocHasInst[(int)$r['allocation_id']] = true; }
                         }
                     }
                     if ($hasInstTbl && !empty($nonDealAllocIds)) {
                         $ph = implode(',', array_fill(0, count($nonDealAllocIds), '?'));
                         $amountDueCol = (function_exists('tableHasColumn') && tableHasColumn('installments', 'amount_due')) ? 'amount_due' : (tableHasColumn('installments','amount') ? 'amount' : null);
                         $amountPaidCol = (function_exists('tableHasColumn') && tableHasColumn('installments', 'paid_amount')) ? 'paid_amount' : (tableHasColumn('installments','amount_paid') ? 'amount_paid' : null);
                         $hasKindCol = function_exists('tableHasColumn') && tableHasColumn('installments', 'kind');
                         if ($amountDueCol) {
                             $clauses = ["allocation_id IN ($ph)", "due_date < CURDATE()"];
                             if ($hasKindCol) { $clauses[] = "kind = 'installment'"; }
                             if ($amountPaidCol) { $clauses[] = "COALESCE($amountPaidCol,0) < COALESCE($amountDueCol,0)"; }
                             $outExpr = $amountPaidCol ? "GREATEST(0, COALESCE($amountDueCol,0) - COALESCE($amountPaidCol,0))" : "COALESCE($amountDueCol,0)";
                             $sql = "SELECT COUNT(*) c, COALESCE(SUM($outExpr),0) s FROM installments WHERE " . implode(' AND ', $clauses);
                             $st = $pdo->prepare($sql);
                             $st->execute($nonDealAllocIds);
                             $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
                             $extraOverdueCount += (int)($row['c'] ?? 0);
                             $extraOverdueAmount += (float)($row['s'] ?? 0);
                         }
                     }
                     if ($hasPsTbl && !empty($nonDealAllocIds)) {
                         $useAllocIds = [];
                         foreach ($nonDealAllocIds as $aid) { if (empty($allocHasInst[$aid])) { $useAllocIds[] = $aid; } }
                         if (!empty($useAllocIds)) {
                             $ph = implode(',', array_fill(0, count($useAllocIds), '?'));
                             $amountDueCol = (function_exists('tableHasColumn') && tableHasColumn('payment_schedules', 'amount_due')) ? 'amount_due' : (tableHasColumn('payment_schedules','amount') ? 'amount' : null);
                             $amountPaidCol = (function_exists('tableHasColumn') && tableHasColumn('payment_schedules', 'amount_paid')) ? 'amount_paid' : (tableHasColumn('payment_schedules','paid_amount') ? 'paid_amount' : null);
                             if ($amountDueCol) {
                                 $outExpr = $amountPaidCol ? "GREATEST(0, COALESCE($amountDueCol,0) - COALESCE($amountPaidCol,0))" : "COALESCE($amountDueCol,0)";
                                 $sql = "SELECT COUNT(*) c, COALESCE(SUM($outExpr),0) s FROM payment_schedules WHERE allocation_id IN ($ph) AND due_date < CURDATE()";
                                 if ($amountPaidCol) { $sql .= " AND COALESCE($amountPaidCol,0) < COALESCE($amountDueCol,0)"; }
                                 $st = $pdo->prepare($sql);
                                 $st->execute($useAllocIds);
                                 $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
                                 $extraOverdueCount += (int)($row['c'] ?? 0);
                                 $extraOverdueAmount += (float)($row['s'] ?? 0);
                             }
                         }
                     }
                 }
             }
         } catch (Throwable $e) {}

         $isOverdue = (($dealDue['overdue_count'] ?? 0) > 0) || ($extraOverdueCount > 0);
         $overdueAmount = (float)($dealDue['overdue_amount'] ?? 0) + (float)$extraOverdueAmount;
         $overduePenalty = $isOverdue ? round($overdueAmount * 0.05, 2) : 0.0;
         $totalOverdueWithPenalty = $overdueAmount + $overduePenalty;
         $isDueToday = ($dealDue['due_today_count'] ?? 0) > 0;
         $dueTodayAmount = (float)($dealDue['due_today_amount'] ?? 0);

         $risk30Count = 0;
         $risk30Amount = 0.0;
         try {
             $cidDash = function_exists('getCurrentCompanyId') ? (int)getCurrentCompanyId() : 0;
             $hasAllocTbl = $pdo->query("SHOW TABLES LIKE 'allocations'")->rowCount() > 0;
             $hasAllocCompany = $hasAllocTbl && function_exists('tableHasColumn') && tableHasColumn('allocations', 'company_id');

             $hasInstTbl = $pdo->query("SHOW TABLES LIKE 'installments'")->rowCount() > 0;
             if ($hasAllocTbl && $hasInstTbl && function_exists('tableHasColumn') && tableHasColumn('installments', 'allocation_id') && tableHasColumn('installments', 'due_date')) {
                 $amountDueCol = tableHasColumn('installments', 'amount_due') ? 'amount_due' : (tableHasColumn('installments', 'amount') ? 'amount' : null);
                 $amountPaidCol = tableHasColumn('installments', 'paid_amount') ? 'paid_amount' : (tableHasColumn('installments', 'amount_paid') ? 'amount_paid' : null);
                 $hasKindCol = tableHasColumn('installments', 'kind');
                 $hasStatusCol = tableHasColumn('installments', 'status');
                 if ($amountDueCol) {
                     $clauses = ["a.user_id = ?", "i.due_date < DATE_SUB(CURDATE(), INTERVAL 30 DAY)"];
                     $params = [(int)$user_id];
                     if ($hasAllocCompany && $cidDash) { $clauses[] = "(a.company_id = ? OR a.company_id IS NULL)"; $params[] = $cidDash; }
                     if ($hasKindCol) { $clauses[] = "i.kind = 'installment'"; }
                     if ($amountPaidCol) { $clauses[] = "COALESCE(i.$amountPaidCol,0) < COALESCE(i.$amountDueCol,0)"; }
                     if ($hasStatusCol) { $clauses[] = "LOWER(TRIM(COALESCE(i.status,''))) <> 'paid'"; }
                     $outExpr = $amountPaidCol ? "GREATEST(0, COALESCE(i.$amountDueCol,0) - COALESCE(i.$amountPaidCol,0))" : "COALESCE(i.$amountDueCol,0)";
                     $sql = "SELECT COUNT(*) AS c, COALESCE(SUM($outExpr),0) AS s FROM installments i JOIN allocations a ON a.id = i.allocation_id WHERE " . implode(' AND ', $clauses);
                     $st = $pdo->prepare($sql);
                     $st->execute($params);
                     $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
                     $risk30Count += (int)($row['c'] ?? 0);
                     $risk30Amount += (float)($row['s'] ?? 0);
                 }
             }

             $hasPsTbl = $pdo->query("SHOW TABLES LIKE 'payment_schedules'")->rowCount() > 0;
             if ($hasAllocTbl && $hasPsTbl && function_exists('tableHasColumn') && tableHasColumn('payment_schedules', 'allocation_id') && tableHasColumn('payment_schedules', 'due_date')) {
                 $amountDueCol = tableHasColumn('payment_schedules', 'amount_due') ? 'amount_due' : (tableHasColumn('payment_schedules', 'amount') ? 'amount' : null);
                 $amountPaidCol = tableHasColumn('payment_schedules', 'amount_paid') ? 'amount_paid' : (tableHasColumn('payment_schedules', 'paid_amount') ? 'paid_amount' : null);
                 $hasStatusCol = tableHasColumn('payment_schedules', 'status');
                 if ($amountDueCol) {
                     $clauses = ["a.user_id = ?", "ps.due_date < DATE_SUB(CURDATE(), INTERVAL 30 DAY)"];
                     $params = [(int)$user_id];
                     if ($hasAllocCompany && $cidDash) { $clauses[] = "(a.company_id = ? OR a.company_id IS NULL)"; $params[] = $cidDash; }
                     if ($amountPaidCol) { $clauses[] = "COALESCE(ps.$amountPaidCol,0) < COALESCE(ps.$amountDueCol,0)"; }
                     if ($hasStatusCol) { $clauses[] = "LOWER(TRIM(COALESCE(ps.status,''))) <> 'paid'"; }
                     $outExpr = $amountPaidCol ? "GREATEST(0, COALESCE(ps.$amountDueCol,0) - COALESCE(ps.$amountPaidCol,0))" : "COALESCE(ps.$amountDueCol,0)";
                     $sql = "SELECT COUNT(*) AS c, COALESCE(SUM($outExpr),0) AS s FROM payment_schedules ps JOIN allocations a ON a.id = ps.allocation_id WHERE " . implode(' AND ', $clauses);
                     $st = $pdo->prepare($sql);
                     $st->execute($params);
                     $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
                     $risk30Count += (int)($row['c'] ?? 0);
                     $risk30Amount += (float)($row['s'] ?? 0);
                 }
             }
         } catch (Throwable $e) {}
         $risk30Penalty = round($risk30Amount * 0.05, 2);
         $risk30Total = $risk30Amount + $risk30Penalty;
     ?>
     <?php if ($risk30Count > 0): ?>
        <div class="alert alert-danger alert-dismissible fade show shadow-sm border-start border-5 border-danger mt-3" role="alert">
            <div class="d-flex align-items-center">
                <div class="fs-1 me-3"><i class="fa-solid fa-triangle-exclamation"></i></div>
                <div>
                    <h5 class="alert-heading mb-1 fw-bold">30+ Days Overdue Warning</h5>
                    <p class="mb-0">Some payments are <strong>30+ days overdue</strong>. Outstanding: <strong>₦<?= number_format($risk30Amount, 2) ?></strong> + penalty: <strong>₦<?= number_format($risk30Penalty, 2) ?></strong>. Total exposure: <strong>₦<?= number_format($risk30Total, 2) ?></strong>. Please contact support or make payment immediately.</p>
                </div>
                <div class="ms-auto d-flex gap-2">
                    <a href="client-payments.php" class="btn btn-dark rounded-pill px-4">View Schedule</a>
                    <a href="client-onboarding.php?view=payments" class="btn btn-danger rounded-pill px-4 shadow-sm">Pay Now</a>
                </div>
            </div>
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
        </div>
     <?php endif; ?>

     <?php if ($isOverdue): ?>
         <div class="alert alert-danger alert-dismissible fade show shadow-sm border-start border-5 border-danger animate__animated animate__pulse animate__infinite mt-3" role="alert">
             <div class="d-flex align-items-center">
                 <div class="fs-1 me-3"><i class="fa-solid fa-triangle-exclamation"></i></div>
                 <div>
                     <h5 class="alert-heading mb-1 fw-bold">Overdue Payment Alert</h5>
                     <p class="mb-0">You have an overdue payment of <strong>₦<?= number_format($overdueAmount, 2) ?></strong> plus a 5% late penalty of <strong>₦<?= number_format($overduePenalty, 2) ?></strong>. Total due: <strong>₦<?= number_format($totalOverdueWithPenalty, 2) ?></strong>. Please make payment immediately to avoid service disruption.</p>
                 </div>
                 <div class="ms-auto">
                     <a href="client-onboarding.php?view=payments" class="btn btn-danger rounded-pill px-4 shadow-sm">Pay Now</a>
                 </div>
             </div>
             <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
         </div>
     <?php elseif ($isDueToday): ?>
        <div class="alert alert-warning alert-dismissible fade show shadow-sm border-start border-5 border-warning mt-3" role="alert">
            <div class="d-flex align-items-center">
                <div class="fs-1 me-3 text-dark"><i class="fa-solid fa-calendar-day"></i></div>
                <div>
                    <h5 class="alert-heading mb-1 fw-bold text-dark">Payment Due Today</h5>
                    <p class="mb-0 text-dark">A payment of <strong>₦<?= number_format($dueTodayAmount, 2) ?></strong> is due today. Please ensure your payment is recorded.</p>
                </div>
                <div class="ms-auto">
                    <a href="client-onboarding.php?view=payments" class="btn btn-dark rounded-pill px-4">View Details</a>
                </div>
            </div>
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
        </div>
    <?php endif; ?>

    <?php
        $account_status = 'active';
        try {
            $st = $pdo->prepare("SELECT status FROM users WHERE id = ?");
            $st->execute([$user_id]);
            $account_status = $st->fetchColumn() ?: 'active';
        } catch (Exception $e) {}
        try {
            if (strtolower($account_status) !== 'active') {
                $cnt = 0;
                $ps = $pdo->prepare("SELECT COUNT(*) FROM payments WHERE user_id = ? AND LOWER(status) IN ('verified','approved','completed','paid','success')");
                $ps->execute([$user_id]);
                $cnt = (int)$ps->fetchColumn();
                if ($cnt > 0 && function_exists('tableHasColumn') && tableHasColumn('users','status')) {
                    $pdo->prepare("UPDATE users SET status = 'active' WHERE id = ?")->execute([$user_id]);
                    $account_status = 'active';
                }
            }
        } catch (Exception $e) {}
        $clientPaymentsPage = file_exists(__DIR__ . '/client-payments.php') ? 'client-payments.php' : (file_exists(__DIR__ . '/my-invoices.php') ? 'my-invoices.php' : null);
    ?>
    <div class="d-flex justify-content-between align-items-center flex-wrap gap-3 mt-4 mb-4">
        <div>
            <h1 class="h3 mb-0 text-navy">Welcome, <?= htmlspecialchars($welcome_name) ?></h1>
            <p class="text-muted"><?= $isAdminTier ? 'Admin Viewer of Client Dashboard' : 'Your Client Dashboard Overview' ?></p>
        </div>
        <?php if ($isAdminTier): ?>
        <div>
            <div class="d-flex flex-wrap gap-2">
                <a href="clients.php?client_id=<?= (int)$user_id ?>" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-user-pen me-1"></i> Manage Client</a>
                <a href="allocations.php?user_id=<?= (int)$user_id ?>" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-file-signature me-1"></i> Allocations</a>
                <?php if (file_exists(__DIR__ . '/client-transfers.php')): ?>
                <a href="client-transfers.php?client_id=<?= (int)$user_id ?>" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-right-left me-1"></i> Transfers</a>
                <?php endif; ?>
                <a href="documents.php?user_id=<?= (int)$user_id ?>" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-folder-tree me-1"></i> Documents</a>
                <a href="customer-care.php?user_id=<?= (int)$user_id ?>" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-headset me-1"></i> Tickets</a>
            </div>
        </div>
        <?php endif; ?>
        <div>
            <?php if (strtolower($account_status) === 'active'): ?>
                <span class="badge bg-success p-2"><i class="fa-solid fa-check-circle me-1"></i> Account Active</span>
            <?php else: ?>
                <span class="badge bg-warning text-dark p-2"><i class="fa-solid fa-hourglass-half me-1"></i> Pending Activation</span>
            <?php endif; ?>
        </div>
    </div>
    <?php if (!empty($myCelebrationCards)): ?>
        <div class="row g-3 mb-4">
            <?php foreach ($myCelebrationCards as $card): ?>
                <div class="col-12 col-md-6">
                    <div class="glass card shadow-sm h-100">
                        <div class="card-body d-flex gap-3 align-items-start">
                            <div class="rounded-circle d-flex align-items-center justify-content-center" style="width:44px;height:44px;background:rgba(25,135,84,0.10);color:#198754;">
                                <i class="<?= htmlspecialchars($card['icon']) ?>"></i>
                            </div>
                            <div class="flex-grow-1">
                                <div class="d-flex justify-content-between align-items-center">
                                    <h6 class="mb-1 text-navy"><?= htmlspecialchars($card['title']) ?></h6>
                                    <span class="badge bg-success-subtle text-success"><?= htmlspecialchars($card['meta']) ?></span>
                                </div>
                                <div class="text-muted small">Occurs on <?= htmlspecialchars($card['date']) ?></div>
                            </div>
                        </div>
                    </div>
                </div>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>
    <?php if (!$isAdminTier && file_exists(__DIR__ . '/client-transfers.php')): ?>
        <div class="d-flex justify-content-end mb-3">
            <a href="client-transfers.php" class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-right-left me-2"></i>Transfer History</a>
        </div>
    <?php endif; ?>
    <?php
        $revokedCount = 0;
        try {
            $revokedCount = function_exists('kpiCountAllocations')
                ? kpiCountAllocations($pdo, kpiAllocationStatuses('revoked'), null, false, " AND user_id = ?", [$user_id])
                : 0;
        } catch (Exception $e) {}
        if ($revokedCount > 0):
    ?>
    <div class="alert alert-danger d-flex align-items-center" role="alert">
        <i class="fa-solid fa-triangle-exclamation me-2"></i>
        <div>Account Revoked — Contact Support</div>
    </div>
    <?php endif; ?>

    <style>
    :root {
        --accent: #ff7a1a;
        --ink: #101828;
        --muted: #667085;
        --soft: #fff7f2;
        --border: #eef0f2;
    }
    .homy-skin {
        background: linear-gradient(180deg, var(--soft) 0, #fff 280px);
    }
    .glass {
        background: #fff;
        border: 1px solid var(--border);
        border-radius: 16px;
        box-shadow: 0 2px 8px rgba(16,24,40,.04);
        transition: transform .15s ease, box-shadow .15s ease;
    }
    .glass:hover {
        transform: translateY(-2px);
        box-shadow: 0 6px 20px rgba(16,24,40,.08);
    }
    .table-responsive, .list-group {
        border-radius: 12px;
        overflow: hidden;
        border: 1px solid var(--border);
    }
    .homy-skin .table {
        border-collapse: separate;
        border-spacing: 0;
    }
    .homy-skin .table thead th {
        background: #f8fafc;
        color: #475467;
        font-weight: 600;
        border-bottom-color: var(--border);
    }
    .homy-skin .table tbody td {
        border-top-color: var(--border);
    }
    .homy-skin .table-hover tbody tr:hover {
        background: #fafafa;
    }
    .metric {
        display: flex;
        align-items: center;
        justify-content: space-between;
    }
    .metric .label {
        text-transform: none;
        font-size: 12px;
        color: var(--muted);
        margin-bottom: 2px;
    }
    .metric .value {
        font-weight: 800;
        font-size: 2rem;
        color: var(--ink);
        letter-spacing: -0.02em;
    }
    .icon-pill {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: #0f172a;
        color: #fff;
        box-shadow: inset 0 0 0 2px rgba(255,255,255,.2);
    }
    .icon-pill.accent {
        background: var(--accent);
    }
    .timeline-bar {
        width: 100%;
        height: 10px;
        background: #f1f3f5;
        border-radius: 999px;
        overflow: hidden;
    }
    .timeline-fill {
        height: 100%;
        background: linear-gradient(90deg, var(--accent), #fb923c);
    }
    .card {
        border-radius: 16px;
        border: 1px solid var(--border);
    }
    .card-header {
        border-bottom: 1px solid var(--border);
    }
    .card-footer {
        border-top: 1px solid var(--border);
    }
    .list-group-item {
        border: 0;
        border-bottom: 1px solid var(--border);
        transition: background .12s ease;
    }
    .list-group-item:hover {
        background: #fafafa;
    }
    .homy-skin .badge {
        border-radius: 10px;
        padding: .35rem .55rem;
        font-weight: 600;
    }
    .btn-primary, .btn-success, .btn-dark {
        border-radius: 12px;
    }
    .btn, .btn-sm, .btn-outline-primary, .btn-outline-secondary, .btn-outline-dark {
        border-radius: 12px;
    }
    .btn:hover {
        transform: translateY(-1px);
    }
    @media (max-width: 767.98px) {
        .homy-skin .metric .value { font-size: 1.4rem; }
        .homy-skin .d-flex.gap-2.mb-3 { flex-wrap: wrap; }
        .homy-skin .card-header.d-flex { flex-wrap: wrap; gap: .5rem; }
        .homy-skin .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }
        .homy-skin .table-responsive table { width: max-content; min-width: 680px; }
    }
    </style>
    <div class="row g-3 mb-4">
        <div class="col-6 col-lg-3">
            <div class="glass p-3 shadow-sm h-100">
                <div class="metric">
                    <div>
                        <div class="label">Total Properties</div>
                        <div class="value"><?= $active_properties ?></div>
                    </div>
                    <div class="icon-pill"><i class="fa-solid fa-house"></i></div>
                </div>
            </div>
        </div>
        <div class="col-6 col-lg-3">
            <div class="glass p-3 shadow-sm h-100">
                <div class="metric">
                    <div>
                        <div class="label">Investment Value</div>
                        <div class="value"><?= formatCurrency($total_investment) ?></div>
                    </div>
                    <div class="icon-pill accent"><i class="fa-solid fa-chart-line"></i></div>
                </div>
            </div>
        </div>
        <div class="col-6 col-lg-3">
            <div class="glass p-3 shadow-sm h-100">
                <div class="metric">
                    <div>
                        <div class="label">Total Paid</div>
                        <div class="value"><?= formatCurrency($total_paid) ?></div>
                    </div>
                    <div class="icon-pill"><i class="fa-regular fa-circle-check"></i></div>
                </div>
            </div>
        </div>
        <div class="col-6 col-lg-3">
            <div class="glass p-3 shadow-sm h-100">
                <div class="metric">
                    <div>
                        <div class="label">Outstanding</div>
                        <div class="value"><?= formatCurrency($outstanding_balance) ?></div>
                    </div>
                    <div class="icon-pill"><i class="fa-solid fa-wallet"></i></div>
                </div>
            </div>
        </div>
    </div>

    <div class="row g-3 mb-4">
        <div class="col-lg-8">
            <div class="glass p-3 shadow-sm h-100">
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div class="fw-semibold">Allocation Status</div>
                    <div>
                        <?php if ($alloc_status): ?>
                            <span class="badge <?= getStatusBadgeClass($alloc_status) ?>"><?= ucfirst($alloc_status) ?></span>
                        <?php else: ?>
                            <span class="badge bg-secondary">N/A</span>
                        <?php endif; ?>
                    </div>
                </div>
                <div class="timeline-bar mb-2"><div class="timeline-fill" style="width: <?= max(0,min(100,(int)$alloc_progress)) ?>%"></div></div>
                <div class="d-flex justify-content-between text-muted small">
                    <span>Draft</span><span>Pending CC</span><span>Finance</span><span>Ready</span><span>Executive</span><span>Approved</span>
                </div>
            </div>
        </div>
        <div class="col-lg-4">
            <div class="glass p-3 shadow-sm h-100">
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div>
                        <div class="label">Next Payment Due</div>
                        <div class="h5 mb-0"><?= $next_due_date ? date('M d, Y', strtotime($next_due_date)) : '—' ?></div>
                    </div>
                    <a href="my-invoices.php" class="btn btn-sm btn-success">Make Payment</a>
                </div>
                <?php if ($next_due_date): ?>
                    <div class="payment-countdown mt-3" data-due-date="<?= htmlspecialchars($next_due_date) ?>" data-start-date="<?= htmlspecialchars($next_start_date ?? '') ?>" data-show-progress="true" data-status="pending"></div>
                <?php endif; ?>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Main Content: Allocations & Payments -->
        <div class="col-lg-8">
            <div class="d-flex flex-wrap gap-2 mb-3">
                <a href="my-invoices.php" class="btn btn-dark"><i class="fa-regular fa-credit-card me-2"></i>Make Payment</a>
                <?php if ($allocation_letter_url): ?>
                <a href="<?= htmlspecialchars($allocation_letter_url) ?>" target="_blank" class="btn btn-outline-secondary"><i class="fa-solid fa-file-signature me-2"></i>Allocation Letter</a>
                <?php endif; ?>
                <?php if ($transfer_certificate_url): ?>
                <a href="<?= htmlspecialchars($transfer_certificate_url) ?>" target="_blank" class="btn btn-outline-secondary"><i class="fa-solid fa-certificate me-2"></i>Transfer Certificate</a>
                <?php endif; ?>
                <a href="client-support.php?prefill=inspection" class="btn btn-outline-primary"><i class="fa-solid fa-calendar-check me-2"></i>Book Site Inspection</a>
                <a href="client-support.php" class="btn btn-outline-secondary"><i class="fa-solid fa-headset me-2"></i>Open Support Ticket</a>
            </div>
            
            <!-- My Properties -->
            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-house-user me-2"></i>My Properties</h6>
                    <?php if ($isAdminTier): ?>
                        <a href="allocations.php?user_id=<?= (int)$user_id ?>" class="btn btn-sm btn-outline-primary">Open Allocations</a>
                    <?php else: ?>
                        <a href="client-properties.php" class="btn btn-sm btn-outline-primary">View All</a>
                    <?php endif; ?>
                </div>
                <div class="card-body">
                    <?php if (empty($my_properties)): ?>
                        <div class="text-center py-4 text-muted">
                            <i class="fa-solid fa-folder-open fa-3x mb-3 text-gray-300"></i>
                            <p>You have no active property allocations or leases.</p>
                        </div>
                    <?php else: ?>
                        <div class="table-responsive">
                            <table class="table table-hover align-middle">
                                <thead class="table-light">
                                    <tr>
                                        <th>Property</th>
                                        <th>Type</th>
                                        <th>Location</th>
                                        <th>Status</th>
                                        <th>Action</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach ($my_properties as $prop): ?>
                                    <tr>
                                        <td>
                                            <div class="fw-bold text-navy"><?= htmlspecialchars($prop['property_title']) ?></div>
                                            <small class="text-muted"><?= htmlspecialchars($prop['property_code'] ?? '') ?></small>
                                        </td>
                                        <td><span class="badge bg-light text-dark border"><?= $prop['type'] ?></span></td>
                                        <td><?= htmlspecialchars($prop['property_location'] ?? '-') ?></td>
                                        <td>
                                            <span class="badge <?= getStatusBadgeClass($prop['status']) ?>">
                                                <?= ucfirst($prop['status']) ?>
                                            </span>
                                        </td>
                                        <td>
                                            <?php if ($prop['type'] === 'Lease'): ?>
                                                <a href="rental-details.php?id=<?= $prop['id'] ?>" class="btn btn-sm btn-outline-primary">Manage</a>
                                            <?php else: ?>
                                                <button class="btn btn-sm btn-light border" disabled>Details</button>
                                            <?php endif; ?>
                                        </td>
                                    </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                    <?php endif; ?>
                </div>
            </div>

            <!-- Payment History -->
            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-money-bill-wave me-2"></i>Recent Payments</h6>
                    <div class="d-flex gap-2 flex-wrap">
                        <a href="<?= $clientPaymentsPage ? ($clientPaymentsPage . '?open_upload=1') : '#' ?>" class="btn btn-sm btn-outline-dark"><i class="fa-solid fa-upload me-1"></i>Upload Proof</a>
                        <a href="<?= $clientPaymentsPage ?: '#' ?>" class="btn btn-sm btn-success"><i class="fa-solid fa-plus me-1"></i> Make Payment</a>
                    </div>
                </div>
                <div class="card-body">
                    <?php if (empty($payments)): ?>
                        <div class="text-center">
                            <p class="text-muted text-center mb-1">You haven't made any payments yet.</p>
                            <div class="journey-zero-note">This will update once you proceed.</div>
                        </div>
                    <?php else: ?>
                        <div class="table-responsive">
                            <table class="table table-sm">
                                <thead>
                                    <tr>
                                        <th>Date</th>
                                        <th>Amount</th>
                                        <th>Method</th>
                                        <th>Status</th>
                                        <th>Receipt</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach ($payments as $pay): ?>
                                    <tr>
                                        <td><?= date('M d, Y', strtotime($pay['created_at'])) ?></td>
                                        <td class="fw-bold"><?= formatCurrency($pay['amount']) ?></td>
                                        <td><?= ucfirst($pay['payment_method'] ?? ($pay['method'] ?? 'transfer')) ?></td>
                                        <td>
                                            <span class="badge <?= getStatusBadgeClass($pay['status']) ?>">
                                                <?= ucfirst($pay['status']) ?>
                                            </span>
                                        </td>
                                        <td>
                                            <?php 
                                                $okStatuses = ['verified','approved','completed','paid','success'];
                                                $hasProof = !empty($pay['proof_file'] ?? '');
                                            ?>
                                            <?php if ($hasProof && in_array(strtolower($pay['status']), array_map('strtolower', $okStatuses))): ?>
                                                <a class="btn btn-outline-secondary btn-sm me-1" target="_blank" href="<?= htmlspecialchars($pay['proof_file']) ?>">View</a>
                                                <a class="btn btn-outline-primary btn-sm me-1" href="<?= htmlspecialchars($pay['proof_file']) ?>" download>Download</a>
                                                <button class="btn btn-outline-dark btn-sm" data-bs-toggle="modal" data-bs-target="#printPaymentReceipt<?= (int)$pay['id'] ?>">Print</button>
                                                <div class="modal fade" id="printPaymentReceipt<?= (int)$pay['id'] ?>" tabindex="-1" aria-labelledby="printPaymentReceiptLabel<?= (int)$pay['id'] ?>" aria-hidden="true">
                                                    <div class="modal-dialog modal-lg">
                                                        <div class="modal-content">
                                                            <div class="modal-header">
                                                                <h5 class="modal-title" id="printPaymentReceiptLabel<?= (int)$pay['id'] ?>">Print Receipt</h5>
                                                                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                                            </div>
                                                            <div class="modal-body">
                                                                <iframe id="payFrame-<?= (int)$pay['id'] ?>" src="<?= htmlspecialchars($pay['proof_file']) ?>" width="100%" height="500px" style="border:0;"></iframe>
                                                            </div>
                                                            <div class="modal-footer">
                                                                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                                                                <button type="button" class="btn btn-dark" onclick="document.getElementById('payFrame-<?= (int)$pay['id'] ?>').contentWindow.print()">Print</button>
                                                            </div>
                                                        </div>
                                                    </div>
                                                </div>
                                            <?php else: ?>
                                                <span class="text-muted">-</span>
                                            <?php endif; ?>
                                        </td>
                                    </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                    <?php endif; ?>
                </div>
            </div>

        </div>

        <!-- Sidebar: Documents & Notifications -->
        <div class="col-lg-4">

            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-bell me-2"></i>Notifications</h6>
                    <a href="<?= $clientPaymentsPage ?: '#' ?>" class="btn btn-sm btn-outline-secondary">View</a>
                </div>
                <div class="list-group list-group-flush">
                    <?php
                    $notices = [];
                    try {
                        if (tableHasColumn('invoices','due_date')) {
                            $invUserColN = tableHasColumn('invoices','tenant_id') ? 'tenant_id' : 'user_id';
                            $stN = $pdo->prepare("SELECT id, amount, due_date, status FROM invoices WHERE $invUserColN = ? AND status IN ('unpaid','overdue') AND due_date <= DATE_ADD(NOW(), INTERVAL 7 DAY) ORDER BY due_date ASC LIMIT 5");
                            $stN->execute([$user_id]);
                            $notices = $stN->fetchAll(PDO::FETCH_ASSOC);
                        }
                    } catch (Exception $e) {}
                    ?>
                    <?php if (empty($notices)): ?>
                        <div class="list-group-item text-muted text-center py-3">No upcoming dues.</div>
                    <?php else: ?>
                        <?php foreach ($notices as $n): ?>
                        <div class="list-group-item d-flex justify-content-between align-items-center flex-wrap gap-2">
                            <div>
                                <div class="fw-semibold">Invoice #<?= (int)$n['id'] ?></div>
                                <div class="small text-muted">Due <?= date('M d, Y', strtotime($n['due_date'])) ?></div>
                            </div>
                            <div class="text-end">
                                <div class="fw-bold"><?= formatCurrency((float)$n['amount']) ?></div>
                                <span class="badge <?= getStatusBadgeClass($n['status']) ?>"><?= ucfirst($n['status']) ?></span>
                            </div>
                        </div>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </div>
            </div>

            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-building-columns me-2"></i>Pay via Bank Transfer</h6>
                </div>
                <div class="card-body">
                    <?php
                        $accs = [];
                        if (function_exists('getSetting')) {
                            $accs = json_decode(getSetting('company_bank_accounts','[]'), true) ?: [];
                            if ($accs) {
                                usort($accs, function($a, $b){
                                    return (int)!($a['preferred'] ?? false) <=> (int)!($b['preferred'] ?? false);
                                });
                            }
                        }
                    ?>
                    <?php if (empty($accs)): ?>
                        <div class="small">
                            <div class="fw-semibold">Bank Transfer Details</div>
                            <div class="text-muted">Bank Name: —</div>
                            <div class="text-muted">Account Name: —</div>
                            <div class="text-muted">Account Number: —</div>
                            <div class="text-muted mt-2">Please contact support if details are unavailable.</div>
                        </div>
                    <?php else: ?>
                        <?php 
                            $df = function_exists('getSetting') ? (int)getSetting('onboarding_form_fee','30000') : 30000;
                            $di = function_exists('getSetting') ? (int)getSetting('infrastructure_fee','0') : 0;
                        ?>
                        <div class="row g-2">
                            <?php foreach ($accs as $acc): ?>
                                <div class="col-12">
                                    <div class="p-2 border rounded">
                                        <div class="d-flex justify-content-between align-items-center">
                                            <div class="small text-muted"><?= htmlspecialchars($acc['bank_name'] ?? '') ?></div>
                                            <div>
                                                <?php if (!empty($acc['preferred'])): ?><span class="badge bg-success me-1">Preferred</span><?php endif; ?>
                                                <span class="badge bg-light text-dark border">Bank Transfer</span>
                                            </div>
                                        </div>
                                        <div class="fw-bold"><?= htmlspecialchars($acc['account_number'] ?? '') ?></div>
                                        <div class="small"><?= htmlspecialchars($acc['account_name'] ?? '') ?></div>
                                        <div class="small text-muted mt-1">Form fee: <?= formatCurrency($df) ?></div>
                                        <?php if (!empty($acc['branch']) || !empty($acc['swift_bic'])): ?>
                                            <div class="small text-muted mt-1">
                                                <?php if (!empty($acc['branch'])): ?><span>Branch: <?= htmlspecialchars($acc['branch']) ?></span><?php endif; ?>
                                                <?php if (!empty($acc['branch']) && !empty($acc['swift_bic'])): ?> • <?php endif; ?>
                                                <?php if (!empty($acc['swift_bic'])): ?><span>SWIFT/BIC: <?= htmlspecialchars($acc['swift_bic']) ?></span><?php endif; ?>
                                            </div>
                                        <?php endif; ?>
                                    </div>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>
                </div>
            </div>

            <!-- Recent Tickets -->
            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-headset me-2"></i>Support</h6>
                    <a href="client-support.php" class="btn btn-sm btn-outline-primary">View All</a>
                </div>
                <div class="list-group list-group-flush">
                    <?php if (empty($recent_tickets)): ?>
                        <div class="list-group-item text-muted text-center py-3">No active tickets.</div>
                    <?php else: ?>
                        <?php foreach ($recent_tickets as $ticket): ?>
                        <a href="ticket-details.php?id=<?= $ticket['id'] ?>" class="list-group-item list-group-item-action px-3 py-3">
                            <div class="d-flex w-100 justify-content-between align-items-center">
                                <div class="text-truncate me-2" style="max-width: 70%;">
                                    <h6 class="mb-1 text-dark text-truncate"><?= htmlspecialchars($ticket['subject']) ?></h6>
                                    <small class="text-muted">
                                        <span class="badge bg-light text-dark border me-1"><?= ucfirst($ticket['status']) ?></span>
                                        <?= date('M d', strtotime($ticket['updated_at'])) ?>
                                    </small>
                                </div>
                                <i class="fa-solid fa-chevron-right text-gray-300 small"></i>
                            </div>
                        </a>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </div>
                <div class="card-footer bg-white text-center">
                    <a href="client-support.php" class="btn btn-sm btn-primary w-100">
                        <i class="fa-solid fa-plus me-2"></i>New Ticket
                    </a>
                </div>
            </div>
            
            <!-- Documents -->
            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-file-contract me-2"></i>My Documents</h6>
                </div>
                <div class="list-group list-group-flush">
                    <?php if (empty($documents)): ?>
                        <div class="list-group-item text-muted text-center">No documents available.</div>
                    <?php else: ?>
                        <?php foreach ($documents as $doc): ?>
                        <div class="list-group-item px-3 py-3">
                            <div class="d-flex w-100 justify-content-between align-items-center">
                                <div class="text-truncate me-2">
                                    <h6 class="mb-1 text-dark"><?= htmlspecialchars($doc['title']) ?></h6>
                                    <small class="text-muted"><?= ucfirst($doc['type']) ?> • <?= date('M d', strtotime($doc['created_at'])) ?></small>
                                </div>
                                <a href="<?= htmlspecialchars($doc['file_path']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">
                                    <i class="fa-solid fa-download"></i>
                                </a>
                            </div>
                        </div>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </div>
                <div class="card-footer bg-white text-center">
                    <a href="client-documents.php" class="small fw-bold text-navy text-decoration-none">View All Documents</a>
                </div>
            </div>

            <!-- Document Status -->
            <div class="glass card shadow mb-4">
                <div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-file-signature me-2"></i>Document Status</h6>
                </div>
                <div class="list-group list-group-flush">
                    <?php
                    $offerRaw = null; $allocRaw = null;
                    try {
                        $stO = $pdo->prepare("SELECT status FROM documents WHERE user_id = ? AND title LIKE '%Offer%' ORDER BY updated_at DESC, created_at DESC LIMIT 1");
                        $stO->execute([$user_id]); $offerRaw = strtolower((string)($stO->fetchColumn() ?: ''));
                    } catch (Exception $e) {}
                    try {
                        $stA = $pdo->prepare("SELECT status FROM documents WHERE user_id = ? AND title LIKE '%Allocation%' ORDER BY updated_at DESC, created_at DESC LIMIT 1");
                        $stA->execute([$user_id]); $allocRaw = strtolower((string)($stA->fetchColumn() ?: ''));
                    } catch (Exception $e) {}
                    $mapLabel = function($raw, $titleHint = '') {
                        $raw = strtolower((string)$raw);
                        if (in_array($raw, ['approved','issued','signed','released'], true)) return ['Available','bg-success'];
                        if (in_array($raw, ['rejected','revoked'], true)) return ['Rejected','bg-danger'];
                        if (in_array($raw, ['archived'], true)) return ['Archived','bg-secondary'];
                        if (in_array($raw, ['draft'], true)) return ['Draft','bg-light text-dark border'];
                        if (in_array($raw, ['pending','pending_chairman_signature','awaiting_approval'], true)) return ['Awaiting Approval','bg-warning text-dark'];
                        return [$raw ? ucfirst($raw) : 'Pending','bg-warning text-dark'];
                    };
                    [$offerLbl, $offerBadge] = $mapLabel($offerRaw, 'offer');
                    [$allocLbl, $allocBadge] = $mapLabel($allocRaw, 'allocation');
                    ?>
                    <div class="list-group-item d-flex justify-content-between align-items-center">
                        <div>Offer Letter</div>
                        <span class="badge <?= $offerBadge ?>"><?= htmlspecialchars($offerLbl) ?></span>
                    </div>
                    <div class="list-group-item d-flex justify-content-between align-items-center">
                        <div>Allocation Letter</div>
                        <span class="badge <?= $allocBadge ?>"><?= htmlspecialchars($allocLbl) ?></span>
                    </div>
                </div>
            </div>

            <!-- Notifications (Mock) -->
            <div class="card shadow mb-4">
                <div class="card-header bg-white py-3">
                    <h6 class="m-0 font-weight-bold text-navy"><i class="fa-solid fa-bell me-2"></i>Notifications</h6>
                </div>
                <div class="list-group list-group-flush">
                    <div class="list-group-item px-3 py-3 border-left-warning">
                        <div class="d-flex w-100 justify-content-between">
                            <strong class="text-warning">Payment Due</strong>
                            <small class="text-muted">Today</small>
                        </div>
                        <p class="mb-1 small">Installment for Plot #404 is due tomorrow.</p>
                    </div>
                    <div class="list-group-item px-3 py-3">
                        <div class="d-flex w-100 justify-content-between">
                            <strong class="text-navy">Welcome</strong>
                            <small class="text-muted">3 days ago</small>
                        </div>
                        <p class="mb-1 small">Welcome to the Aiben Client Dashboard!</p>
                    </div>
                </div>
            </div>

            <?php renderGuzapeFaq(); ?>

        </div>
    </div>
</div>

<?php if (!empty($celebrationPopup) && is_array($celebrationPopup)): ?>
    <div class="modal fade" id="celebrationPopupModal" tabindex="-1" aria-labelledby="celebrationPopupModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="celebrationPopupModalLabel"><?= htmlspecialchars((string)($celebrationPopup['headline'] ?? '')) ?></h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div class="text-muted"><?= htmlspecialchars((string)($celebrationPopup['detail'] ?? '')) ?></div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" data-bs-dismiss="modal">Thank you</button>
                </div>
            </div>
        </div>
    </div>
    <script>
        (function () {
            function ymd(d) {
                var y = d.getFullYear();
                var m = String(d.getMonth() + 1).padStart(2, '0');
                var day = String(d.getDate()).padStart(2, '0');
                return y + '-' + m + '-' + day;
            }

            var modalId = 'celebrationPopupModal';
            var modalEl = document.getElementById(modalId);
            if (!modalEl) return;

            var userId = <?= (int)$user_id ?>;
            var kinds = <?= json_encode(array_values((array)($celebrationPopup['kinds'] ?? []))) ?>;
            var key = 'ap_celebration_popup_seen_' + userId + '_' + ymd(new Date()) + '_' + kinds.join('_');
            try {
                if (localStorage.getItem(key) === '1') return;
                localStorage.setItem(key, '1');
            } catch (e) {}

            function show() {
                if (window.bootstrap && bootstrap.Modal) {
                    bootstrap.Modal.getOrCreateInstance(modalEl).show();
                    return;
                }
                if (window.jQuery && jQuery.fn && jQuery.fn.modal) {
                    jQuery(modalEl).modal('show');
                }
            }

            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', show);
            } else {
                show();
            }
        })();
    </script>
<?php endif; ?>

<?php include 'includes/footer.php'; ?>

Youez - 2016 - github.com/yon3zu
LinuXploit