diff --git a/app/templates/activity.html b/app/templates/activity.html
index dbb7db7..09337b9 100644
--- a/app/templates/activity.html
+++ b/app/templates/activity.html
@@ -20,6 +20,7 @@
📰 Activité
📊 Briefing
🔍 Recherche
+ 🖥️ Wallboard
diff --git a/app/templates/briefing.html b/app/templates/briefing.html
index 5e2e6b5..f290eb3 100644
--- a/app/templates/briefing.html
+++ b/app/templates/briefing.html
@@ -20,6 +20,7 @@
👤 Mes issues
📰 Activité
🔍 Recherche
+ 🖥️ Wallboard
diff --git a/app/templates/focus.html b/app/templates/focus.html
index 481c503..8a60743 100644
--- a/app/templates/focus.html
+++ b/app/templates/focus.html
@@ -20,6 +20,7 @@
📰 Activité
📊 Briefing
🔍 Recherche
+ 🖥️ Wallboard
{{ groups|map(attribute='cards')|map('length')|sum }} cartes en cours
diff --git a/app/templates/my.html b/app/templates/my.html
index 460ad5d..32697a5 100644
--- a/app/templates/my.html
+++ b/app/templates/my.html
@@ -19,6 +19,7 @@
👤 Mes issues
📰 Activité
🔍 Recherche
+ 🖥️ Wallboard
diff --git a/app/templates/search.html b/app/templates/search.html
index ae08b1a..36f6208 100644
--- a/app/templates/search.html
+++ b/app/templates/search.html
@@ -19,6 +19,7 @@
👤 Mes issues
📰 Activité
🔍 Recherche
+ 🖥️ Wallboard
diff --git a/app/templates/wall.html b/app/templates/wall.html
new file mode 100644
index 0000000..57ce551
--- /dev/null
+++ b/app/templates/wall.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+Kanbante — Wallboard
+
+
+
+{% if slides %}
+
+ {% for slide in slides %}
+
+
+
+
+ {% for col in columns %}
+
+ {{ slide.counts[col] }}
+ {{ column_labels[col] }}
+
+ {% endfor %}
+
+
+ {% if slide.cards %}
+
+ {% for card in slide.cards %}
+ -
+ {{ card.column_label }}
+ #{{ card.number }} · {{ card.title }}
+ {% if card.age_days is not none and card.age_days >= 1 %}
+ ⏳ {{ card.age_days }} j
+ {% endif %}
+
+ {% endfor %}
+
+ {% else %}
+ 🌿 Rien en vol pour le moment — tout est au Backlog ou terminé.
+ {% endif %}
+
+
+
+ {% endfor %}
+
+{% else %}
+
+
🖥️ Wallboard
+
Aucun projet actif à afficher{% if single %} pour ce dépôt{% endif %}.
+
Astuce : /wall?repo=Proprietaire/depot fige un seul projet.
+
+{% endif %}
+
+
+
diff --git a/static/css/style.css b/static/css/style.css
index a55d792..4b4a1de 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -893,3 +893,77 @@ footer {
scroll-behavior: auto !important;
}
}
+
+/* ── Wallboard (0.6.0) : affichage plein écran, lisible à 3 mètres ── */
+.wall-body {
+ background: #0b1220;
+ color: #e5ecf5;
+ margin: 0;
+ font-family: inherit;
+}
+.wall-stage { position: relative; min-height: 100vh; }
+.wall-slide {
+ display: none;
+ min-height: 100vh;
+ box-sizing: border-box;
+ padding: 4vh 4vw;
+ flex-direction: column;
+ gap: 3vh;
+}
+.wall-slide.active { display: flex; animation: wall-in 0.45s ease; }
+@keyframes wall-in { from { opacity: 0; } to { opacity: 1; } }
+.wall-head {
+ display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
+}
+.wall-kicker { font-size: 1rem; letter-spacing: 0.22em; text-transform: uppercase; color: #8fa3bf; }
+.wall-project { font-size: clamp(2.2rem, 5.2vw, 4.2rem); margin: 0.4rem 0 0; line-height: 1.05; }
+.wall-clock { text-align: right; }
+.wall-time { font-size: clamp(2rem, 4.5vw, 3.6rem); font-weight: 800; line-height: 1; }
+.wall-date { color: #8fa3bf; font-size: 1.15rem; margin-top: 0.35rem; text-transform: capitalize; }
+.wall-rotation { color: #5b6b84; margin-top: 0.4rem; font-size: 1rem; }
+.wall-counts {
+ display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px;
+}
+.wall-count {
+ border: 1.5px solid var(--col);
+ border-top: 6px solid var(--col);
+ border-radius: 14px;
+ padding: 14px 10px 12px;
+ text-align: center;
+ background: rgba(255, 255, 255, 0.03);
+}
+.wall-count-n { display: block; font-size: clamp(1.9rem, 3.6vw, 3rem); font-weight: 800; }
+.wall-count-l { display: block; color: #aebdd2; font-size: clamp(0.78rem, 1.25vw, 1.02rem); margin-top: 2px; }
+.wall-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
+.wall-card {
+ display: flex; align-items: center; gap: 18px;
+ background: rgba(255, 255, 255, 0.045);
+ border-radius: 14px;
+ padding: 16px 20px;
+ font-size: clamp(1.15rem, 2.1vw, 1.7rem);
+}
+.wall-card-col {
+ border: 1.5px solid var(--col); color: var(--col);
+ border-radius: 999px; padding: 4px 14px;
+ font-size: 0.62em; font-weight: 700; white-space: nowrap;
+}
+.wall-card-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.wall-card-age { color: #fbbf24; font-weight: 700; white-space: nowrap; }
+.wall-card-age.hot { color: #f87171; }
+.wall-idle { font-size: 1.5rem; color: #8fa3bf; }
+.wall-foot {
+ margin-top: auto;
+ display: flex; gap: 36px; flex-wrap: wrap;
+ font-size: clamp(1rem, 1.7vw, 1.35rem); color: #aebdd2;
+}
+.wall-live { color: #34d399; font-weight: 700; letter-spacing: 0.08em; }
+.wall-empty {
+ min-height: 100vh; display: flex; flex-direction: column;
+ align-items: center; justify-content: center; gap: 10px; text-align: center;
+ color: #aebdd2; padding: 24px;
+}
+.wall-empty h1 { color: #e5ecf5; font-size: 2.6rem; margin: 0; }
+.wall-empty code { background: rgba(255,255,255,0.08); padding: 2px 8px; border-radius: 6px; }
+@media (max-width: 900px) {
+ .wall-counts { grid-template-columns: repeat(3, 1fr); }
+}
diff --git a/static/js/wall.js b/static/js/wall.js
new file mode 100644
index 0000000..f0b9be7
--- /dev/null
+++ b/static/js/wall.js
@@ -0,0 +1,42 @@
+/**
+ * Kanbante — Wallboard: slide rotation, clock, live refresh.
+ *
+ * The wall is a display, not a workspace: no interaction to protect,
+ * so a realtime event simply reloads the page (plus a slow safety
+ * reload in case the stream drops silently).
+ */
+(function () {
+ var slides = Array.from(document.querySelectorAll('.wall-slide'));
+ var ROTATE_MS = 30000;
+ var current = 0;
+
+ if (slides.length > 1) {
+ setInterval(function () {
+ slides[current].classList.remove('active');
+ current = (current + 1) % slides.length;
+ slides[current].classList.add('active');
+ }, ROTATE_MS);
+ }
+
+ function tickClock() {
+ var now = new Date();
+ var time = now.toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit' });
+ var date = now.toLocaleDateString('fr-CA', {
+ weekday: 'long', day: 'numeric', month: 'long',
+ });
+ document.querySelectorAll('[data-clock]').forEach(function (el) { el.textContent = time; });
+ document.querySelectorAll('[data-date]').forEach(function (el) { el.textContent = date; });
+ }
+ tickClock();
+ setInterval(tickClock, 15000);
+
+ // Live: any board activity refreshes the wall.
+ try {
+ var source = new EventSource('/api/stream');
+ source.onmessage = function () { location.reload(); };
+ } catch (err) {
+ console.warn('Wallboard live stream unavailable:', err);
+ }
+ // Safety net.
+ setTimeout(function () { location.reload(); }, 5 * 60 * 1000);
+})();