diff --git a/App/teacher.html b/App/teacher.html
index 4e6497f..6ccbb35 100644
--- a/App/teacher.html
+++ b/App/teacher.html
@@ -729,16 +729,12 @@ var LIVE_PRIMARY_FIELDS = {
var done = v||0; var pct = done/t; var c = pct>=1 ? '#5a8a5e' : pct>=.5 ? '#c9913a' : '#8a7a4a';
return ''+done+' / '+t+'';
}},
- {k:'completed', label:'Gerichte', fmt:function(v, row){
- var s = row.state||{}; var t = s.completedTotal||0;
- if (!t) return '—';
- var done = v||0; var pct = done/t; var c = pct>=1 ? '#5a8a5e' : pct>=.5 ? '#c9913a' : '#8a8a8a';
- return ''+done+' / '+t+'';
- }},
{k:'mistakesInDish', label:'Fehlklicks', align:'center', fmt:function(v){
var n = v||0; var c = n>=12 ? '#c07a6b' : n>=5 ? '#c9913a' : '#5a8a5e';
return ''+n+'';
}},
+ {k:'__prog', label:'Fortschritt', align:'left', fmt:function(v, row){ return _liveProgressBar(row.module_id, row.state); }},
+ {k:'__lage', label:'Lage', align:'center', fmt:function(v, row){ return _liveMoodBadge(row.module_id, row.state); }},
],
'busfahrt': [
{k:'levelId', label:'Stufe', align:'center'},
@@ -1159,6 +1155,59 @@ function _liveNeedsHelp(simId, s) {
}
return false;
}
+// Allgemeiner „aktueller Erfolg": Fortschritt (% durch die Sim) + Lage (Ampel).
+// Aus dem Live-State jeder Sim ableitbar → über alle Module vergleichbar.
+function _liveProgressPct(simId, s) {
+ if (!s) return null;
+ var f = function(n, d) { return d > 0 ? Math.max(0, Math.min(100, Math.round((n||0)/d*100))) : null; };
+ switch (simId) {
+ case 'weltkueche': return f(s.completed, s.completedTotal);
+ case 'sonnensystem': return s.taskTotal ? f(s.completed, s.taskTotal) : (s.progressPct!=null?s.progressPct:null);
+ case 'kofferdetektiv': return s.cases_total ? f(s.cases_solved, s.cases_total) : (s.progressPct!=null?s.progressPct:null);
+ case 'eu-werkstatt': return f(s.step, s.stepsTotal);
+ case 'energiemanager': return f(s.day, s.dayTotal);
+ case 'busfahrt': case 'fluggesellschaft': return f(s.orderIndex, s.totalOrders);
+ case 'heli': return f(s.planIndex, s.planTotal);
+ case 'tourismusregion': return f(s.wave, s.waveTotal);
+ case 'tourismustal': return f(s.goalsDone, s.goalsTotal);
+ case 'fluss': return s.progressPct!=null ? s.progressPct : null;
+ }
+ return s.progressPct!=null ? s.progressPct : null;
+}
+function _liveMood(simId, s) {
+ if (!s) return null;
+ if (s.health) return ({good:'good',ok:'good',warning:'mid',bad:'bad',critical:'bad'})[s.health] || 'mid';
+ if (_liveNeedsHelp(simId, s)) return 'bad';
+ switch (simId) {
+ case 'weltkueche': return (s.mistakesInDish||0) <= 2 ? 'good' : (s.mistakesInDish >= 8 ? 'bad' : 'mid');
+ case 'klima': case 'klima-3d': return ((s.floodedPct==null?100:s.floodedPct) < 20 && (s.budget||0) >= 0) ? 'good' : 'mid';
+ case 'busfahrt': case 'fluggesellschaft': return (s.budget==null?0:s.budget) >= 5000 ? 'good' : (s.budget < 0 ? 'bad' : 'mid');
+ case 'tourismustal': return (s.money==null?0:s.money) >= 4000 ? 'good' : (s.money < 0 ? 'bad' : 'mid');
+ case 'heli': return (s.totalStars||0) >= 4 ? 'good' : 'mid';
+ case 'fluss': case 'kofferdetektiv': case 'sonnensystem':
+ return s.score!=null ? (s.score>=70?'good':s.score>=40?'mid':'bad') : 'mid';
+ }
+ return 'mid';
+}
+function _liveProgressBar(simId, s) {
+ var p = _liveProgressPct(simId, s);
+ if (p == null) return '—';
+ var c = p >= 75 ? '#5a8a5e' : p >= 40 ? '#c9913a' : '#c07a6b';
+ return ''
+ + ''
+ + ''
+ + ''+p+'%';
+}
+function _liveMoodBadge(simId, s) {
+ var m = _liveMood(simId, s);
+ if (!m) return '—';
+ var map = { good:['#5a8a5e','Gut'], mid:['#c9913a','OK'], bad:['#c07a6b','Kritisch'] };
+ var x = map[m] || map.mid;
+ return ''
+ + ''
+ + ''+x[1]+'';
+}
+
var _liveReflCache = '', _liveReflAt = 0;
// Aktiv = Lebenszeichen in den letzten 90 s. Ältere Sessions bleiben sichtbar,
// aber als „pausiert" (Lernende:r macht Pause, kann später weitermachen).