403Webshell
Server IP : 69.72.244.102  /  Your IP : 216.73.216.164
Web Server : LiteSpeed
System : Linux s3434.fra1.stableserver.net 4.18.0-513.24.1.lve.2.el8.x86_64 #1 SMP Fri May 24 12:42:50 UTC 2024 x86_64
User : konzalta ( 1271)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/konzalta/constituency.work/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/konzalta/constituency.work//projects.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ConstituencyOS – Projects</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --green:#1a7a4a; --green-light:#e8f5ee; --green-mid:#2d9e63;
  --red:#dc2626; --red-light:#fdecea;
  --amber:#f59e0b; --amber-light:#fffbeb;
  --blue:#2563eb; --blue-light:#eff6ff;
  --purple:#7c3aed; --purple-light:#f5f3ff;
  --gray:#6b7280; --gray-light:#f3f4f6;
  --text:#111827; --muted:#6b7280; --light:#9ca3af;
  --border:#e5e7eb; --bg:#f3f4f6; --white:#ffffff;
  --sidebar-w:216px; --radius:10px; --radius-sm:6px;
  --shadow:0 1px 3px rgba(0,0,0,.08);
}
html,body{height:100%;margin:0;padding:0;}
body{font-family:'Inter',sans-serif;font-size:13px;color:var(--text);background:var(--bg);}

/* SIDEBAR */
.sidebar{position:fixed;top:0;left:0;bottom:0;width:var(--sidebar-w);background:var(--white);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;z-index:40;}
.sidebar-logo{display:flex;align-items:center;gap:9px;padding:14px 14px 12px;border-bottom:1px solid var(--border);flex-shrink:0;}
.logo-icon{width:38px;height:38px;background:linear-gradient(135deg,#b91c1c,#1a7a4a);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0;}
.logo-text strong{display:block;font-size:12.5px;font-weight:700;color:var(--green);}
.logo-text small{font-size:10px;color:var(--muted);line-height:1.3;}
.sidebar-profile{display:flex;align-items:center;gap:9px;padding:11px 14px;border-bottom:1px solid var(--border);flex-shrink:0;}
.avatar{width:36px;height:36px;border-radius:50%;background:#374151;color:white;font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;}
.avatar .dot{position:absolute;bottom:1px;right:1px;width:8px;height:8px;border-radius:50%;background:var(--green-mid);border:2px solid white;}
.profile-name{font-size:11.5px;font-weight:600;}.profile-sub{font-size:10.5px;color:var(--muted);}
.sidebar-nav{flex:1;padding:6px 0;}
.nav-item{display:flex;align-items:center;gap:9px;padding:8px 14px;font-size:12px;font-weight:500;color:var(--muted);cursor:pointer;position:relative;transition:background .12s,color .12s;white-space:nowrap;}
.nav-item:hover{background:var(--bg);color:var(--text);}
.nav-item.active{background:var(--green-light);color:var(--green);font-weight:600;}
.nav-item.active::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);border-radius:0 2px 2px 0;}
.nav-icon{font-size:14px;width:16px;text-align:center;flex-shrink:0;}
.nav-badge{margin-left:auto;background:var(--red);color:white;font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:10px;}
.nav-new{margin-left:auto;background:var(--green);color:white;font-size:9px;font-weight:700;padding:2px 5px;border-radius:4px;}
.nav-chevron{margin-left:auto;font-size:10px;color:var(--light);}
.sidebar-footer{padding:12px 14px;border-top:1px solid var(--border);flex-shrink:0;}
.help-row{display:flex;align-items:center;gap:9px;cursor:pointer;}
.help-label{font-size:11.5px;font-weight:600;}.help-sub{font-size:10.5px;color:var(--muted);}

/* RIGHT PANEL */
.right-panel{margin-left:var(--sidebar-w);display:flex;flex-direction:column;min-height:100vh;}
.topbar{position:sticky;top:0;z-index:30;height:52px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;padding:0 18px;}
.menu-btn{font-size:17px;cursor:pointer;color:var(--muted);}
.const-selector{display:flex;align-items:center;gap:6px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px 10px;cursor:pointer;font-size:12px;font-weight:500;}
.search-top{flex:1;max-width:360px;display:flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 11px;color:var(--muted);font-size:12px;}
.search-top input{border:none;background:transparent;outline:none;width:100%;font-size:12px;font-family:inherit;}
.search-top kbd{margin-left:auto;font-size:9.5px;background:var(--border);padding:1px 5px;border-radius:3px;font-family:inherit;}
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:8px;}
.icon-btn{position:relative;width:32px;height:32px;border-radius:50%;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;}
.icon-btn .bdg{position:absolute;top:-3px;right:-3px;background:var(--red);color:white;font-size:9px;font-weight:700;width:15px;height:15px;border-radius:50%;display:flex;align-items:center;justify-content:center;border:1.5px solid white;}
.icon-btn .bdg.grn{background:var(--green-mid);}
.user-pill{display:flex;align-items:center;gap:7px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:3px 8px;cursor:pointer;font-size:12px;font-weight:500;}

/* CONTENT */
.content{padding:18px 18px 40px;display:flex;flex-direction:column;gap:14px;}

/* UTILS */
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:var(--radius-sm);font-size:12px;font-weight:600;cursor:pointer;border:none;transition:background .15s;}
.btn-primary{background:var(--green);color:white;}.btn-primary:hover{background:var(--green-mid);}
.btn-ghost{background:var(--white);color:var(--text);border:1px solid var(--border);}.btn-ghost:hover{background:var(--bg);}
.page-header{display:flex;align-items:flex-start;justify-content:space-between;}
.page-title{font-size:19px;font-weight:700;}
.page-sub{font-size:12px;color:var(--muted);margin-top:2px;}

/* STAT STRIP */
.stat-strip{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;}
.sstat{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);padding:12px 14px;cursor:pointer;transition:box-shadow .15s;}
.sstat:hover,.sstat.active-filter{box-shadow:0 0 0 2px var(--green-light);border-color:var(--green);}
.sstat-val{font-size:24px;font-weight:700;}
.sstat-lbl{font-size:11px;color:var(--muted);margin-top:2px;}
.sstat-bar{height:3px;border-radius:3px;margin-top:8px;}

/* TOOLBAR */
.toolbar{display:flex;align-items:center;gap:10px;background:var(--white);border:1px solid var(--border);border-radius:var(--radius);padding:10px 14px;}
.search-bar{flex:1;display:flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 10px;}
.search-bar input{border:none;background:transparent;outline:none;width:100%;font-size:12px;font-family:inherit;color:var(--text);}
.fsel{display:flex;align-items:center;gap:5px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 10px;font-size:12px;}
.fsel select{border:none;background:transparent;outline:none;font-size:12px;font-family:inherit;color:var(--text);cursor:pointer;}
.view-toggle{display:flex;gap:2px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:2px;}
.vt{width:28px;height:26px;border-radius:4px;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:13px;color:var(--muted);}
.vt.active{background:var(--white);color:var(--text);box-shadow:var(--shadow);}

/* CARD GRID VIEW */
.card-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;}
.proj-card{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;cursor:pointer;transition:box-shadow .15s;}
.proj-card:hover{box-shadow:0 4px 16px rgba(0,0,0,.1);}
.pc-header{padding:14px 14px 10px;border-bottom:1px solid var(--border);}
.pc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:8px;}
.pc-title{font-size:13px;font-weight:700;line-height:1.3;}
.pc-id{font-size:10px;color:var(--muted);margin-top:2px;}
.pc-body{padding:12px 14px;}
.pc-meta-row{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted);margin-bottom:6px;}
.pc-meta-row strong{color:var(--text);}
.prog-wrap{margin:10px 0 6px;}
.prog-label{display:flex;justify-content:space-between;font-size:10.5px;margin-bottom:4px;}
.prog-label span:last-child{font-weight:700;}
.pbar{height:6px;background:var(--border);border-radius:6px;}
.pbar-fill{height:100%;border-radius:6px;transition:width .4s;}
.pc-footer{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-top:1px solid var(--border);background:var(--bg);}
.pc-budget{font-size:11px;color:var(--muted);}
.pc-budget strong{color:var(--text);}
.milestone-chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px;}
.mc{font-size:9.5px;padding:2px 7px;border-radius:20px;font-weight:600;}
.mc.done{background:#ecfdf5;color:#065f46;}
.mc.pending{background:#eff6ff;color:#1d4ed8;}
.mc.late{background:#fdecea;color:#b91c1c;}

/* TABLE VIEW */
.table-card{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;display:none;}
.table-wrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;}
thead tr{background:var(--bg);border-bottom:1px solid var(--border);}
th{padding:9px 14px;font-size:11px;font-weight:600;color:var(--muted);text-align:left;white-space:nowrap;cursor:pointer;user-select:none;}
th:hover{color:var(--text);}
tbody tr{border-bottom:1px solid var(--border);transition:background .1s;cursor:pointer;}
tbody tr:last-child{border-bottom:none;}
tbody tr:hover{background:#f9fafb;}
td{padding:10px 14px;font-size:12px;vertical-align:middle;}
.stag{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 8px;border-radius:20px;white-space:nowrap;}
.stag.progress{background:#eff6ff;color:#1d4ed8;}
.stag.completed{background:#ecfdf5;color:#065f46;}
.stag.delayed{background:#fdecea;color:#b91c1c;}
.stag.notstarted{background:#f3f4f6;color:#6b7280;}
.pagination{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-top:1px solid var(--border);}
.pg-info{font-size:11.5px;color:var(--muted);}
.pg-btns{display:flex;gap:4px;}
.pg-btn{width:28px;height:28px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--white);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:12px;font-weight:500;}
.pg-btn.active{background:var(--green);color:white;border-color:var(--green);}
.pg-btn:hover:not(.active){background:var(--bg);}

/* DETAIL PANEL */
.detail-overlay{position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:100;display:none;align-items:flex-start;justify-content:flex-end;}
.detail-overlay.open{display:flex;}
.detail-panel{width:460px;height:100%;background:var(--white);box-shadow:-4px 0 24px rgba(0,0,0,.12);display:flex;flex-direction:column;overflow:hidden;}
.dp-header{padding:16px 18px;border-bottom:1px solid var(--border);flex-shrink:0;}
.dp-hdr-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;}
.dp-close{width:28px;height:28px;border-radius:50%;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:14px;}
.dp-title{font-size:15px;font-weight:700;}
.dp-sub{font-size:11.5px;color:var(--muted);margin-top:2px;}
.dp-body{flex:1;overflow-y:auto;padding:18px;display:flex;flex-direction:column;gap:16px;}
.dp-section-title{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;}
.dp-row{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--border);font-size:12px;}
.dp-row:last-child{border-bottom:none;}
.dp-key{color:var(--muted);}
.dp-val{font-weight:500;text-align:right;}
.big-prog{margin:4px 0;}
.big-prog-bar{height:10px;background:var(--border);border-radius:10px;}
.big-prog-fill{height:100%;border-radius:10px;}
.big-prog-label{display:flex;justify-content:space-between;font-size:11px;margin-top:4px;}
.milestone-list{display:flex;flex-direction:column;gap:6px;}
.ml-item{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:var(--radius-sm);border:1px solid var(--border);font-size:11.5px;}
.ml-check{width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;flex-shrink:0;}
.ml-name{flex:1;font-weight:500;}
.ml-date{font-size:10.5px;color:var(--muted);}
.dp-footer{padding:14px 18px;border-top:1px solid var(--border);display:flex;gap:8px;flex-shrink:0;}
.dp-footer .btn{flex:1;justify-content:center;}
.budget-visual{background:var(--bg);border-radius:var(--radius-sm);padding:12px;}
.bv-row{display:flex;justify-content:space-between;font-size:12px;margin-bottom:8px;}
.bv-bar{height:8px;background:var(--border);border-radius:8px;overflow:hidden;}
.bv-fill{height:100%;border-radius:8px;}
.bv-legend{display:flex;gap:12px;margin-top:8px;font-size:10.5px;color:var(--muted);}
.bv-leg-dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:3px;}
</style>
</head>
<body>

<!-- SIDEBAR -->
<aside class="sidebar">
  <div class="sidebar-logo">
    <div class="logo-icon">πŸ›οΈ</div>
    <div class="logo-text"><strong>ConstituencyOS</strong><small>Everything in your constituency,<br>in one place.</small></div>
  </div>
  <div class="sidebar-profile">
    <div class="avatar">DM<div class="dot"></div></div>
    <div><div class="profile-name">Hon. David Mwangi, MP</div><div class="profile-sub">Embakasi South</div></div>
  </div>
  <nav class="sidebar-nav">
    <div class="nav-item" onclick="location.href='index.html'"><span class="nav-icon">🏠</span>Dashboard</div>
    <div class="nav-item" onclick="location.href='constituents.html'"><span class="nav-icon">πŸ‘₯</span>Constituents</div>
    <div class="nav-item" onclick="location.href='complaints.html'"><span class="nav-icon">πŸ“‹</span>Complaints<span class="nav-badge">9</span></div>
    <div class="nav-item" onclick="location.href='projects.html'"><span class="nav-icon">πŸ“</span>Projects</div>
    <div class="nav-item" onclick="location.href='bursaries.html'"><span class="nav-icon">πŸŽ“</span>Bursaries</div>
    <div class="nav-item" onclick="location.href='events.html'"><span class="nav-icon">πŸ“…</span>Events</div>
    <div class="nav-item" onclick="location.href='social_protection.html'"><span class="nav-icon">πŸ›‘οΈ</span>Social Protection</div>
    <div class="nav-item" onclick="location.href='ward_management.html'"><span class="nav-icon">🏘️</span>Ward Management</div>
    <div class="nav-item" onclick="location.href='finance.html'"><span class="nav-icon">πŸ’°</span>Finance</div>
    <div class="nav-item" onclick="location.href='documents.html'"><span class="nav-icon">πŸ“„</span>Documents</div>
    <div class="nav-item" onclick="location.href='staff_management.html'"><span class="nav-icon">πŸ‘€</span>Staff Management</div>
    <div class="nav-item" onclick="location.href='reports_analytics.html'"><span class="nav-icon">πŸ“Š</span>Reports & Analytics</div>
    <div class="nav-item active"><span class="nav-icon">πŸ€–</span>AI Assistant<span class="nav-new">New</span></div>
    <div class="nav-item" onclick="location.href='settings.html'"><span class="nav-icon">βš™οΈ</span>Settings</div>
    <div class="nav-item" onclick="location.href='public_portal.html'"><span class="nav-icon">🌐</span>Public Portal</div>
  </nav>
  <div class="sidebar-footer">
    <div class="help-row"><span>❓</span><div><div class="help-label">Need Help?</div><div class="help-sub">Contact Support</div></div></div>
  </div>
</aside>

<!-- RIGHT PANEL -->
<div class="right-panel">
  <header class="topbar">
    <span class="menu-btn">☰</span>
    <div class="const-selector"><span style="font-size:13px">πŸ›οΈ</span>Embakasi South Constituency<span style="font-size:10px;color:var(--muted)">β–Ό</span></div>
    <div class="search-top"><span>πŸ”</span><input type="text" placeholder="Search for anything…"><kbd>⌘K</kbd></div>
    <div class="topbar-right">
      <div class="icon-btn">πŸ””<div class="bdg">8</div></div>
      <div class="icon-btn">βœ‰οΈ<div class="bdg grn">3</div></div>
      <div class="user-pill"><div class="avatar" style="width:26px;height:26px;font-size:10px">DM</div>Hon. David Mwangi<span style="font-size:10px;color:var(--muted)">β–Ό</span></div>
    </div>
  </header>

  <main class="content">

    <div class="page-header">
      <div>
        <div class="page-title">Projects</div>
        <div class="page-sub">Track all constituency development projects and budgets across wards</div>
      </div>
      <div style="display:flex;gap:8px;">
        <button class="btn btn-ghost">⬇ Export</button>
        <button class="btn btn-primary">οΌ‹ New Project</button>
      </div>
    </div>

    <!-- Stat Strip -->
    <div class="stat-strip">
      <div class="sstat active-filter" id="stat-all" onclick="filterStatus('all',this)">
        <div class="sstat-val" id="cnt-all">47</div>
        <div class="sstat-lbl">Total Projects</div>
        <div class="sstat-bar" style="background:var(--border)"></div>
      </div>
      <div class="sstat" id="stat-ip" onclick="filterStatus('In Progress',this)">
        <div class="sstat-val" style="color:var(--blue)" id="cnt-ip">26</div>
        <div class="sstat-lbl">In Progress</div>
        <div class="sstat-bar" style="background:var(--blue);opacity:.3"></div>
      </div>
      <div class="sstat" id="stat-done" onclick="filterStatus('Completed',this)">
        <div class="sstat-val" style="color:var(--green)" id="cnt-done">12</div>
        <div class="sstat-lbl">Completed</div>
        <div class="sstat-bar" style="background:var(--green);opacity:.3"></div>
      </div>
      <div class="sstat" id="stat-del" onclick="filterStatus('Delayed',this)">
        <div class="sstat-val" style="color:var(--red)" id="cnt-del">5</div>
        <div class="sstat-lbl">Delayed</div>
        <div class="sstat-bar" style="background:var(--red);opacity:.3"></div>
      </div>
      <div class="sstat" id="stat-ns" onclick="filterStatus('Not Started',this)">
        <div class="sstat-val" style="color:var(--muted)" id="cnt-ns">4</div>
        <div class="sstat-lbl">Not Started</div>
        <div class="sstat-bar" style="background:var(--light);opacity:.4"></div>
      </div>
    </div>

    <!-- Toolbar -->
    <div class="toolbar">
      <div class="search-bar"><span>πŸ”</span><input type="text" id="searchInput" placeholder="Search projects…" oninput="applyFilters()"></div>
      <div class="fsel">🏘️ <select id="wardFilter" onchange="applyFilters()">
        <option value="">All Wards</option>
        <option>Pipeline Ward</option><option>Imara Daima</option><option>Mabatini Ward</option>
        <option>Umoja Ward</option><option>Kwa Njenga Ward</option><option>Mihango Ward</option>
      </select></div>
      <div class="fsel">πŸ“‚ <select id="catFilter" onchange="applyFilters()">
        <option value="">All Sectors</option>
        <option>Water</option><option>Roads</option><option>Health</option>
        <option>Education</option><option>Sanitation</option><option>Energy</option>
      </select></div>
      <div class="fsel">πŸ“… <select id="yearFilter" onchange="applyFilters()">
        <option value="">All Years</option><option>2024</option><option>2023</option><option>2022</option>
      </select></div>
      <div class="view-toggle">
        <div class="vt active" id="vt-cards" onclick="setView('cards')" title="Cards">⊞</div>
        <div class="vt" id="vt-table" onclick="setView('table')" title="Table">☰</div>
      </div>
    </div>

    <!-- Card Grid -->
    <div class="card-grid" id="cardGrid"></div>

    <!-- Table View -->
    <div class="table-card" id="tableView">
      <div class="table-wrap">
        <table>
          <thead><tr>
            <th>ID</th><th>Project</th><th>Ward</th><th>Sector</th>
            <th>Status</th><th>Progress</th><th>Budget (KSh)</th><th>Deadline</th><th>Lead</th>
          </tr></thead>
          <tbody id="tableBody"></tbody>
        </table>
      </div>
      <div class="pagination">
        <div class="pg-info" id="pgInfo"></div>
        <div class="pg-btns" id="pgBtns"></div>
      </div>
    </div>

  </main>
</div>

<!-- DETAIL OVERLAY -->
<div class="detail-overlay" id="detailOverlay" onclick="closeDetail(event)">
  <div class="detail-panel" id="detailPanel">
    <div class="dp-header">
      <div class="dp-hdr-top">
        <div style="font-size:10.5px;color:var(--muted)" id="dp-id"></div>
        <div class="dp-close" onclick="closeDetailDirect()">βœ•</div>
      </div>
      <div class="dp-title" id="dp-title"></div>
      <div class="dp-sub" id="dp-sub"></div>
    </div>
    <div class="dp-body">

      <div>
        <div class="dp-section-title">Overall Progress</div>
        <div class="big-prog">
          <div class="big-prog-bar"><div class="big-prog-fill" id="dp-progbar"></div></div>
          <div class="big-prog-label"><span id="dp-prog-lbl"></span><span id="dp-prog-pct" style="font-weight:700"></span></div>
        </div>
      </div>

      <div>
        <div class="dp-section-title">Project Details</div>
        <div class="dp-row"><span class="dp-key">Ward</span><span class="dp-val" id="dp-ward"></span></div>
        <div class="dp-row"><span class="dp-key">Sector</span><span class="dp-val" id="dp-cat"></span></div>
        <div class="dp-row"><span class="dp-key">Status</span><span class="dp-val" id="dp-status"></span></div>
        <div class="dp-row"><span class="dp-key">Project Lead</span><span class="dp-val" id="dp-lead"></span></div>
        <div class="dp-row"><span class="dp-key">Contractor</span><span class="dp-val" id="dp-contractor"></span></div>
        <div class="dp-row"><span class="dp-key">Start Date</span><span class="dp-val" id="dp-start"></span></div>
        <div class="dp-row"><span class="dp-key">Deadline</span><span class="dp-val" id="dp-deadline"></span></div>
      </div>

      <div>
        <div class="dp-section-title">Budget</div>
        <div class="budget-visual">
          <div class="bv-row"><span>Total Budget</span><strong id="dp-budget"></strong></div>
          <div class="bv-row"><span>Spent</span><strong id="dp-spent"></strong></div>
          <div class="bv-bar"><div class="bv-fill" id="dp-bv-fill" style="background:var(--green)"></div></div>
          <div class="bv-legend">
            <span><span class="bv-leg-dot" style="background:var(--green)"></span>Spent</span>
            <span><span class="bv-leg-dot" style="background:var(--border)"></span>Remaining</span>
          </div>
        </div>
      </div>

      <div>
        <div class="dp-section-title">Milestones</div>
        <div class="milestone-list" id="dp-milestones"></div>
      </div>

      <div>
        <div class="dp-section-title">Description</div>
        <div style="font-size:12px;line-height:1.6;color:var(--text);background:var(--bg);border-radius:var(--radius-sm);padding:10px 12px;" id="dp-desc"></div>
      </div>

    </div>
    <div class="dp-footer">
      <button class="btn btn-ghost" onclick="closeDetailDirect()">Close</button>
      <button class="btn btn-primary" onclick="updateProgress()">πŸ“ Update Progress</button>
    </div>
  </div>
</div>

<script>
const statusColor = {
  'In Progress': '#2563eb', 'Completed': '#16a34a',
  'Delayed': '#dc2626', 'Not Started': '#9ca3af'
};
const sectorIcon = {
  Water:'πŸ’§', Roads:'πŸ›£οΈ', Health:'πŸ₯', Education:'🏫', Sanitation:'πŸ—‘οΈ', Energy:'⚑'
};

const PROJECTS = [
  {id:'PRJ-001',title:'Kwa Njenga Water Pipeline',ward:'Kwa Njenga Ward',category:'Water',status:'In Progress',progress:68,budget:12500000,spent:8500000,start:'Jan 2024',deadline:'Aug 2024',lead:'Eng. Kamau',contractor:'Aqua Works Ltd',desc:'Installation of a 4.2km water pipeline to serve over 3,000 households in Kwa Njenga with clean piped water. Includes 3 water kiosks and 2 storage tanks.',milestones:[{name:'Site survey complete',done:true,date:'Feb 2024'},{name:'Pipe trenching – Phase 1',done:true,date:'Mar 2024'},{name:'Pipe installation – Phase 1',done:true,date:'Apr 2024'},{name:'Pipe installation – Phase 2',done:false,date:'Jun 2024'},{name:'Storage tanks construction',done:false,date:'Jul 2024'},{name:'Commissioning & handover',done:false,date:'Aug 2024'}]},
  {id:'PRJ-002',title:'Imara Daima Dispensary Construction',ward:'Imara Daima',category:'Health',status:'In Progress',progress:75,budget:8200000,spent:6150000,start:'Nov 2023',deadline:'Jun 2024',lead:'Dr. Achieng',contractor:'BuildRight Contractors',desc:'Construction of a new dispensary to serve the Imara Daima ward population of 45,000. Includes maternity wing, outpatient department, and pharmacy.',milestones:[{name:'Foundation & slab',done:true,date:'Dec 2023'},{name:'Structural walls',done:true,date:'Jan 2024'},{name:'Roofing',done:true,date:'Feb 2024'},{name:'Interior finishes',done:true,date:'Apr 2024'},{name:'Medical equipment installation',done:false,date:'May 2024'},{name:'Commissioning',done:false,date:'Jun 2024'}]},
  {id:'PRJ-003',title:'Pipeline Ward Road Rehabilitation',ward:'Pipeline Ward',category:'Roads',status:'Delayed',progress:30,budget:18000000,spent:5400000,start:'Oct 2023',deadline:'Mar 2024',lead:'Eng. Mwangi',contractor:'Tarmac East Africa',desc:'Rehabilitation of 6.5km of roads in Pipeline Ward including tarmacking, drainage channels, and installation of street lighting along the main road.',milestones:[{name:'Ground clearing',done:true,date:'Nov 2023'},{name:'Sub-base laying',done:true,date:'Dec 2023'},{name:'Tarmacking – Phase 1',done:false,date:'Feb 2024'},{name:'Drainage channels',done:false,date:'Mar 2024'},{name:'Street lights installation',done:false,date:'Mar 2024'}]},
  {id:'PRJ-004',title:'Umoja Ward Market Renovation',ward:'Umoja Ward',category:'Roads',status:'Completed',progress:100,budget:5500000,spent:5300000,start:'Aug 2023',deadline:'Dec 2023',lead:'Wambui Karanja',contractor:'Local Works Kenya',desc:'Complete renovation of Umoja Market including new stalls, ablution block, waste management area, drainage system, and solar-powered lighting.',milestones:[{name:'Demolition & clearing',done:true,date:'Aug 2023'},{name:'New stall construction',done:true,date:'Oct 2023'},{name:'Ablution block',done:true,date:'Nov 2023'},{name:'Solar lighting',done:true,date:'Nov 2023'},{name:'Handover ceremony',done:true,date:'Dec 2023'}]},
  {id:'PRJ-005',title:'Mihango Primary School Classrooms',ward:'Mihango Ward',category:'Education',status:'In Progress',progress:55,budget:6800000,spent:3740000,start:'Feb 2024',deadline:'Jul 2024',lead:'Headmaster Oduya',contractor:'EduBuild Ltd',desc:'Construction of 6 additional classrooms, a library, and a computer lab to address the severe shortage of learning space at Mihango Primary School.',milestones:[{name:'Foundation complete',done:true,date:'Mar 2024'},{name:'Block work – 3 rooms',done:true,date:'Apr 2024'},{name:'Block work – 3 rooms',done:false,date:'May 2024'},{name:'Roofing',done:false,date:'Jun 2024'},{name:'Interior & furnishing',done:false,date:'Jul 2024'}]},
  {id:'PRJ-006',title:'Mabatini Solar Street Lights',ward:'Mabatini Ward',category:'Energy',status:'Completed',progress:100,budget:3200000,spent:3150000,start:'Sep 2023',deadline:'Nov 2023',lead:'Eng. Kamau',contractor:'SolarTech EA',desc:'Installation of 120 solar-powered street lights along the main roads of Mabatini Ward, improving security and enabling evening economic activities.',milestones:[{name:'Pole installation',done:true,date:'Sep 2023'},{name:'Solar panel mounting',done:true,date:'Oct 2023'},{name:'Electrical wiring',done:true,date:'Oct 2023'},{name:'Testing & commissioning',done:true,date:'Nov 2023'}]},
  {id:'PRJ-007',title:'Kwa Njenga Drainage System',ward:'Kwa Njenga Ward',category:'Sanitation',status:'Not Started',progress:0,budget:9500000,spent:0,start:'Jun 2024',deadline:'Dec 2024',lead:'Unassigned',contractor:'TBD',desc:'Construction of a comprehensive storm drainage system to address chronic flooding in Kwa Njenga. Includes 3.8km of covered drains and 2 retention ponds.',milestones:[{name:'Environmental impact assessment',done:false,date:'Jun 2024'},{name:'Design & approval',done:false,date:'Jul 2024'},{name:'Phase 1 excavation',done:false,date:'Aug 2024'},{name:'Phase 2 excavation',done:false,date:'Oct 2024'},{name:'Commissioning',done:false,date:'Dec 2024'}]},
  {id:'PRJ-008',title:'Imara Daima Footbridge Repair',ward:'Imara Daima',category:'Roads',status:'Delayed',progress:10,budget:2100000,spent:210000,start:'Mar 2024',deadline:'Apr 2024',lead:'Eng. Mwangi',contractor:'FastFix Contractors',desc:'Emergency repair of the Kwa Reuben footbridge which partially collapsed in March 2024. Critical access route for 2,000 daily commuters and school children.',milestones:[{name:'Structural assessment',done:true,date:'Mar 2024'},{name:'Materials procurement',done:false,date:'Apr 2024'},{name:'Decking replacement',done:false,date:'Apr 2024'},{name:'Load testing',done:false,date:'Apr 2024'}]},
  {id:'PRJ-009',title:'Pipeline Borehole Drilling',ward:'Pipeline Ward',category:'Water',status:'In Progress',progress:45,budget:4400000,spent:1980000,start:'Mar 2024',deadline:'Jun 2024',lead:'Eng. Kamau',contractor:'Aqua Works Ltd',desc:'Drilling and equipping of two new boreholes in Pipeline Ward to supplement existing water supply and reduce dependence on the aging distribution network.',milestones:[{name:'Site selection & survey',done:true,date:'Mar 2024'},{name:'Drilling – Borehole 1',done:true,date:'Apr 2024'},{name:'Drilling – Borehole 2',done:false,date:'May 2024'},{name:'Pump installation',done:false,date:'May 2024'},{name:'Commissioning',done:false,date:'Jun 2024'}]},
  {id:'PRJ-010',title:'Mabatini Health Centre Upgrade',ward:'Mabatini Ward',category:'Health',status:'Not Started',progress:0,budget:7800000,spent:0,start:'Jul 2024',deadline:'Feb 2025',lead:'Dr. Wanjiku',contractor:'TBD',desc:'Upgrade of Mabatini Health Centre to a Level 3 facility including expansion of maternity ward, addition of X-ray room, laboratory upgrade, and staff quarters.',milestones:[{name:'Needs assessment',done:false,date:'Jul 2024'},{name:'Architectural drawings',done:false,date:'Aug 2024'},{name:'Construction begins',done:false,date:'Sep 2024'},{name:'Completion',done:false,date:'Feb 2025'}]},
  {id:'PRJ-011',title:'Umoja Youth Sports Complex',ward:'Umoja Ward',category:'Education',status:'In Progress',progress:40,budget:11000000,spent:4400000,start:'Jan 2024',deadline:'Oct 2024',lead:'Coach Karuri',contractor:'SportsBuild Kenya',desc:'Construction of a multi-purpose sports complex featuring a football pitch, basketball court, athletics track, and changing rooms for youth in Umoja Ward.',milestones:[{name:'Land leveling',done:true,date:'Jan 2024'},{name:'Perimeter wall',done:true,date:'Feb 2024'},{name:'Football pitch grading',done:false,date:'Apr 2024'},{name:'Court construction',done:false,date:'Jun 2024'},{name:'Facilities & lighting',done:false,date:'Sep 2024'}]},
  {id:'PRJ-012',title:'Mihango Road Storm Drains',ward:'Mihango Ward',category:'Sanitation',status:'Completed',progress:100,budget:3800000,spent:3650000,start:'Jun 2023',deadline:'Oct 2023',lead:'Eng. Mwangi',contractor:'Tarmac East Africa',desc:'Construction of storm water drainage channels along Mihango Road to prevent flooding during rainy seasons and protect road infrastructure.',milestones:[{name:'Excavation',done:true,date:'Jul 2023'},{name:'Culvert installation',done:true,date:'Aug 2023'},{name:'Concrete lining',done:true,date:'Sep 2023'},{name:'Backfill & surfacing',done:true,date:'Oct 2023'}]},
];

let filtered = [...PROJECTS];
let activeStatus = 'all';
let currentView = 'cards';
let currentProject = null;
let currentPage = 1;
const PAGE_SIZE = 8;

function statusTag(s){
  const cls = s.replace(' ','').toLowerCase();
  const icons = {'In Progress':'β—‘','Completed':'βœ“','Delayed':'⚠','Not Started':'β—‹'};
  return `<span class="stag ${cls}">${icons[s]||'●'} ${s}</span>`;
}

function formatKsh(n){ return 'KSh '+n.toLocaleString(); }

function cardColor(s){
  return statusColor[s]||'#9ca3af';
}

function applyFilters(){
  const q = document.getElementById('searchInput').value.toLowerCase();
  const ward = document.getElementById('wardFilter').value;
  const cat = document.getElementById('catFilter').value;
  const year = document.getElementById('yearFilter').value;
  filtered = PROJECTS.filter(p=>{
    if(activeStatus!=='all' && p.status!==activeStatus) return false;
    if(ward && p.ward!==ward) return false;
    if(cat && p.category!==cat) return false;
    if(year && !p.start.includes(year) && !p.deadline.includes(year)) return false;
    if(q && !`${p.id} ${p.title} ${p.ward} ${p.lead} ${p.contractor}`.toLowerCase().includes(q)) return false;
    return true;
  });
  currentPage = 1;
  render();
}

function filterStatus(status, el){
  activeStatus = status;
  document.querySelectorAll('.sstat').forEach(s=>s.classList.remove('active-filter'));
  el.classList.add('active-filter');
  applyFilters();
}

function setView(v){
  currentView = v;
  document.getElementById('vt-cards').classList.toggle('active', v==='cards');
  document.getElementById('vt-table').classList.toggle('active', v==='table');
  document.getElementById('cardGrid').style.display = v==='cards'?'grid':'none';
  document.getElementById('tableView').style.display = v==='table'?'block':'none';
  render();
}

function render(){
  if(currentView==='cards') renderCards();
  else renderTable();
}

function renderCards(){
  const grid = document.getElementById('cardGrid');
  grid.innerHTML = filtered.map(p=>{
    const color = cardColor(p.status);
    const budgetPct = Math.round(p.spent/p.budget*100);
    const done = p.milestones.filter(m=>m.done).length;
    return `
    <div class="proj-card" onclick="openDetail('${p.id}')">
      <div class="pc-header">
        <div class="pc-top">
          <div>
            <div class="pc-title">${p.title}</div>
            <div class="pc-id">${p.id} Β· ${p.ward}</div>
          </div>
          <div style="font-size:20px">${sectorIcon[p.category]||'πŸ“'}</div>
        </div>
        ${statusTag(p.status)}
      </div>
      <div class="pc-body">
        <div class="pc-meta-row">πŸ‘€ <strong>${p.lead}</strong></div>
        <div class="pc-meta-row">πŸ“… Deadline: <strong>${p.deadline}</strong></div>
        <div class="prog-wrap">
          <div class="prog-label"><span>Progress</span><span style="color:${color}">${p.progress}%</span></div>
          <div class="pbar"><div class="pbar-fill" style="width:${p.progress}%;background:${color}"></div></div>
        </div>
        <div class="milestone-chips">
          ${p.milestones.slice(0,4).map(m=>`<span class="mc ${m.done?'done':'pending'}">${m.done?'βœ“':'β—‹'} ${m.name}</span>`).join('')}
          ${p.milestones.length>4?`<span class="mc pending">+${p.milestones.length-4} more</span>`:''}
        </div>
      </div>
      <div class="pc-footer">
        <div class="pc-budget">Budget: <strong>${formatKsh(p.budget)}</strong></div>
        <div class="pc-budget">${done}/${p.milestones.length} milestones</div>
      </div>
    </div>`;
  }).join('');
}

function renderTable(){
  const start=(currentPage-1)*PAGE_SIZE, end=start+PAGE_SIZE;
  const page=filtered.slice(start,end);
  document.getElementById('tableBody').innerHTML = page.map(p=>`
    <tr onclick="openDetail('${p.id}')">
      <td style="font-size:11px;color:var(--muted);font-weight:600">${p.id}</td>
      <td><div style="font-weight:600;font-size:12.5px">${p.title}</div><div style="font-size:10.5px;color:var(--muted)">${p.contractor}</div></td>
      <td style="font-size:11.5px">${p.ward}</td>
      <td>${sectorIcon[p.category]} ${p.category}</td>
      <td>${statusTag(p.status)}</td>
      <td>
        <div style="display:flex;align-items:center;gap:8px">
          <div style="flex:1;height:5px;background:var(--border);border-radius:5px;min-width:60px">
            <div style="height:100%;border-radius:5px;background:${cardColor(p.status)};width:${p.progress}%"></div>
          </div>
          <span style="font-size:11px;font-weight:600;color:${cardColor(p.status)}">${p.progress}%</span>
        </div>
      </td>
      <td style="font-size:11.5px">${formatKsh(p.budget)}</td>
      <td style="font-size:11px;color:var(--muted)">${p.deadline}</td>
      <td style="font-size:11.5px">${p.lead}</td>
    </tr>
  `).join('');
  const total=filtered.length, pages=Math.ceil(total/PAGE_SIZE);
  document.getElementById('pgInfo').textContent=`Showing ${Math.min(start+1,total)}–${Math.min(end,total)} of ${total}`;
  const pb=document.getElementById('pgBtns'); pb.innerHTML='';
  const addBtn=(label,p,active)=>{const d=document.createElement('div');d.className='pg-btn'+(active?' active':'');d.textContent=label;d.onclick=()=>{currentPage=p;render();};pb.appendChild(d);};
  if(currentPage>1) addBtn('β€Ή',currentPage-1,false);
  for(let i=1;i<=pages;i++) addBtn(i,i,i===currentPage);
  if(currentPage<pages) addBtn('β€Ί',currentPage+1,false);
}

function openDetail(id){
  currentProject = PROJECTS.find(p=>p.id===id);
  const p = currentProject;
  const color = cardColor(p.status);
  document.getElementById('dp-id').textContent = `${p.id} Β· ${p.category}`;
  document.getElementById('dp-title').textContent = p.title;
  document.getElementById('dp-sub').innerHTML = statusTag(p.status);
  document.getElementById('dp-ward').textContent = p.ward;
  document.getElementById('dp-cat').textContent = p.category;
  document.getElementById('dp-status').innerHTML = statusTag(p.status);
  document.getElementById('dp-lead').textContent = p.lead;
  document.getElementById('dp-contractor').textContent = p.contractor;
  document.getElementById('dp-start').textContent = p.start;
  document.getElementById('dp-deadline').textContent = p.deadline;
  document.getElementById('dp-budget').textContent = formatKsh(p.budget);
  document.getElementById('dp-spent').textContent = formatKsh(p.spent);
  const budgetPct = Math.round(p.spent/p.budget*100);
  document.getElementById('dp-bv-fill').style.width = budgetPct+'%';
  document.getElementById('dp-progbar').style.cssText = `width:${p.progress}%;background:${color}`;
  document.getElementById('dp-prog-lbl').textContent = `${p.milestones.filter(m=>m.done).length} of ${p.milestones.length} milestones complete`;
  document.getElementById('dp-prog-pct').textContent = p.progress+'%';
  document.getElementById('dp-prog-pct').style.color = color;
  document.getElementById('dp-desc').textContent = p.desc;
  document.getElementById('dp-milestones').innerHTML = p.milestones.map(m=>`
    <div class="ml-item" style="background:${m.done?'#f0fdf4':'var(--white)'}">
      <div class="ml-check" style="background:${m.done?'#dcfce7':'var(--bg)'};color:${m.done?'#16a34a':'var(--muted)'}">${m.done?'βœ“':'β—‹'}</div>
      <div class="ml-name" style="color:${m.done?'var(--text)':'var(--muted)'};text-decoration:${m.done?'none':'none'}">${m.name}</div>
      <div class="ml-date">${m.date}</div>
    </div>
  `).join('');
  document.getElementById('detailOverlay').classList.add('open');
}

function closeDetail(e){ if(e.target===document.getElementById('detailOverlay')) closeDetailDirect(); }
function closeDetailDirect(){ document.getElementById('detailOverlay').classList.remove('open'); }

function updateProgress(){
  if(!currentProject) return;
  const newPct = prompt(`Current progress: ${currentProject.progress}%\nEnter new progress (0–100):`);
  if(newPct===null) return;
  const val = Math.min(100,Math.max(0,parseInt(newPct)||0));
  currentProject.progress = val;
  if(val===100) currentProject.status='Completed';
  render();
  openDetail(currentProject.id);
}

// init
render();
</script>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit