diff --git a/core/tpl/frontend/reedcrm_opportunity_chain_matrix.tpl.php b/core/tpl/frontend/reedcrm_opportunity_chain_matrix.tpl.php
new file mode 100644
index 00000000..75f6e7fa
--- /dev/null
+++ b/core/tpl/frontend/reedcrm_opportunity_chain_matrix.tpl.php
@@ -0,0 +1,116 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file core/tpl/frontend/reedcrm_opportunity_chain_matrix.tpl.php
+ * \ingroup reedcrm
+ * \brief Reusable fragment: opportunity->payment chain as a matrix (pieces = rows, projects = columns).
+ * Expects $matrixProjects (array of project objects: id, ref, title)
+ * and $matrixDocs (= reedcrm_get_pwa_projects_documents($ids, true)).
+ * Uses globals $conf/$langs; chain logic in reedcrm_compute_opportunity_chain().
+ */
+if (!defined('DOL_DOCUMENT_ROOT')) {
+ exit;
+}
+
+$enabledPieces = [];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_OPP_AMOUNT)) $enabledPieces['montant'] = ['icon' => 'fas fa-wallet'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_PROPAL)) $enabledPieces['propal'] = ['icon' => 'fas fa-file-signature'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_COMMANDE)) $enabledPieces['commande'] = ['icon' => 'fas fa-shopping-cart'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_COMMANDE_FOURN)) $enabledPieces['commande_fourn'] = ['icon' => 'fas fa-shopping-bag'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_RECEPTION)) $enabledPieces['reception'] = ['icon' => 'fas fa-dolly'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_FACTURE_FOURN)) $enabledPieces['facture_fourn'] = ['icon' => 'fas fa-receipt'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_EXPEDITION)) $enabledPieces['expedition'] = ['icon' => 'fas fa-shipping-fast'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_FACTURE)) $enabledPieces['facture'] = ['icon' => 'fas fa-file-invoice-dollar'];
+if (!empty($conf->global->REEDCRM_PWA_SHOW_PAYMENT)) $enabledPieces['payment'] = ['icon' => 'fas fa-coins'];
+
+$matrixProjects = (isset($matrixProjects) && is_array($matrixProjects)) ? $matrixProjects : [];
+$matrixDocs = (isset($matrixDocs) && is_array($matrixDocs)) ? $matrixDocs : [];
+$iconsOnly = !empty($conf->global->REEDCRM_PWA_PIECES_ICONS_ONLY);
+
+// Pre-compute the chain (state + issues) once per project.
+$matrixChains = [];
+foreach ($matrixProjects as $proj) {
+ $matrixChains[$proj->id] = reedcrm_compute_opportunity_chain($matrixDocs[$proj->id] ?? []);
+}
+
+// Cancelled/refused statuses, per piece, to strike out the offending document.
+$matrixBadStatuses = ['propal' => [3], 'commande' => [-1], 'facture' => [3]];
+
+if (!empty($enabledPieces) && !empty($matrixProjects)) : ?>
+
';
$pwaHeaderCenterHtml .= $searchHtml;
$pwaHeaderCenterHtml .= $paginationHtml;
+$pwaHeaderCenterHtml .= $toggleHtml;
$pwaHeaderCenterHtml .= '
';
+print reedcrm_chain_matrix_styles();
+
require_once __DIR__ . '/../../core/tpl/frontend/reedcrm_pwa_header.tpl.php';
print '';
diff --git a/view/frontend/pwa_projets_overview.php b/view/frontend/pwa_projets_overview.php
new file mode 100644
index 00000000..f284ae9d
--- /dev/null
+++ b/view/frontend/pwa_projets_overview.php
@@ -0,0 +1,126 @@
+payment chain across projects.
+ */
+
+if (file_exists('../reedcrm.main.inc.php')) {
+ require_once __DIR__ . '/../reedcrm.main.inc.php';
+} elseif (file_exists('../../reedcrm.main.inc.php')) {
+ require_once __DIR__ . '/../../reedcrm.main.inc.php';
+} else {
+ die('Include of reedcrm main fails');
+}
+
+global $conf, $db, $hookmanager, $langs, $user;
+
+require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
+require_once DOL_DOCUMENT_ROOT . '/custom/reedcrm/lib/reedcrm.lib.php';
+
+saturne_load_langs(['projects', 'users', 'companies', 'main']);
+
+$title = $langs->trans('ProjectsOverviewMatrix');
+$help_url = 'FR:Module_ReedCRM';
+$moreJS = [
+ '/custom/saturne/js/saturne.min.js',
+ '/custom/reedcrm/js/reedcrm.min.js'
+];
+$moreCSS = ['/custom/saturne/css/saturne.min.css', '/custom/reedcrm/css/reedcrm.min.css'];
+
+$conf->dol_hide_topmenu = 1;
+$conf->dol_hide_leftmenu = 1;
+$conf->global->MAIN_FAVICON_URL = DOL_URL_ROOT . '/custom/reedcrm/img/reedcrm_color_512.png';
+
+llxHeader('', $title, $help_url, '', 0, 0, $moreJS, $moreCSS, '', 'template-pwa pwa-projets-overview');
+
+if (!$user->rights->projet->lire) {
+ accessforbidden($langs->trans('NotEnoughPermissions'), 0);
+ exit;
+}
+
+// 1. Search & pagination params (same contract as pwa_projets.php).
+$searchStr = trim(GETPOST('s', 'alpha'));
+$page = GETPOST('page', 'int');
+if (empty($page)) $page = 0;
+
+$limit = getDolGlobalInt('REEDCRM_NB_LATEST_OPPORTUNITIES_FRONTEND', 15);
+if ($limit <= 0) $limit = 15;
+$offset = $limit * $page;
+
+// 2. Filters (same as pwa_projets.php).
+$filter = [];
+if (!empty($searchStr)) {
+ $searchEscaped = $db->escape($searchStr);
+ $customSql = "(t.ref LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR t.title LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR t.description LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR eft.reedcrm_firstname LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR eft.reedcrm_lastname LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR eft.projectphone LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= " OR eft.reedcrm_email LIKE '%" . $searchEscaped . "%' ";
+ $customSql .= ")";
+ $filter['customsql'] = $customSql;
+}
+
+// 3. Fetch total + current page.
+$moreparamsCount = ['count' => true];
+$totalProjects = saturne_fetch_all_object_type('Project', 'DESC', 't.datec', 0, 0, $filter, 'AND', true, true, false, '', $moreparamsCount);
+if (!is_numeric($totalProjects) || $totalProjects < 0) $totalProjects = 0;
+
+$matrixProjects = saturne_fetch_all_object_type('Project', 'DESC', 't.datec', $limit, $offset, $filter, 'AND', true, true, false, '', [], ', t.description', ['description']);
+if (empty($matrixProjects) || !is_array($matrixProjects)) {
+ $matrixProjects = [];
+}
+$nbResults = count($matrixProjects);
+
+$pwaProjectIds = [];
+foreach ($matrixProjects as $proj) {
+ $pwaProjectIds[] = $proj->id;
+}
+$matrixDocs = reedcrm_get_pwa_projects_documents($pwaProjectIds, true);
+
+// --- SEARCH BAR + VIEW TOGGLE for the header ---
+$selfList = dol_buildpath('/custom/reedcrm/view/frontend/pwa_projets.php', 1);
+$qs = (!empty($searchStr) ? '&s=' . urlencode($searchStr) : '') . ($page > 0 ? '&page=' . (int) $page : '');
+$toggleHtml = '
' . $langs->trans('ViewAsList') . '';
+
+$searchHtml = '
+
';
+
+$pwaHeaderCenterHtml = '
';
+$pwaHeaderCenterHtml .= $searchHtml;
+$pwaHeaderCenterHtml .= $toggleHtml;
+$pwaHeaderCenterHtml .= '
';
+
+print reedcrm_chain_matrix_styles();
+
+require_once __DIR__ . '/../../core/tpl/frontend/reedcrm_pwa_header.tpl.php';
+
+print '
';
+
+if (!empty($matrixProjects)) {
+ require __DIR__ . '/../../core/tpl/frontend/reedcrm_opportunity_chain_matrix.tpl.php';
+} else {
+ print '
';
+ print '
';
+ print '
' . $langs->trans('NoRecordFound') . '
';
+ print '
';
+}
+
+print '
';
+
+// Include the Bottom Navigation Bar for App
+require_once __DIR__ . '/../../core/tpl/frontend/reedcrm_pwa_bottom_nav.tpl.php';
+
+llxFooter();
+$db->close();