Lehrer-Observability + Weltküche-Inhalt + Wrapper-Fix + Passstraße

teacher.html: Menü „Live" → „Ergebnisse" mit Unteransichten
Tag·Aktuell·Vergleich·Gesamt (alte Ergebnisse-Ansicht ist jetzt „Gesamt").
Neue Kennzahl Qualität (grafischer richtig/falsch-Balken) in Aktuell +
Vergleich + Weltküche-Zeile, Gerichte-Zähler (Fleiß), Labels entschärft
(„Kritisch" → Stark/Solide/Viele Fehler).

Weltküche: korrekte Artikel (der/die/das) für alle 70 Zutaten in
production-matrix.json; verdrehten Herkunfts-Satz + Heimat-Banner neu und
marktbewusst (Ukraine-Distraktor ehrlich erklärt), „man"-Konstruktionen
für Singular/Plural.

_scripts.php: renderPage() injizierte Favicon per strrpos ins letzte
</head> — das lag in teacher.htmls printBatchTickets-JS-String → SyntaxError
zerschoss das ganze Inline-Script auf /teacher. Fix: strpos (erstes </head>).

tourismusregion: neue Karte passstrasse in maps-custom.json (Route bergauf
136 Punkte, 41 Bauslots) aus Editor-Export.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 13:32:24 +02:00
parent 4bfb6539cb
commit 5655af81bf
6 changed files with 7038 additions and 5808 deletions
+26 -7
View File
@@ -521,7 +521,7 @@ async function loadWeltkuecheData() {
// ING-Map aus production-matrix bauen
Object.entries(prodMatrix).forEach(([k, v]) => {
ING[k] = {
nm: v.nm, ic: v.ic,
nm: v.nm, ic: v.ic, art: v.art || 'die',
producers: v.producers || {},
climate_possible: v.climate_possible || [],
fact: v.fact || '',
@@ -1021,6 +1021,16 @@ function impossibleCountries(corr, possible) {
return out;
}
// Zutat mit korrektem Artikel: „die Kartoffel", „der Pfeffer", „das Olivenöl".
// Plural-Zutaten tragen art='die' — die Sätze nutzen bewusst „man"-Konstruktionen
// (nimmt man / holt man …), damit Singular UND Plural grammatisch passen.
function ingWas(ing, sTask, ingKey) {
const label = sTask && sTask.label;
if (label) return label;
const a = (ing && ing.art) || 'die';
return a + ' ' + (ing ? ing.nm : '');
}
function buildTaskFor(ingKey) {
if (_taskCache[ingKey]) return _taskCache[ingKey];
const ing = ING[ingKey];
@@ -1358,12 +1368,17 @@ function explainChoice(ingKey, key, isCorrect){
const sTask = _taskCache[ingKey];
if (sTask && sTask.signature) {
const heimatN = C[sTask.heimat] ? C[sTask.heimat].n : '';
const was = sTask.label || ('der/die/das ' + ing.nm);
const was = ingWas(ing, sTask, ingKey);
if (isCorrect) {
return {cls:'ok', badge:'✓', text:`Dieses Gericht kommt aus <b>${heimatN}</b> ${was} ist hier heimisch und wird vor Ort erzeugt.`};
if (key === sTask.heimat)
return {cls:'ok', badge:'✓', text:`Richtig für ein Gericht aus <b>${heimatN}</b> nimmt man ${was} aus ${heimatN} selbst.`};
return {cls:'ok', badge:'✓', text:`Auch richtig ${heimatN} allein deckt den Bedarf nicht, darum ist ${C[key].n} als Nachbarland ein realistischer Zweit-Lieferant.`};
}
if (info) {
return {cls:'mid', badge:'⚠️', text:`${C[key].n} erzeugt zwar viel ${ing.nm}${amount?' ('+amount+')':''} aber in einem Gericht aus ${heimatN} stammt ${was} von dort.`};
const m = info.market || 'global';
if (m === 'world-far' || m === 'local')
return {cls:'mid', badge:'🌐', text:`${C[key].n} erzeugt zwar riesige Mengen ${ing.nm}${amount?' ('+amount+')':''} in unseren Handel kommt davon aber kaum etwas. Für ein Gericht aus ${heimatN} nimmt man ${was} aus ${heimatN} oder einem Nachbarland.`};
return {cls:'mid', badge:'⚠️', text:`${C[key].n} ist auch ein echter Erzeuger${amount?' ('+amount+')':''} aber für ein Gericht aus ${heimatN} nimmt man ${was} lieber aus ${heimatN} selbst oder dem nächsten Nachbarland.`};
}
// Nicht-Produzent-Fehlklick → normale „unmöglich"-Logik unten
}
@@ -1471,7 +1486,7 @@ function showSolved(ing,pts,bonus){
const factLine = ing.fact ? `<div class="more-line"><b>Wusstest du?</b> ${esc(ing.fact)}</div>` : '';
// Heimat-Regel: erklären, warum die Region die Antwort ist (nicht der größte Produzent)
const sigLine = (task.signature && C[task.heimat])
? `<div class="more-line" style="background:#eef5ec;border-left:3px solid #4a7c4e">🍽️ Das ist ein Gericht aus <b>${C[task.heimat].n}</b>. ${task.label ? ('<b>'+task.label+'</b>') : ('Der/die/das '+esc(ing.nm))} kommt von hier nur Zutaten, die bei uns gar nicht wachsen, reisen von weit her.</div>`
? `<div class="more-line" style="background:#eef5ec;border-left:3px solid #4a7c4e">🍽️ Das ist ein Gericht aus <b>${C[task.heimat].n}</b>. Zutaten werden zwar bevorzugt aus ${C[task.heimat].n} verwendet, aber ${C[task.heimat].n} allein deckt den Bedarf nicht ab darum zählt auch ein Nachbarland als richtig. Nur Zutaten, die bei uns gar nicht wachsen, reisen von weit her.</div>`
: '';
// Caveats für world-far/off-season Korrekt-Picks (pro Land separat)
const caveats = task.correct.map(k => {
@@ -1521,8 +1536,12 @@ function showWrong(key, kind, ingKey){
const info = ing.producers[key];
const amount = info && info.t ? fmtTonnes(info.t) : 'verbreitet';
const heimatN = C[sTask.heimat] ? C[sTask.heimat].n : '';
const was = sTask.label || ('der/die/das ' + ing.nm);
card.innerHTML = `<div class="rc-head">⚠️ ${c.f} ${c.n} erzeugt zwar viel ${ing.nm} (${amount}) aber dieses Gericht kommt aus ${heimatN}, und ${was} stammt von dort.</div>`+
const was = ingWas(ing, sTask, ingKey);
const m = info.market || 'global';
const head = (m === 'world-far' || m === 'local')
? `⚠️ ${c.f} ${c.n} erzeugt zwar riesige Mengen ${ing.nm} (${amount}) aber davon kommt bei uns fast nichts in den Handel. Für dieses Gericht aus ${heimatN} nimmt man ${was} aus ${heimatN} oder einem Nachbarland.`
: `⚠️ ${c.f} ${c.n} ist auch ein echter Erzeuger (${amount}) aber für dieses Gericht aus ${heimatN} nimmt man ${was} lieber aus ${heimatN} selbst oder dem nächsten Nachbarland.`;
card.innerHTML = `<div class="rc-head">${head}</div>`+
`<div class="note">${c.info}<br><br>🔎 Tipp: Achte auf den Namen des Gerichts er verrät oft die Herkunft.</div>`;
return;
}