diff --git a/web/src/beanflows/dashboard/templates/pulse.html b/web/src/beanflows/dashboard/templates/pulse.html
index 54779d3..9373b4f 100644
--- a/web/src/beanflows/dashboard/templates/pulse.html
+++ b/web/src/beanflows/dashboard/templates/pulse.html
@@ -25,16 +25,13 @@
color: var(--color-stone);
}
-/* 2×2 sparkline grid */
+/* Sparkline grid — auto-fit for 4 or 5 cards */
.spark-grid {
display: grid;
- grid-template-columns: 1fr 1fr;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
-@media (max-width: 600px) {
- .spark-grid { grid-template-columns: 1fr; }
-}
.spark-card {
background: white;
@@ -94,7 +91,7 @@
Global coffee market — full picture in 10 seconds{% if user.name %} · Welcome back, {{ user.name }}{% endif %}
-
+
KC=F Close
@@ -139,6 +136,17 @@
ending stocks / consumption{% if stu_latest %} · {{ stu_latest.market_year }}{% endif %}
+
+
+
Crop Stress Index
+
+ {% if weather_stress_latest %}{{ "{:.0f}".format(weather_stress_latest.avg_crop_stress_index) }}/100{% else %}--{% endif %}
+
+
+ avg · {% if weather_stress_latest %}{{ weather_stress_latest.locations_under_stress }} stressed{% endif %}
+ {% if weather_stress_latest %} · {{ weather_stress_latest.observation_date }}{% endif %}
+
+
@@ -156,6 +164,9 @@
ICE Stocks {% if ice_stocks_latest %}{{ ice_stocks_latest.report_date }}{% else %}—{% endif %}
+
+ Weather {% if weather_stress_latest %}{{ weather_stress_latest.observation_date }}{% else %}—{% endif %}
+
@@ -209,6 +220,18 @@
USDA WASDE · 1,000 60-kg bags · production vs distribution
+
+
+
+
+
+
+
Open-Meteo ERA5 · avg across 12 origins · 0 = no stress · 100 = severe
+
+
{% if plan == "free" %}
@@ -338,6 +361,27 @@
options: sparkOpts(C.copper, false),
});
}
+
+ // Weather crop stress sparkline (90d)
+ var weatherRaw = {{ weather_stress_trend | tojson }};
+ if (weatherRaw && weatherRaw.length > 0) {
+ var weatherAsc = weatherRaw.slice().reverse();
+ new Chart(document.getElementById('sparkWeather'), {
+ type: 'line',
+ data: {
+ labels: weatherAsc.map(function (r) { return r.observation_date; }),
+ datasets: [{
+ data: weatherAsc.map(function (r) { return r.avg_crop_stress_index; }),
+ borderColor: C.copper,
+ backgroundColor: C.copper + '22',
+ fill: true,
+ tension: 0.3,
+ borderWidth: 2,
+ }],
+ },
+ options: sparkOpts(C.copper, true),
+ });
+ }
}());
{% endblock %}