diff --git a/App/Don_t_Deploy/2026-07-16-glossar-bilder.sql b/App/Don_t_Deploy/2026-07-16-glossar-bilder.sql new file mode 100644 index 0000000..fdcfd5e --- /dev/null +++ b/App/Don_t_Deploy/2026-07-16-glossar-bilder.sql @@ -0,0 +1,162 @@ +UPDATE glossar SET image_path='assets/img/glossar/aequator.webp' WHERE key_slug='aequator' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/almwirtschaft.webp' WHERE key_slug='almwirtschaft' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/anbaugrenze.webp' WHERE key_slug='anbaugrenze' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/anbauguertel.webp' WHERE key_slug='anbauguertel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/aue.webp' WHERE key_slug='aue' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/barten.webp' WHERE key_slug='barten' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bartenwale.webp' WHERE key_slug='bartenwale' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/basistunnel.webp' WHERE key_slug='basistunnel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bestaeubung.webp' WHERE key_slug='bestaeubung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bims.webp' WHERE key_slug='bims' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/binnengrenze.webp' WHERE key_slug='binnengrenze' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/binnenmarkt.webp' WHERE key_slug='binnenmarkt' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/binnenschiff.webp' WHERE key_slug='binnenschiff' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/blas.webp' WHERE key_slug='blas' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/blasloch.webp' WHERE key_slug='blasloch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bodenversiegelung.webp' WHERE key_slug='bodenversiegelung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bubble-net.webp' WHERE key_slug='bubble-net' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/buckelwal.webp' WHERE key_slug='buckelwal' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/bycatch.webp' WHERE key_slug='bycatch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/caldera.webp' WHERE key_slug='caldera' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/co2-flugverkehr.webp' WHERE key_slug='co2-flugverkehr' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/co2-fussabdruck-lebensmittel.webp' WHERE key_slug='co2-fussabdruck-lebensmittel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/cockpit-air-traffic.webp' WHERE key_slug='cockpit-air-traffic' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/datumsgrenze.webp' WHERE key_slug='datumsgrenze' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/drafting.webp' WHERE key_slug='drafting' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/echolokation.webp' WHERE key_slug='echolokation' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/engpass.webp' WHERE key_slug='engpass' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/ernaehrungspyramide.webp' WHERE key_slug='ernaehrungspyramide' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/ewr.webp' WHERE key_slug='ewr' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/fair-trade.webp' WHERE key_slug='fair-trade' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/fernbus.webp' WHERE key_slug='fernbus' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/flugrettung.webp' WHERE key_slug='flugrettung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/flugware.webp' WHERE key_slug='flugware' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/fluke.webp' WHERE key_slug='fluke' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/folgekosten.webp' WHERE key_slug='folgekosten' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/frequenz.webp' WHERE key_slug='frequenz' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gebundene-rotation.webp' WHERE key_slug='gebundene-rotation' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gefahrenzonenplan.webp' WHERE key_slug='gefahrenzonenplan' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/geisternetz.webp' WHERE key_slug='geisternetz' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gepaeckfoerderanlage.webp' WHERE key_slug='gepaeckfoerderanlage' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gewitter-flug.webp' WHERE key_slug='gewitter-flug' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gigawattstunde.webp' WHERE key_slug='gigawattstunde' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/gletscher.webp' WHERE key_slug='gletscher' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/harte-weiche-standortfaktoren.webp' WHERE key_slug='harte-weiche-standortfaktoren' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hartweizen.webp' WHERE key_slug='hartweizen' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hawaiianisch.webp' WHERE key_slug='hawaiianisch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/heli-kennzeichen.webp' WHERE key_slug='heli-kennzeichen' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hertz.webp' WHERE key_slug='hertz' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hitzetag.webp' WHERE key_slug='hitzetag' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hotspot.webp' WHERE key_slug='hotspot' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hq100.webp' WHERE key_slug='hq100' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/hub-flughafen.webp' WHERE key_slug='hub-flughafen' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/imo.webp' WHERE key_slug='imo' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/iwc.webp' WHERE key_slug='iwc' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/jetstream.webp' WHERE key_slug='jetstream' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/just-in-time.webp' WHERE key_slug='just-in-time' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kakao-bohne.webp' WHERE key_slug='kakao-bohne' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kanaltunnel.webp' WHERE key_slug='kanaltunnel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kapazitaet.webp' WHERE key_slug='kapazitaet' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/keeling-kurve.webp' WHERE key_slug='keeling-kurve' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kernenergie.webp' WHERE key_slug='kernenergie' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kernschatten.webp' WHERE key_slug='kernschatten' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/klimatraegheit.webp' WHERE key_slug='klimatraegheit' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/knochenleitung.webp' WHERE key_slug='knochenleitung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/knoten.webp' WHERE key_slug='knoten' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kondensstreifen.webp' WHERE key_slug='kondensstreifen' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kontinent.webp' WHERE key_slug='kontinent' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kopplungseffekt.webp' WHERE key_slug='kopplungseffekt' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/krater.webp' WHERE key_slug='krater' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/krill.webp' WHERE key_slug='krill' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/kurzstreckenflug.webp' WHERE key_slug='kurzstreckenflug' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lageenergie.webp' WHERE key_slug='lageenergie' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lahar.webp' WHERE key_slug='lahar' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lapilli.webp' WHERE key_slug='lapilli' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lastabwurf.webp' WHERE key_slug='lastabwurf' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/laufwasserkraftwerk.webp' WHERE key_slug='laufwasserkraftwerk' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lava.webp' WHERE key_slug='lava' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lawine.webp' WHERE key_slug='lawine' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lawinenwarnstufe.webp' WHERE key_slug='lawinenwarnstufe' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lebensmittelverschwendung.webp' WHERE key_slug='lebensmittelverschwendung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lenkungsinstrumente.webp' WHERE key_slug='lenkungsinstrumente' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/letzte-meile.webp' WHERE key_slug='letzte-meile' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lichtgeschwindigkeit.webp' WHERE key_slug='lichtgeschwindigkeit' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/lichtverschmutzung.webp' WHERE key_slug='lichtverschmutzung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/luftverkehr.webp' WHERE key_slug='luftverkehr' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/maar.webp' WHERE key_slug='maar' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/magma.webp' WHERE key_slug='magma' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/magmakammer.webp' WHERE key_slug='magmakammer' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/marine-sanctuary.webp' WHERE key_slug='marine-sanctuary' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/migration.webp' WHERE key_slug='migration' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/modal-split.webp' WHERE key_slug='modal-split' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/mofette.webp' WHERE key_slug='mofette' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/monsun.webp' WHERE key_slug='monsun' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/mont-blanc-tunnel.webp' WHERE key_slug='mont-blanc-tunnel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/myoglobin.webp' WHERE key_slug='myoglobin' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/nachtzug.webp' WHERE key_slug='nachtzug' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/netzbetreiber.webp' WHERE key_slug='netzbetreiber' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/netzfrequenz.webp' WHERE key_slug='netzfrequenz' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/nicht-co2-effekte.webp' WHERE key_slug='nicht-co2-effekte' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/norroena-faehre.webp' WHERE key_slug='norroena-faehre' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/notruf.webp' WHERE key_slug='notruf' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/obsidian.webp' WHERE key_slug='obsidian' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/oeresundbruecke.webp' WHERE key_slug='oeresundbruecke' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/off-season-import.webp' WHERE key_slug='off-season-import' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/pegel.webp' WHERE key_slug='pegel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/pektoralflosse.webp' WHERE key_slug='pektoralflosse' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/personenkilometer.webp' WHERE key_slug='personenkilometer' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/photon.webp' WHERE key_slug='photon' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/phreatomagmatisch.webp' WHERE key_slug='phreatomagmatisch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/planetenweg.webp' WHERE key_slug='planetenweg' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/plantage.webp' WHERE key_slug='plantage' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/plinianisch.webp' WHERE key_slug='plinianisch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/polarnacht.webp' WHERE key_slug='polarnacht' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/polartag.webp' WHERE key_slug='polartag' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/preiselastizitaet.webp' WHERE key_slug='preiselastizitaet' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/pyroklastischer-strom.webp' WHERE key_slug='pyroklastischer-strom' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/reisemotiv.webp' WHERE key_slug='reisemotiv' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/restrisiko.webp' WHERE key_slug='restrisiko' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/rollende-landstrasse.webp' WHERE key_slug='rollende-landstrasse' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/rueckhaltebecken.webp' WHERE key_slug='rueckhaltebecken' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/ruecklagen.webp' WHERE key_slug='ruecklagen' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/saisonal-regional.webp' WHERE key_slug='saisonal-regional' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/schildvulkan.webp' WHERE key_slug='schildvulkan' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/schlot.webp' WHERE key_slug='schlot' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/schwammstadt.webp' WHERE key_slug='schwammstadt' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/selbstversorgungsgrad.webp' WHERE key_slug='selbstversorgungsgrad' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/ship-strike.webp' WHERE key_slug='ship-strike' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/skaleneffekt.webp' WHERE key_slug='skaleneffekt' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/stratovulkan.webp' WHERE key_slug='stratovulkan' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/stromboerse.webp' WHERE key_slug='stromboerse' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/strombolisch.webp' WHERE key_slug='strombolisch' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/sturmflut.webp' WHERE key_slug='sturmflut' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/subduktionszone.webp' WHERE key_slug='subduktionszone' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/subsidiaritaet.webp' WHERE key_slug='subsidiaritaet' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/tagesgast.webp' WHERE key_slug='tagesgast' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/tephra.webp' WHERE key_slug='tephra' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/tourismusarten.webp' WHERE key_slug='tourismusarten' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/transitverkehr.webp' WHERE key_slug='transitverkehr' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/transparenzregister.webp' WHERE key_slug='transparenzregister' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/trilog.webp' WHERE key_slug='trilog' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/tss.webp' WHERE key_slug='tss' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/tubercles.webp' WHERE key_slug='tubercles' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/vegetationsperiode.webp' WHERE key_slug='vegetationsperiode' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/vei.webp' WHERE key_slug='vei' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/verbundnetz.webp' WHERE key_slug='verbundnetz' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/versalzung.webp' WHERE key_slug='versalzung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/viskositaet.webp' WHERE key_slug='viskositaet' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/vogelschlag.webp' WHERE key_slug='vogelschlag' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/vulkanasche.webp' WHERE key_slug='vulkanasche' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/waermeausdehnung.webp' WHERE key_slug='waermeausdehnung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/waldgrenze.webp' WHERE key_slug='waldgrenze' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/walgesang.webp' WHERE key_slug='walgesang' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/welternaehrung.webp' WHERE key_slug='welternaehrung' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/welternte.webp' WHERE key_slug='welternte' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/welthandel.webp' WHERE key_slug='welthandel' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/wertschoepfungskette.webp' WHERE key_slug='wertschoepfungskette' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/windrose.webp' WHERE key_slug='windrose' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/zeitzone.webp' WHERE key_slug='zeitzone' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/zenit.webp' WHERE key_slug='zenit' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/zielkonflikt.webp' WHERE key_slug='zielkonflikt' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/zollunion.webp' WHERE key_slug='zollunion' AND (image_path IS NULL OR image_path=''); +UPDATE glossar SET image_path='assets/img/glossar/großkreis.webp' WHERE key_slug='großkreis' AND (image_path IS NULL OR image_path=''); diff --git a/App/assets/css/buch.css b/App/assets/css/buch.css index 1cace5b..05a804d 100644 --- a/App/assets/css/buch.css +++ b/App/assets/css/buch.css @@ -19,6 +19,7 @@ body { background: #edeae0; margin: 0; font-family: system-ui, -apple-system, "S .b-seite .b-nr { position: absolute; top: 14px; right: 18px; font-size: 12px; color: #9a958a; font-weight: 700; letter-spacing: .08em; } .b-kicker { text-transform: uppercase; letter-spacing: .1em; font-size: 12px; font-weight: 800; color: #b3541e; margin: 0 0 4px; } .b-seite h1 { font-size: 30px; margin: 0 0 6px; line-height: 1.2; } +.b-kapicon { width: 46px; height: 46px; border-radius: 10px; vertical-align: -12px; margin-right: 4px; } .b-seite h2 { font-size: 22px; margin: 0 0 10px; } .b-leitfrage { font-size: 17px; font-style: italic; color: #4a4f52; border-left: 4px solid #e8c547; padding: 6px 12px; margin: 14px 0; background: #fbf6e3; border-radius: 0 8px 8px 0; } .b-seite p { line-height: 1.65; font-size: 15.5px; } diff --git a/App/assets/img/buch/icon-busfahrt.webp b/App/assets/img/buch/icon-busfahrt.webp new file mode 100644 index 0000000..0c48852 Binary files /dev/null and b/App/assets/img/buch/icon-busfahrt.webp differ diff --git a/App/assets/img/buch/icon-energiemanager.webp b/App/assets/img/buch/icon-energiemanager.webp new file mode 100644 index 0000000..91df469 Binary files /dev/null and b/App/assets/img/buch/icon-energiemanager.webp differ diff --git a/App/assets/img/buch/icon-eu-werkstatt.webp b/App/assets/img/buch/icon-eu-werkstatt.webp new file mode 100644 index 0000000..5d2f633 Binary files /dev/null and b/App/assets/img/buch/icon-eu-werkstatt.webp differ diff --git a/App/assets/img/buch/icon-farmer.webp b/App/assets/img/buch/icon-farmer.webp new file mode 100644 index 0000000..4fabebe Binary files /dev/null and b/App/assets/img/buch/icon-farmer.webp differ diff --git a/App/assets/img/buch/icon-fluss.webp b/App/assets/img/buch/icon-fluss.webp new file mode 100644 index 0000000..2322d7d Binary files /dev/null and b/App/assets/img/buch/icon-fluss.webp differ diff --git a/App/assets/img/buch/icon-heli.webp b/App/assets/img/buch/icon-heli.webp new file mode 100644 index 0000000..71c907e Binary files /dev/null and b/App/assets/img/buch/icon-heli.webp differ diff --git a/App/assets/img/buch/icon-klima.webp b/App/assets/img/buch/icon-klima.webp new file mode 100644 index 0000000..01f4b33 Binary files /dev/null and b/App/assets/img/buch/icon-klima.webp differ diff --git a/App/assets/img/buch/icon-kofferdetektiv.webp b/App/assets/img/buch/icon-kofferdetektiv.webp new file mode 100644 index 0000000..18f153a Binary files /dev/null and b/App/assets/img/buch/icon-kofferdetektiv.webp differ diff --git a/App/assets/img/buch/icon-logistik.webp b/App/assets/img/buch/icon-logistik.webp new file mode 100644 index 0000000..85c10ee Binary files /dev/null and b/App/assets/img/buch/icon-logistik.webp differ diff --git a/App/assets/img/buch/icon-sonnensystem.webp b/App/assets/img/buch/icon-sonnensystem.webp new file mode 100644 index 0000000..c0bd1f8 Binary files /dev/null and b/App/assets/img/buch/icon-sonnensystem.webp differ diff --git a/App/assets/img/buch/icon-tourismusregion.webp b/App/assets/img/buch/icon-tourismusregion.webp new file mode 100644 index 0000000..ce8b440 Binary files /dev/null and b/App/assets/img/buch/icon-tourismusregion.webp differ diff --git a/App/assets/img/buch/icon-tourismustal.webp b/App/assets/img/buch/icon-tourismustal.webp new file mode 100644 index 0000000..8d14041 Binary files /dev/null and b/App/assets/img/buch/icon-tourismustal.webp differ diff --git a/App/assets/img/buch/icon-weltkueche.webp b/App/assets/img/buch/icon-weltkueche.webp new file mode 100644 index 0000000..0bdbdc6 Binary files /dev/null and b/App/assets/img/buch/icon-weltkueche.webp differ diff --git a/App/assets/img/glossar/aequator.webp b/App/assets/img/glossar/aequator.webp new file mode 100644 index 0000000..f660a88 Binary files /dev/null and b/App/assets/img/glossar/aequator.webp differ diff --git a/App/assets/img/glossar/almwirtschaft.webp b/App/assets/img/glossar/almwirtschaft.webp new file mode 100644 index 0000000..05cb75e Binary files /dev/null and b/App/assets/img/glossar/almwirtschaft.webp differ diff --git a/App/assets/img/glossar/anbaugrenze.webp b/App/assets/img/glossar/anbaugrenze.webp new file mode 100644 index 0000000..41000c5 Binary files /dev/null and b/App/assets/img/glossar/anbaugrenze.webp differ diff --git a/App/assets/img/glossar/anbauguertel.webp b/App/assets/img/glossar/anbauguertel.webp new file mode 100644 index 0000000..a998aec Binary files /dev/null and b/App/assets/img/glossar/anbauguertel.webp differ diff --git a/App/assets/img/glossar/aue.webp b/App/assets/img/glossar/aue.webp new file mode 100644 index 0000000..bd1ff78 Binary files /dev/null and b/App/assets/img/glossar/aue.webp differ diff --git a/App/assets/img/glossar/barten.webp b/App/assets/img/glossar/barten.webp new file mode 100644 index 0000000..7d54020 Binary files /dev/null and b/App/assets/img/glossar/barten.webp differ diff --git a/App/assets/img/glossar/bartenwale.webp b/App/assets/img/glossar/bartenwale.webp new file mode 100644 index 0000000..6d96c92 Binary files /dev/null and b/App/assets/img/glossar/bartenwale.webp differ diff --git a/App/assets/img/glossar/basistunnel.webp b/App/assets/img/glossar/basistunnel.webp new file mode 100644 index 0000000..8ee1da6 Binary files /dev/null and b/App/assets/img/glossar/basistunnel.webp differ diff --git a/App/assets/img/glossar/bestaeubung.webp b/App/assets/img/glossar/bestaeubung.webp new file mode 100644 index 0000000..81db009 Binary files /dev/null and b/App/assets/img/glossar/bestaeubung.webp differ diff --git a/App/assets/img/glossar/bims.webp b/App/assets/img/glossar/bims.webp new file mode 100644 index 0000000..3a32b4e Binary files /dev/null and b/App/assets/img/glossar/bims.webp differ diff --git a/App/assets/img/glossar/binnengrenze.webp b/App/assets/img/glossar/binnengrenze.webp new file mode 100644 index 0000000..18b34d9 Binary files /dev/null and b/App/assets/img/glossar/binnengrenze.webp differ diff --git a/App/assets/img/glossar/binnenmarkt.webp b/App/assets/img/glossar/binnenmarkt.webp new file mode 100644 index 0000000..60dbd39 Binary files /dev/null and b/App/assets/img/glossar/binnenmarkt.webp differ diff --git a/App/assets/img/glossar/binnenschiff.webp b/App/assets/img/glossar/binnenschiff.webp new file mode 100644 index 0000000..619cab5 Binary files /dev/null and b/App/assets/img/glossar/binnenschiff.webp differ diff --git a/App/assets/img/glossar/blas.webp b/App/assets/img/glossar/blas.webp new file mode 100644 index 0000000..9374e67 Binary files /dev/null and b/App/assets/img/glossar/blas.webp differ diff --git a/App/assets/img/glossar/blasloch.webp b/App/assets/img/glossar/blasloch.webp new file mode 100644 index 0000000..dc7b5b2 Binary files /dev/null and b/App/assets/img/glossar/blasloch.webp differ diff --git a/App/assets/img/glossar/bodenversiegelung.webp b/App/assets/img/glossar/bodenversiegelung.webp new file mode 100644 index 0000000..dc2ec53 Binary files /dev/null and b/App/assets/img/glossar/bodenversiegelung.webp differ diff --git a/App/assets/img/glossar/bubble-net.webp b/App/assets/img/glossar/bubble-net.webp new file mode 100644 index 0000000..a054640 Binary files /dev/null and b/App/assets/img/glossar/bubble-net.webp differ diff --git a/App/assets/img/glossar/buckelwal.webp b/App/assets/img/glossar/buckelwal.webp new file mode 100644 index 0000000..eafae5d Binary files /dev/null and b/App/assets/img/glossar/buckelwal.webp differ diff --git a/App/assets/img/glossar/bycatch.webp b/App/assets/img/glossar/bycatch.webp new file mode 100644 index 0000000..1560440 Binary files /dev/null and b/App/assets/img/glossar/bycatch.webp differ diff --git a/App/assets/img/glossar/caldera.webp b/App/assets/img/glossar/caldera.webp new file mode 100644 index 0000000..dbe7238 Binary files /dev/null and b/App/assets/img/glossar/caldera.webp differ diff --git a/App/assets/img/glossar/co2-flugverkehr.webp b/App/assets/img/glossar/co2-flugverkehr.webp new file mode 100644 index 0000000..300fe7f Binary files /dev/null and b/App/assets/img/glossar/co2-flugverkehr.webp differ diff --git a/App/assets/img/glossar/co2-fussabdruck-lebensmittel.webp b/App/assets/img/glossar/co2-fussabdruck-lebensmittel.webp new file mode 100644 index 0000000..ca38b00 Binary files /dev/null and b/App/assets/img/glossar/co2-fussabdruck-lebensmittel.webp differ diff --git a/App/assets/img/glossar/cockpit-air-traffic.webp b/App/assets/img/glossar/cockpit-air-traffic.webp new file mode 100644 index 0000000..a2ca6fc Binary files /dev/null and b/App/assets/img/glossar/cockpit-air-traffic.webp differ diff --git a/App/assets/img/glossar/datumsgrenze.webp b/App/assets/img/glossar/datumsgrenze.webp new file mode 100644 index 0000000..f55c183 Binary files /dev/null and b/App/assets/img/glossar/datumsgrenze.webp differ diff --git a/App/assets/img/glossar/drafting.webp b/App/assets/img/glossar/drafting.webp new file mode 100644 index 0000000..e416d66 Binary files /dev/null and b/App/assets/img/glossar/drafting.webp differ diff --git a/App/assets/img/glossar/echolokation.webp b/App/assets/img/glossar/echolokation.webp new file mode 100644 index 0000000..bd1f4fe Binary files /dev/null and b/App/assets/img/glossar/echolokation.webp differ diff --git a/App/assets/img/glossar/engpass.webp b/App/assets/img/glossar/engpass.webp new file mode 100644 index 0000000..08828ac Binary files /dev/null and b/App/assets/img/glossar/engpass.webp differ diff --git a/App/assets/img/glossar/ernaehrungspyramide.webp b/App/assets/img/glossar/ernaehrungspyramide.webp new file mode 100644 index 0000000..2aaf816 Binary files /dev/null and b/App/assets/img/glossar/ernaehrungspyramide.webp differ diff --git a/App/assets/img/glossar/ewr.webp b/App/assets/img/glossar/ewr.webp new file mode 100644 index 0000000..f05f0e2 Binary files /dev/null and b/App/assets/img/glossar/ewr.webp differ diff --git a/App/assets/img/glossar/fair-trade.webp b/App/assets/img/glossar/fair-trade.webp new file mode 100644 index 0000000..1524cf3 Binary files /dev/null and b/App/assets/img/glossar/fair-trade.webp differ diff --git a/App/assets/img/glossar/fernbus.webp b/App/assets/img/glossar/fernbus.webp new file mode 100644 index 0000000..ce5f8d4 Binary files /dev/null and b/App/assets/img/glossar/fernbus.webp differ diff --git a/App/assets/img/glossar/flugrettung.webp b/App/assets/img/glossar/flugrettung.webp new file mode 100644 index 0000000..c23b818 Binary files /dev/null and b/App/assets/img/glossar/flugrettung.webp differ diff --git a/App/assets/img/glossar/flugware.webp b/App/assets/img/glossar/flugware.webp new file mode 100644 index 0000000..66b1ce4 Binary files /dev/null and b/App/assets/img/glossar/flugware.webp differ diff --git a/App/assets/img/glossar/fluke.webp b/App/assets/img/glossar/fluke.webp new file mode 100644 index 0000000..48908c6 Binary files /dev/null and b/App/assets/img/glossar/fluke.webp differ diff --git a/App/assets/img/glossar/folgekosten.webp b/App/assets/img/glossar/folgekosten.webp new file mode 100644 index 0000000..906b23a Binary files /dev/null and b/App/assets/img/glossar/folgekosten.webp differ diff --git a/App/assets/img/glossar/frequenz.webp b/App/assets/img/glossar/frequenz.webp new file mode 100644 index 0000000..531ad55 Binary files /dev/null and b/App/assets/img/glossar/frequenz.webp differ diff --git a/App/assets/img/glossar/gebundene-rotation.webp b/App/assets/img/glossar/gebundene-rotation.webp new file mode 100644 index 0000000..1165c6e Binary files /dev/null and b/App/assets/img/glossar/gebundene-rotation.webp differ diff --git a/App/assets/img/glossar/gefahrenzonenplan.webp b/App/assets/img/glossar/gefahrenzonenplan.webp new file mode 100644 index 0000000..8210817 Binary files /dev/null and b/App/assets/img/glossar/gefahrenzonenplan.webp differ diff --git a/App/assets/img/glossar/geisternetz.webp b/App/assets/img/glossar/geisternetz.webp new file mode 100644 index 0000000..4dbb1e5 Binary files /dev/null and b/App/assets/img/glossar/geisternetz.webp differ diff --git a/App/assets/img/glossar/gepaeckfoerderanlage.webp b/App/assets/img/glossar/gepaeckfoerderanlage.webp new file mode 100644 index 0000000..0ac41a7 Binary files /dev/null and b/App/assets/img/glossar/gepaeckfoerderanlage.webp differ diff --git a/App/assets/img/glossar/gewitter-flug.webp b/App/assets/img/glossar/gewitter-flug.webp new file mode 100644 index 0000000..b6af1fc Binary files /dev/null and b/App/assets/img/glossar/gewitter-flug.webp differ diff --git a/App/assets/img/glossar/gigawattstunde.webp b/App/assets/img/glossar/gigawattstunde.webp new file mode 100644 index 0000000..3299142 Binary files /dev/null and b/App/assets/img/glossar/gigawattstunde.webp differ diff --git a/App/assets/img/glossar/gletscher.webp b/App/assets/img/glossar/gletscher.webp new file mode 100644 index 0000000..792072d Binary files /dev/null and b/App/assets/img/glossar/gletscher.webp differ diff --git a/App/assets/img/glossar/großkreis.webp b/App/assets/img/glossar/großkreis.webp new file mode 100644 index 0000000..1108dc2 Binary files /dev/null and b/App/assets/img/glossar/großkreis.webp differ diff --git a/App/assets/img/glossar/harte-weiche-standortfaktoren.webp b/App/assets/img/glossar/harte-weiche-standortfaktoren.webp new file mode 100644 index 0000000..fa930a2 Binary files /dev/null and b/App/assets/img/glossar/harte-weiche-standortfaktoren.webp differ diff --git a/App/assets/img/glossar/hartweizen.webp b/App/assets/img/glossar/hartweizen.webp new file mode 100644 index 0000000..b3c6be4 Binary files /dev/null and b/App/assets/img/glossar/hartweizen.webp differ diff --git a/App/assets/img/glossar/hawaiianisch.webp b/App/assets/img/glossar/hawaiianisch.webp new file mode 100644 index 0000000..cd9e4b5 Binary files /dev/null and b/App/assets/img/glossar/hawaiianisch.webp differ diff --git a/App/assets/img/glossar/heli-kennzeichen.webp b/App/assets/img/glossar/heli-kennzeichen.webp new file mode 100644 index 0000000..063ea4a Binary files /dev/null and b/App/assets/img/glossar/heli-kennzeichen.webp differ diff --git a/App/assets/img/glossar/hertz.webp b/App/assets/img/glossar/hertz.webp new file mode 100644 index 0000000..688d2f4 Binary files /dev/null and b/App/assets/img/glossar/hertz.webp differ diff --git a/App/assets/img/glossar/hitzetag.webp b/App/assets/img/glossar/hitzetag.webp new file mode 100644 index 0000000..1e5a026 Binary files /dev/null and b/App/assets/img/glossar/hitzetag.webp differ diff --git a/App/assets/img/glossar/hotspot.webp b/App/assets/img/glossar/hotspot.webp new file mode 100644 index 0000000..eb7d6c2 Binary files /dev/null and b/App/assets/img/glossar/hotspot.webp differ diff --git a/App/assets/img/glossar/hq100.webp b/App/assets/img/glossar/hq100.webp new file mode 100644 index 0000000..9f93f64 Binary files /dev/null and b/App/assets/img/glossar/hq100.webp differ diff --git a/App/assets/img/glossar/hub-flughafen.webp b/App/assets/img/glossar/hub-flughafen.webp new file mode 100644 index 0000000..0332ea4 Binary files /dev/null and b/App/assets/img/glossar/hub-flughafen.webp differ diff --git a/App/assets/img/glossar/imo.webp b/App/assets/img/glossar/imo.webp new file mode 100644 index 0000000..6833d47 Binary files /dev/null and b/App/assets/img/glossar/imo.webp differ diff --git a/App/assets/img/glossar/iwc.webp b/App/assets/img/glossar/iwc.webp new file mode 100644 index 0000000..8ab6173 Binary files /dev/null and b/App/assets/img/glossar/iwc.webp differ diff --git a/App/assets/img/glossar/jetstream.webp b/App/assets/img/glossar/jetstream.webp new file mode 100644 index 0000000..9d9bf89 Binary files /dev/null and b/App/assets/img/glossar/jetstream.webp differ diff --git a/App/assets/img/glossar/just-in-time.webp b/App/assets/img/glossar/just-in-time.webp new file mode 100644 index 0000000..ca27bbe Binary files /dev/null and b/App/assets/img/glossar/just-in-time.webp differ diff --git a/App/assets/img/glossar/kakao-bohne.webp b/App/assets/img/glossar/kakao-bohne.webp new file mode 100644 index 0000000..cb84590 Binary files /dev/null and b/App/assets/img/glossar/kakao-bohne.webp differ diff --git a/App/assets/img/glossar/kanaltunnel.webp b/App/assets/img/glossar/kanaltunnel.webp new file mode 100644 index 0000000..f7665d7 Binary files /dev/null and b/App/assets/img/glossar/kanaltunnel.webp differ diff --git a/App/assets/img/glossar/kapazitaet.webp b/App/assets/img/glossar/kapazitaet.webp new file mode 100644 index 0000000..4694a9f Binary files /dev/null and b/App/assets/img/glossar/kapazitaet.webp differ diff --git a/App/assets/img/glossar/keeling-kurve.webp b/App/assets/img/glossar/keeling-kurve.webp new file mode 100644 index 0000000..f72b8c9 Binary files /dev/null and b/App/assets/img/glossar/keeling-kurve.webp differ diff --git a/App/assets/img/glossar/kernenergie.webp b/App/assets/img/glossar/kernenergie.webp new file mode 100644 index 0000000..ba8cef3 Binary files /dev/null and b/App/assets/img/glossar/kernenergie.webp differ diff --git a/App/assets/img/glossar/kernschatten.webp b/App/assets/img/glossar/kernschatten.webp new file mode 100644 index 0000000..5f3b030 Binary files /dev/null and b/App/assets/img/glossar/kernschatten.webp differ diff --git a/App/assets/img/glossar/klimatraegheit.webp b/App/assets/img/glossar/klimatraegheit.webp new file mode 100644 index 0000000..9190f45 Binary files /dev/null and b/App/assets/img/glossar/klimatraegheit.webp differ diff --git a/App/assets/img/glossar/knochenleitung.webp b/App/assets/img/glossar/knochenleitung.webp new file mode 100644 index 0000000..d9ba873 Binary files /dev/null and b/App/assets/img/glossar/knochenleitung.webp differ diff --git a/App/assets/img/glossar/knoten.webp b/App/assets/img/glossar/knoten.webp new file mode 100644 index 0000000..273dad1 Binary files /dev/null and b/App/assets/img/glossar/knoten.webp differ diff --git a/App/assets/img/glossar/kondensstreifen.webp b/App/assets/img/glossar/kondensstreifen.webp new file mode 100644 index 0000000..cb627e6 Binary files /dev/null and b/App/assets/img/glossar/kondensstreifen.webp differ diff --git a/App/assets/img/glossar/kontinent.webp b/App/assets/img/glossar/kontinent.webp new file mode 100644 index 0000000..f203b03 Binary files /dev/null and b/App/assets/img/glossar/kontinent.webp differ diff --git a/App/assets/img/glossar/kopplungseffekt.webp b/App/assets/img/glossar/kopplungseffekt.webp new file mode 100644 index 0000000..a7d5b8a Binary files /dev/null and b/App/assets/img/glossar/kopplungseffekt.webp differ diff --git a/App/assets/img/glossar/krater.webp b/App/assets/img/glossar/krater.webp new file mode 100644 index 0000000..79df2c9 Binary files /dev/null and b/App/assets/img/glossar/krater.webp differ diff --git a/App/assets/img/glossar/krill.webp b/App/assets/img/glossar/krill.webp new file mode 100644 index 0000000..21c9507 Binary files /dev/null and b/App/assets/img/glossar/krill.webp differ diff --git a/App/assets/img/glossar/kurzstreckenflug.webp b/App/assets/img/glossar/kurzstreckenflug.webp new file mode 100644 index 0000000..21abb83 Binary files /dev/null and b/App/assets/img/glossar/kurzstreckenflug.webp differ diff --git a/App/assets/img/glossar/lageenergie.webp b/App/assets/img/glossar/lageenergie.webp new file mode 100644 index 0000000..4297221 Binary files /dev/null and b/App/assets/img/glossar/lageenergie.webp differ diff --git a/App/assets/img/glossar/lahar.webp b/App/assets/img/glossar/lahar.webp new file mode 100644 index 0000000..b6e8a08 Binary files /dev/null and b/App/assets/img/glossar/lahar.webp differ diff --git a/App/assets/img/glossar/lapilli.webp b/App/assets/img/glossar/lapilli.webp new file mode 100644 index 0000000..fd50963 Binary files /dev/null and b/App/assets/img/glossar/lapilli.webp differ diff --git a/App/assets/img/glossar/lastabwurf.webp b/App/assets/img/glossar/lastabwurf.webp new file mode 100644 index 0000000..8cf4850 Binary files /dev/null and b/App/assets/img/glossar/lastabwurf.webp differ diff --git a/App/assets/img/glossar/laufwasserkraftwerk.webp b/App/assets/img/glossar/laufwasserkraftwerk.webp new file mode 100644 index 0000000..3d1821c Binary files /dev/null and b/App/assets/img/glossar/laufwasserkraftwerk.webp differ diff --git a/App/assets/img/glossar/lava.webp b/App/assets/img/glossar/lava.webp new file mode 100644 index 0000000..3731cf3 Binary files /dev/null and b/App/assets/img/glossar/lava.webp differ diff --git a/App/assets/img/glossar/lawine.webp b/App/assets/img/glossar/lawine.webp new file mode 100644 index 0000000..581a72d Binary files /dev/null and b/App/assets/img/glossar/lawine.webp differ diff --git a/App/assets/img/glossar/lawinenwarnstufe.webp b/App/assets/img/glossar/lawinenwarnstufe.webp new file mode 100644 index 0000000..d57f8ea Binary files /dev/null and b/App/assets/img/glossar/lawinenwarnstufe.webp differ diff --git a/App/assets/img/glossar/lebensmittelverschwendung.webp b/App/assets/img/glossar/lebensmittelverschwendung.webp new file mode 100644 index 0000000..ae08310 Binary files /dev/null and b/App/assets/img/glossar/lebensmittelverschwendung.webp differ diff --git a/App/assets/img/glossar/lenkungsinstrumente.webp b/App/assets/img/glossar/lenkungsinstrumente.webp new file mode 100644 index 0000000..71eac8a Binary files /dev/null and b/App/assets/img/glossar/lenkungsinstrumente.webp differ diff --git a/App/assets/img/glossar/letzte-meile.webp b/App/assets/img/glossar/letzte-meile.webp new file mode 100644 index 0000000..2e4303a Binary files /dev/null and b/App/assets/img/glossar/letzte-meile.webp differ diff --git a/App/assets/img/glossar/lichtgeschwindigkeit.webp b/App/assets/img/glossar/lichtgeschwindigkeit.webp new file mode 100644 index 0000000..d70c275 Binary files /dev/null and b/App/assets/img/glossar/lichtgeschwindigkeit.webp differ diff --git a/App/assets/img/glossar/lichtverschmutzung.webp b/App/assets/img/glossar/lichtverschmutzung.webp new file mode 100644 index 0000000..996104f Binary files /dev/null and b/App/assets/img/glossar/lichtverschmutzung.webp differ diff --git a/App/assets/img/glossar/luftverkehr.webp b/App/assets/img/glossar/luftverkehr.webp new file mode 100644 index 0000000..f5c60f8 Binary files /dev/null and b/App/assets/img/glossar/luftverkehr.webp differ diff --git a/App/assets/img/glossar/maar.webp b/App/assets/img/glossar/maar.webp new file mode 100644 index 0000000..8906a39 Binary files /dev/null and b/App/assets/img/glossar/maar.webp differ diff --git a/App/assets/img/glossar/magma.webp b/App/assets/img/glossar/magma.webp new file mode 100644 index 0000000..f1f14b2 Binary files /dev/null and b/App/assets/img/glossar/magma.webp differ diff --git a/App/assets/img/glossar/magmakammer.webp b/App/assets/img/glossar/magmakammer.webp new file mode 100644 index 0000000..f73b570 Binary files /dev/null and b/App/assets/img/glossar/magmakammer.webp differ diff --git a/App/assets/img/glossar/marine-sanctuary.webp b/App/assets/img/glossar/marine-sanctuary.webp new file mode 100644 index 0000000..ab70e99 Binary files /dev/null and b/App/assets/img/glossar/marine-sanctuary.webp differ diff --git a/App/assets/img/glossar/migration.webp b/App/assets/img/glossar/migration.webp new file mode 100644 index 0000000..4a04537 Binary files /dev/null and b/App/assets/img/glossar/migration.webp differ diff --git a/App/assets/img/glossar/modal-split.webp b/App/assets/img/glossar/modal-split.webp new file mode 100644 index 0000000..433574e Binary files /dev/null and b/App/assets/img/glossar/modal-split.webp differ diff --git a/App/assets/img/glossar/mofette.webp b/App/assets/img/glossar/mofette.webp new file mode 100644 index 0000000..5438cc9 Binary files /dev/null and b/App/assets/img/glossar/mofette.webp differ diff --git a/App/assets/img/glossar/monsun.webp b/App/assets/img/glossar/monsun.webp new file mode 100644 index 0000000..cc9cddc Binary files /dev/null and b/App/assets/img/glossar/monsun.webp differ diff --git a/App/assets/img/glossar/mont-blanc-tunnel.webp b/App/assets/img/glossar/mont-blanc-tunnel.webp new file mode 100644 index 0000000..834972a Binary files /dev/null and b/App/assets/img/glossar/mont-blanc-tunnel.webp differ diff --git a/App/assets/img/glossar/myoglobin.webp b/App/assets/img/glossar/myoglobin.webp new file mode 100644 index 0000000..dcd6b09 Binary files /dev/null and b/App/assets/img/glossar/myoglobin.webp differ diff --git a/App/assets/img/glossar/nachtzug.webp b/App/assets/img/glossar/nachtzug.webp new file mode 100644 index 0000000..33c6b60 Binary files /dev/null and b/App/assets/img/glossar/nachtzug.webp differ diff --git a/App/assets/img/glossar/netzbetreiber.webp b/App/assets/img/glossar/netzbetreiber.webp new file mode 100644 index 0000000..50ff45c Binary files /dev/null and b/App/assets/img/glossar/netzbetreiber.webp differ diff --git a/App/assets/img/glossar/netzfrequenz.webp b/App/assets/img/glossar/netzfrequenz.webp new file mode 100644 index 0000000..2426750 Binary files /dev/null and b/App/assets/img/glossar/netzfrequenz.webp differ diff --git a/App/assets/img/glossar/nicht-co2-effekte.webp b/App/assets/img/glossar/nicht-co2-effekte.webp new file mode 100644 index 0000000..ce8005f Binary files /dev/null and b/App/assets/img/glossar/nicht-co2-effekte.webp differ diff --git a/App/assets/img/glossar/norroena-faehre.webp b/App/assets/img/glossar/norroena-faehre.webp new file mode 100644 index 0000000..41f5b29 Binary files /dev/null and b/App/assets/img/glossar/norroena-faehre.webp differ diff --git a/App/assets/img/glossar/notruf.webp b/App/assets/img/glossar/notruf.webp new file mode 100644 index 0000000..9b9da04 Binary files /dev/null and b/App/assets/img/glossar/notruf.webp differ diff --git a/App/assets/img/glossar/obsidian.webp b/App/assets/img/glossar/obsidian.webp new file mode 100644 index 0000000..90348f5 Binary files /dev/null and b/App/assets/img/glossar/obsidian.webp differ diff --git a/App/assets/img/glossar/oeresundbruecke.webp b/App/assets/img/glossar/oeresundbruecke.webp new file mode 100644 index 0000000..df4e56c Binary files /dev/null and b/App/assets/img/glossar/oeresundbruecke.webp differ diff --git a/App/assets/img/glossar/off-season-import.webp b/App/assets/img/glossar/off-season-import.webp new file mode 100644 index 0000000..c210c94 Binary files /dev/null and b/App/assets/img/glossar/off-season-import.webp differ diff --git a/App/assets/img/glossar/pegel.webp b/App/assets/img/glossar/pegel.webp new file mode 100644 index 0000000..70315e3 Binary files /dev/null and b/App/assets/img/glossar/pegel.webp differ diff --git a/App/assets/img/glossar/pektoralflosse.webp b/App/assets/img/glossar/pektoralflosse.webp new file mode 100644 index 0000000..c37f333 Binary files /dev/null and b/App/assets/img/glossar/pektoralflosse.webp differ diff --git a/App/assets/img/glossar/personenkilometer.webp b/App/assets/img/glossar/personenkilometer.webp new file mode 100644 index 0000000..da0155e Binary files /dev/null and b/App/assets/img/glossar/personenkilometer.webp differ diff --git a/App/assets/img/glossar/photon.webp b/App/assets/img/glossar/photon.webp new file mode 100644 index 0000000..5ca2a48 Binary files /dev/null and b/App/assets/img/glossar/photon.webp differ diff --git a/App/assets/img/glossar/phreatomagmatisch.webp b/App/assets/img/glossar/phreatomagmatisch.webp new file mode 100644 index 0000000..17bf4fe Binary files /dev/null and b/App/assets/img/glossar/phreatomagmatisch.webp differ diff --git a/App/assets/img/glossar/planetenweg.webp b/App/assets/img/glossar/planetenweg.webp new file mode 100644 index 0000000..930e7dd Binary files /dev/null and b/App/assets/img/glossar/planetenweg.webp differ diff --git a/App/assets/img/glossar/plantage.webp b/App/assets/img/glossar/plantage.webp new file mode 100644 index 0000000..b8f43e9 Binary files /dev/null and b/App/assets/img/glossar/plantage.webp differ diff --git a/App/assets/img/glossar/plinianisch.webp b/App/assets/img/glossar/plinianisch.webp new file mode 100644 index 0000000..db6ce46 Binary files /dev/null and b/App/assets/img/glossar/plinianisch.webp differ diff --git a/App/assets/img/glossar/polarnacht.webp b/App/assets/img/glossar/polarnacht.webp new file mode 100644 index 0000000..fe72816 Binary files /dev/null and b/App/assets/img/glossar/polarnacht.webp differ diff --git a/App/assets/img/glossar/polartag.webp b/App/assets/img/glossar/polartag.webp new file mode 100644 index 0000000..2b2198c Binary files /dev/null and b/App/assets/img/glossar/polartag.webp differ diff --git a/App/assets/img/glossar/preiselastizitaet.webp b/App/assets/img/glossar/preiselastizitaet.webp new file mode 100644 index 0000000..a42c7b8 Binary files /dev/null and b/App/assets/img/glossar/preiselastizitaet.webp differ diff --git a/App/assets/img/glossar/pyroklastischer-strom.webp b/App/assets/img/glossar/pyroklastischer-strom.webp new file mode 100644 index 0000000..c85838e Binary files /dev/null and b/App/assets/img/glossar/pyroklastischer-strom.webp differ diff --git a/App/assets/img/glossar/reisemotiv.webp b/App/assets/img/glossar/reisemotiv.webp new file mode 100644 index 0000000..95b8773 Binary files /dev/null and b/App/assets/img/glossar/reisemotiv.webp differ diff --git a/App/assets/img/glossar/restrisiko.webp b/App/assets/img/glossar/restrisiko.webp new file mode 100644 index 0000000..3b4512b Binary files /dev/null and b/App/assets/img/glossar/restrisiko.webp differ diff --git a/App/assets/img/glossar/rollende-landstrasse.webp b/App/assets/img/glossar/rollende-landstrasse.webp new file mode 100644 index 0000000..e1d5f69 Binary files /dev/null and b/App/assets/img/glossar/rollende-landstrasse.webp differ diff --git a/App/assets/img/glossar/rueckhaltebecken.webp b/App/assets/img/glossar/rueckhaltebecken.webp new file mode 100644 index 0000000..ec96138 Binary files /dev/null and b/App/assets/img/glossar/rueckhaltebecken.webp differ diff --git a/App/assets/img/glossar/ruecklagen.webp b/App/assets/img/glossar/ruecklagen.webp new file mode 100644 index 0000000..34f266f Binary files /dev/null and b/App/assets/img/glossar/ruecklagen.webp differ diff --git a/App/assets/img/glossar/saisonal-regional.webp b/App/assets/img/glossar/saisonal-regional.webp new file mode 100644 index 0000000..59e4328 Binary files /dev/null and b/App/assets/img/glossar/saisonal-regional.webp differ diff --git a/App/assets/img/glossar/schildvulkan.webp b/App/assets/img/glossar/schildvulkan.webp new file mode 100644 index 0000000..815024f Binary files /dev/null and b/App/assets/img/glossar/schildvulkan.webp differ diff --git a/App/assets/img/glossar/schlot.webp b/App/assets/img/glossar/schlot.webp new file mode 100644 index 0000000..3be098d Binary files /dev/null and b/App/assets/img/glossar/schlot.webp differ diff --git a/App/assets/img/glossar/schwammstadt.webp b/App/assets/img/glossar/schwammstadt.webp new file mode 100644 index 0000000..7d9dec4 Binary files /dev/null and b/App/assets/img/glossar/schwammstadt.webp differ diff --git a/App/assets/img/glossar/selbstversorgungsgrad.webp b/App/assets/img/glossar/selbstversorgungsgrad.webp new file mode 100644 index 0000000..7065419 Binary files /dev/null and b/App/assets/img/glossar/selbstversorgungsgrad.webp differ diff --git a/App/assets/img/glossar/ship-strike.webp b/App/assets/img/glossar/ship-strike.webp new file mode 100644 index 0000000..1c3f64c Binary files /dev/null and b/App/assets/img/glossar/ship-strike.webp differ diff --git a/App/assets/img/glossar/skaleneffekt.webp b/App/assets/img/glossar/skaleneffekt.webp new file mode 100644 index 0000000..33cb8d6 Binary files /dev/null and b/App/assets/img/glossar/skaleneffekt.webp differ diff --git a/App/assets/img/glossar/stratovulkan.webp b/App/assets/img/glossar/stratovulkan.webp new file mode 100644 index 0000000..c8f73d3 Binary files /dev/null and b/App/assets/img/glossar/stratovulkan.webp differ diff --git a/App/assets/img/glossar/stromboerse.webp b/App/assets/img/glossar/stromboerse.webp new file mode 100644 index 0000000..de9155d Binary files /dev/null and b/App/assets/img/glossar/stromboerse.webp differ diff --git a/App/assets/img/glossar/strombolisch.webp b/App/assets/img/glossar/strombolisch.webp new file mode 100644 index 0000000..77d9789 Binary files /dev/null and b/App/assets/img/glossar/strombolisch.webp differ diff --git a/App/assets/img/glossar/sturmflut.webp b/App/assets/img/glossar/sturmflut.webp new file mode 100644 index 0000000..8d98b8b Binary files /dev/null and b/App/assets/img/glossar/sturmflut.webp differ diff --git a/App/assets/img/glossar/subduktionszone.webp b/App/assets/img/glossar/subduktionszone.webp new file mode 100644 index 0000000..15ecec5 Binary files /dev/null and b/App/assets/img/glossar/subduktionszone.webp differ diff --git a/App/assets/img/glossar/subsidiaritaet.webp b/App/assets/img/glossar/subsidiaritaet.webp new file mode 100644 index 0000000..0d7fa6b Binary files /dev/null and b/App/assets/img/glossar/subsidiaritaet.webp differ diff --git a/App/assets/img/glossar/tagesgast.webp b/App/assets/img/glossar/tagesgast.webp new file mode 100644 index 0000000..2257843 Binary files /dev/null and b/App/assets/img/glossar/tagesgast.webp differ diff --git a/App/assets/img/glossar/tephra.webp b/App/assets/img/glossar/tephra.webp new file mode 100644 index 0000000..4e3309e Binary files /dev/null and b/App/assets/img/glossar/tephra.webp differ diff --git a/App/assets/img/glossar/tourismusarten.webp b/App/assets/img/glossar/tourismusarten.webp new file mode 100644 index 0000000..8fb9363 Binary files /dev/null and b/App/assets/img/glossar/tourismusarten.webp differ diff --git a/App/assets/img/glossar/transitverkehr.webp b/App/assets/img/glossar/transitverkehr.webp new file mode 100644 index 0000000..24626e1 Binary files /dev/null and b/App/assets/img/glossar/transitverkehr.webp differ diff --git a/App/assets/img/glossar/transparenzregister.webp b/App/assets/img/glossar/transparenzregister.webp new file mode 100644 index 0000000..86a5764 Binary files /dev/null and b/App/assets/img/glossar/transparenzregister.webp differ diff --git a/App/assets/img/glossar/trilog.webp b/App/assets/img/glossar/trilog.webp new file mode 100644 index 0000000..1f60111 Binary files /dev/null and b/App/assets/img/glossar/trilog.webp differ diff --git a/App/assets/img/glossar/tss.webp b/App/assets/img/glossar/tss.webp new file mode 100644 index 0000000..7d562e8 Binary files /dev/null and b/App/assets/img/glossar/tss.webp differ diff --git a/App/assets/img/glossar/tubercles.webp b/App/assets/img/glossar/tubercles.webp new file mode 100644 index 0000000..8f80e09 Binary files /dev/null and b/App/assets/img/glossar/tubercles.webp differ diff --git a/App/assets/img/glossar/vegetationsperiode.webp b/App/assets/img/glossar/vegetationsperiode.webp new file mode 100644 index 0000000..9faf587 Binary files /dev/null and b/App/assets/img/glossar/vegetationsperiode.webp differ diff --git a/App/assets/img/glossar/vei.webp b/App/assets/img/glossar/vei.webp new file mode 100644 index 0000000..3e4432e Binary files /dev/null and b/App/assets/img/glossar/vei.webp differ diff --git a/App/assets/img/glossar/verbundnetz.webp b/App/assets/img/glossar/verbundnetz.webp new file mode 100644 index 0000000..ea1e34a Binary files /dev/null and b/App/assets/img/glossar/verbundnetz.webp differ diff --git a/App/assets/img/glossar/versalzung.webp b/App/assets/img/glossar/versalzung.webp new file mode 100644 index 0000000..031e9d9 Binary files /dev/null and b/App/assets/img/glossar/versalzung.webp differ diff --git a/App/assets/img/glossar/viskositaet.webp b/App/assets/img/glossar/viskositaet.webp new file mode 100644 index 0000000..04a8df3 Binary files /dev/null and b/App/assets/img/glossar/viskositaet.webp differ diff --git a/App/assets/img/glossar/vogelschlag.webp b/App/assets/img/glossar/vogelschlag.webp new file mode 100644 index 0000000..42b492e Binary files /dev/null and b/App/assets/img/glossar/vogelschlag.webp differ diff --git a/App/assets/img/glossar/vulkanasche.webp b/App/assets/img/glossar/vulkanasche.webp new file mode 100644 index 0000000..d1ab2a8 Binary files /dev/null and b/App/assets/img/glossar/vulkanasche.webp differ diff --git a/App/assets/img/glossar/waermeausdehnung.webp b/App/assets/img/glossar/waermeausdehnung.webp new file mode 100644 index 0000000..49f05db Binary files /dev/null and b/App/assets/img/glossar/waermeausdehnung.webp differ diff --git a/App/assets/img/glossar/waldgrenze.webp b/App/assets/img/glossar/waldgrenze.webp new file mode 100644 index 0000000..96904ad Binary files /dev/null and b/App/assets/img/glossar/waldgrenze.webp differ diff --git a/App/assets/img/glossar/walgesang.webp b/App/assets/img/glossar/walgesang.webp new file mode 100644 index 0000000..395c019 Binary files /dev/null and b/App/assets/img/glossar/walgesang.webp differ diff --git a/App/assets/img/glossar/welternaehrung.webp b/App/assets/img/glossar/welternaehrung.webp new file mode 100644 index 0000000..17535fd Binary files /dev/null and b/App/assets/img/glossar/welternaehrung.webp differ diff --git a/App/assets/img/glossar/welternte.webp b/App/assets/img/glossar/welternte.webp new file mode 100644 index 0000000..b817613 Binary files /dev/null and b/App/assets/img/glossar/welternte.webp differ diff --git a/App/assets/img/glossar/welthandel.webp b/App/assets/img/glossar/welthandel.webp new file mode 100644 index 0000000..2e778c3 Binary files /dev/null and b/App/assets/img/glossar/welthandel.webp differ diff --git a/App/assets/img/glossar/wertschoepfungskette.webp b/App/assets/img/glossar/wertschoepfungskette.webp new file mode 100644 index 0000000..eb7cfc9 Binary files /dev/null and b/App/assets/img/glossar/wertschoepfungskette.webp differ diff --git a/App/assets/img/glossar/windrose.webp b/App/assets/img/glossar/windrose.webp new file mode 100644 index 0000000..64b76a8 Binary files /dev/null and b/App/assets/img/glossar/windrose.webp differ diff --git a/App/assets/img/glossar/zeitzone.webp b/App/assets/img/glossar/zeitzone.webp new file mode 100644 index 0000000..327dc7d Binary files /dev/null and b/App/assets/img/glossar/zeitzone.webp differ diff --git a/App/assets/img/glossar/zenit.webp b/App/assets/img/glossar/zenit.webp new file mode 100644 index 0000000..1eb4b71 Binary files /dev/null and b/App/assets/img/glossar/zenit.webp differ diff --git a/App/assets/img/glossar/zielkonflikt.webp b/App/assets/img/glossar/zielkonflikt.webp new file mode 100644 index 0000000..71203ba Binary files /dev/null and b/App/assets/img/glossar/zielkonflikt.webp differ diff --git a/App/assets/img/glossar/zollunion.webp b/App/assets/img/glossar/zollunion.webp new file mode 100644 index 0000000..ea334db Binary files /dev/null and b/App/assets/img/glossar/zollunion.webp differ diff --git a/App/assets/js/glossar-experiments-natur.js b/App/assets/js/glossar-experiments-natur.js new file mode 100644 index 0000000..97e7f92 --- /dev/null +++ b/App/assets/js/glossar-experiments-natur.js @@ -0,0 +1,812 @@ +/** + * Glossar-Experimente „Natur" — Astronomie, Klima, Hochwasser. + * + * Registrierung wie in glossar-experiments.js: + * window.GlossarExperiments[key_slug] = function (root) { … } + * Der Renderer (glossar.php) übergibt einen leeren Container; das Widget + * baut seinen DOM selbst und bindet seine Events. Styles: .ge-* aus glossar.php. + * + * Richtlinien: + * - Keine externen Libraries, Vanilla JS + SVG. + * - Mobile-/Tap-freundlich, keine Hover-Abhängigkeit. + * - Zahlen mit kurzer Quellenangabe in der .ge-note. + * - Animations-Loops stoppen selbst, sobald der Container aus dem DOM fällt + * (root.isConnected), damit kein Loop nach Modal-Schließen weiterläuft. + */ + +(function () { + 'use strict'; + + const NS = 'http://www.w3.org/2000/svg'; + const svgEl = (tag, attrs, parent) => { + const el = document.createElementNS(NS, tag); + if (attrs) for (const k in attrs) el.setAttribute(k, attrs[k]); + if (parent) parent.appendChild(el); + return el; + }; + const fmtDE = (n, dec) => n.toFixed(dec === undefined ? 1 : dec).replace('.', ','); + + // ===================================================================== + // Experiment: Gebundene Rotation — warum wir immer dieselbe Mondseite sehen + // ===================================================================== + function tidalLock(root) { + root.innerHTML = ` +
+
+

🌗 Warum sehen wir immer dieselbe Mondseite?

+

Der Mond umkreist die Erde. Seine rot markierte Hälfte zeigt dir, wie er sich dabei um sich selbst dreht. Schalte um und vergleiche!

+
+ +
+ + + +
+
+
+
+
+

Der Mond dreht sich in 27,3 Tagen genau einmal um sich selbst — exakt so lange, wie er für einen Umlauf um die Erde braucht. Diese „gebundene Rotation" entstand durch die Gezeitenkräfte der Erde. Quelle: NASA Moon Fact Sheet (siderische Rotation = siderischer Umlauf = 27,32 Tage).

+
+ `; + const svg = root.querySelector('.ge-track'); + const insightEl = root.querySelector('[data-ref="insight"]'); + const viewEl = root.querySelector('[data-ref="view"]'); + const playBtn = root.querySelector('[data-act="play"]'); + + const CX = 300, CY = 172, ORBIT_R = 118, MOON_R = 16; + + // Weltall-Hintergrund + Sterne + svgEl('rect', { x: 0, y: 0, width: 600, height: 340, fill: '#152430', rx: 8 }, svg); + for (let i = 0; i < 40; i++) { + svgEl('circle', { + cx: Math.round(Math.random() * 590 + 5), + cy: Math.round(Math.random() * 330 + 5), + r: (Math.random() * 1.2 + 0.4).toFixed(1), + fill: '#dae8ec', opacity: (0.3 + Math.random() * 0.5).toFixed(2) + }, svg); + } + // Mondbahn + svgEl('circle', { cx: CX, cy: CY, r: ORBIT_R, fill: 'none', stroke: '#4a7c8a', 'stroke-width': '1', 'stroke-dasharray': '4 5', opacity: '.7' }, svg); + // Erde + svgEl('circle', { cx: CX, cy: CY, r: 30, fill: '#2e6b8a' }, svg); + svgEl('circle', { cx: CX - 8, cy: CY - 6, r: 10, fill: '#5a8a5e', opacity: '.9' }, svg); + svgEl('circle', { cx: CX + 10, cy: CY + 9, r: 7, fill: '#5a8a5e', opacity: '.9' }, svg); + const earthLabel = svgEl('text', { x: CX, y: CY + 48, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '700', fill: '#dae8ec' }, svg); + earthLabel.textContent = 'Erde'; + // Sichtlinie Erde → Mond + const sight = svgEl('line', { x1: CX, y1: CY, x2: CX + ORBIT_R, y2: CY, stroke: '#e8c547', 'stroke-width': '1', 'stroke-dasharray': '2 4', opacity: '.6' }, svg); + // Mond: Gruppe mit heller + rot markierter Hälfte (markierte Hälfte zeigt lokal nach +x) + const moonG = svgEl('g', {}, svg); + svgEl('circle', { cx: 0, cy: 0, r: MOON_R, fill: '#cfc9bc', stroke: '#8a857a', 'stroke-width': '1' }, moonG); + svgEl('path', { d: `M 0 ${-MOON_R} A ${MOON_R} ${MOON_R} 0 0 1 0 ${MOON_R} Z`, fill: '#c85c4a' }, moonG); + // Tag-Zähler + const dayLabel = svgEl('text', { x: 590, y: 24, 'text-anchor': 'end', 'font-size': '12', 'font-weight': '700', fill: '#dae8ec' }, svg); + + const PERIOD_DAYS = 27.3; + const ORBIT_MS = 12000; // 1 Umlauf in 12 s + let mode = 'locked'; + let playing = true; + let angle = -Math.PI / 2; // Start oben + let last = null; + let lastViewTxt = ''; + + function insightText() { + return mode === 'locked' + ? '🔒 Rotation = Umlauf: Die rote Seite zeigt immer zur Erde. Deshalb sehen wir die Mond-Rückseite nie.' + : '🔓 Ohne Eigendrehung: Die rote Seite zeigt mal zur Erde, mal weg — wir würden im Lauf eines Monats den ganzen Mond sehen.'; + } + function applyMode(m) { + mode = m; + root.querySelectorAll('[data-mode]').forEach(b => b.classList.toggle('ge-btn-primary', b.dataset.mode === m)); + insightEl.textContent = insightText(); + insightEl.dataset.state = m === 'locked' ? 'good' : 'warn'; + } + function draw() { + const mx = CX + Math.cos(angle) * ORBIT_R; + const my = CY + Math.sin(angle) * ORBIT_R; + const aDeg = angle * 180 / Math.PI; + const rot = mode === 'locked' ? aDeg + 180 : 0; + moonG.setAttribute('transform', `translate(${mx.toFixed(1)} ${my.toFixed(1)}) rotate(${rot.toFixed(1)})`); + sight.setAttribute('x2', mx.toFixed(1)); + sight.setAttribute('y2', my.toFixed(1)); + const day = ((angle + Math.PI / 2) / (2 * Math.PI)) * PERIOD_DAYS; + const dayShown = ((day % PERIOD_DAYS) + PERIOD_DAYS) % PERIOD_DAYS; + dayLabel.textContent = 'Tag ' + fmtDE(dayShown, 0) + ' von 27,3'; + // Was sieht man von der Erde aus? Winkel zwischen markierter Richtung und Richtung Mond→Erde + const toEarth = aDeg + 180; + let diff = ((rot - toEarth) % 360 + 360) % 360; + if (diff > 180) diff = 360 - diff; + const txt = diff < 90 + ? '👁 Von der Erde aus sichtbar: die rote Seite' + : '👁 Von der Erde aus sichtbar: die Rückseite'; + if (txt !== lastViewTxt) { viewEl.textContent = txt; lastViewTxt = txt; } + } + function tick(now) { + if (!root.isConnected) return; // Modal geschlossen → Loop beenden + if (playing) { + if (last !== null) angle += ((now - last) / ORBIT_MS) * 2 * Math.PI; + draw(); + } + last = now; + requestAnimationFrame(tick); + } + playBtn.addEventListener('click', () => { + playing = !playing; + playBtn.textContent = playing ? '⏸ Pause' : '▶ Weiter'; + }); + root.querySelectorAll('[data-mode]').forEach(b => { + b.addEventListener('click', () => { applyMode(b.dataset.mode); draw(); }); + }); + applyMode('locked'); + draw(); + requestAnimationFrame(tick); + } + + // ===================================================================== + // Experiment: Kernschatten — Mond durch den Erdschatten schieben + // ===================================================================== + function umbraCones(root) { + root.innerHTML = ` +
+
+

🌑 Schiebe den Mond durch den Erdschatten

+

Die Sonne beleuchtet die Erde — dahinter entstehen Kernschatten (ganz dunkel) und Halbschatten (teilweise dunkel). Bewege den Mond mit dem Regler auf seiner Bahn.

+
+ +
+ + +
oberhalbmitten im Schattenunterhalb
+
+
+
+
+

Größen und Abstände sind nicht maßstäblich. Real ist der Kernschatten der Erde in Mondentfernung rund 9.000 km breit — etwa 2,6 Mond-Durchmesser. Bei einer totalen Mondfinsternis leuchtet der Mond rötlich („Blutmond"), weil die Erdatmosphäre rotes Sonnenlicht in den Schatten lenkt. Weil die Mondbahn um 5° geneigt ist, verfehlt der Mond den Schatten meistens — darum gibt es nicht jeden Vollmond eine Finsternis. Quelle: NASA Eclipse Web Site (F. Espenak).

+
+ `; + const svg = root.querySelector('.ge-track'); + const rng = root.querySelector('#ge-umbra-range'); + const verdict = root.querySelector('[data-ref="verdict"]'); + + // Geometrie-Konstanten (Zeichnung und Klassifikation nutzen dieselben Werte) + const SUN = { x: 60, y: 160, r: 32 }; + const EARTH = { x: 280, y: 160, r: 24 }; + const MOON_X = 460, MOON_R = 7; + const D = EARTH.x - SUN.x; + // Kernschatten-Grenze: Linie von Sonnen-Oberkante durch Erd-Oberkante + const mU = (EARTH.r - SUN.r) / D * -1; // Steigung der oberen Umbra-Grenze relativ zur Achse + // Halbschatten-Grenze: Linie von Sonnen-Unterkante durch Erd-Oberkante + const mP = (SUN.r + EARTH.r) / D; + const hU = x => Math.max(0, EARTH.r - mU * (x - EARTH.x)); // halbe Kernschatten-Höhe bei x + const hP = x => EARTH.r + mP * (x - EARTH.x); // halbe Halbschatten-Höhe bei x + + // Weltall + Sterne + svgEl('rect', { x: 0, y: 0, width: 600, height: 320, fill: '#152430', rx: 8 }, svg); + for (let i = 0; i < 30; i++) { + svgEl('circle', { + cx: Math.round(Math.random() * 590 + 5), cy: Math.round(Math.random() * 310 + 5), + r: (Math.random() * 1.1 + 0.4).toFixed(1), fill: '#dae8ec', opacity: (0.3 + Math.random() * 0.5).toFixed(2) + }, svg); + } + // Halbschatten-Polygon (heller), dann Kernschatten (dunkler) darüber + const X_END = 600; + svgEl('polygon', { + points: `${EARTH.x},${EARTH.y - EARTH.r} ${X_END},${EARTH.y - hP(X_END)} ${X_END},${EARTH.y + hP(X_END)} ${EARTH.x},${EARTH.y + EARTH.r}`, + fill: '#4a5a66', opacity: '.35' + }, svg); + svgEl('polygon', { + points: `${EARTH.x},${EARTH.y - EARTH.r} ${X_END},${EARTH.y - hU(X_END)} ${X_END},${EARTH.y + hU(X_END)} ${EARTH.x},${EARTH.y + EARTH.r}`, + fill: '#0c151c', opacity: '.8' + }, svg); + // Beschriftung der Schattenzonen + const lblU = svgEl('text', { x: 520, y: EARTH.y + 4, 'text-anchor': 'middle', 'font-size': '10', 'font-weight': '700', fill: '#8aa4b0' }, svg); + lblU.textContent = 'Kernschatten'; + const lblP = svgEl('text', { x: 520, y: EARTH.y - hP(520) - 6, 'text-anchor': 'middle', 'font-size': '10', fill: '#8aa4b0' }, svg); + lblP.textContent = 'Halbschatten'; + // Sonne mit Strahlenkranz + svgEl('circle', { cx: SUN.x, cy: SUN.y, r: SUN.r + 8, fill: '#f4c94e', opacity: '.25' }, svg); + svgEl('circle', { cx: SUN.x, cy: SUN.y, r: SUN.r, fill: '#f4c94e' }, svg); + const sunLbl = svgEl('text', { x: SUN.x, y: SUN.y + SUN.r + 18, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '700', fill: '#f4c94e' }, svg); + sunLbl.textContent = 'Sonne'; + // Erde + svgEl('circle', { cx: EARTH.x, cy: EARTH.y, r: EARTH.r, fill: '#2e6b8a' }, svg); + svgEl('circle', { cx: EARTH.x - 6, cy: EARTH.y - 5, r: 8, fill: '#5a8a5e', opacity: '.9' }, svg); + // Nachtseite der Erde + svgEl('path', { d: `M ${EARTH.x} ${EARTH.y - EARTH.r} A ${EARTH.r} ${EARTH.r} 0 0 1 ${EARTH.x} ${EARTH.y + EARTH.r} Z`, fill: '#0c151c', opacity: '.55' }, svg); + const earthLbl = svgEl('text', { x: EARTH.x, y: EARTH.y + EARTH.r + 18, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '700', fill: '#dae8ec' }, svg); + earthLbl.textContent = 'Erde'; + // Mondbahn (angedeutet, senkrecht) + svgEl('line', { x1: MOON_X, y1: 30, x2: MOON_X, y2: 290, stroke: '#4a7c8a', 'stroke-width': '1', 'stroke-dasharray': '3 5', opacity: '.6' }, svg); + // Mond: Basis + Schatten-Halbscheibe + const moon = svgEl('circle', { cx: MOON_X, cy: 60, r: MOON_R, fill: '#cfc9bc', stroke: '#8a857a', 'stroke-width': '.8' }, svg); + const moonHalf = svgEl('path', { d: '', fill: '#241a16', opacity: '0' }, svg); + const moonLbl = svgEl('text', { x: MOON_X + 14, y: 64, 'font-size': '11', 'font-weight': '700', fill: '#dae8ec' }, svg); + moonLbl.textContent = 'Mond'; + + const HU = hU(MOON_X), HPn = hP(MOON_X); + function update() { + const yOff = +rng.value * 0.9; // Slider ±100 → ±90 px + const my = EARTH.y + yOff; + moon.setAttribute('cy', my.toFixed(1)); + moonLbl.setAttribute('y', (my + 4).toFixed(1)); + const a = Math.abs(yOff); + let state, txt, fill, halfOp = 0; + if (a + MOON_R <= HU) { + state = 'bad'; txt = '🔴 Totale Mondfinsternis — der Mond steht ganz im Kernschatten (Blutmond)'; + fill = '#a63c2a'; + } else if (a - MOON_R < HU) { + state = 'warn'; txt = '🟠 Partielle Mondfinsternis — nur ein Teil des Mondes taucht in den Kernschatten'; + fill = '#cfc9bc'; halfOp = 0.85; + } else if (a - MOON_R < HPn) { + state = 'now'; txt = '🌫 Halbschattenfinsternis — der Mond wird nur leicht dunkler, mit freiem Auge kaum sichtbar'; + fill = '#a8a397'; + } else { + state = 'good'; txt = '🌕 Keine Finsternis — der Mond verfehlt den Erdschatten (der Normalfall)'; + fill = '#cfc9bc'; + } + moon.setAttribute('fill', fill); + // Bei partieller Finsternis: die dem Schattenzentrum zugewandte Hälfte verdunkeln + if (halfOp > 0) { + const sweep = yOff > 0 ? 0 : 1; // Mond unterhalb → obere Hälfte im Schatten + moonHalf.setAttribute('d', `M ${MOON_X - MOON_R} ${my.toFixed(1)} A ${MOON_R} ${MOON_R} 0 0 ${sweep} ${MOON_X + MOON_R} ${my.toFixed(1)} Z`); + } + moonHalf.setAttribute('opacity', halfOp); + verdict.textContent = txt; + verdict.dataset.state = state; + } + rng.addEventListener('input', update); + update(); + } + + // ===================================================================== + // Experiment: Keeling-Kurve — CO₂-Messung 1958 bis heute, animiert + // ===================================================================== + function keelingCurve(root) { + root.innerHTML = ` +
+
+

📈 Die Keeling-Kurve zeichnet sich selbst

+

Seit 1958 wird auf dem Vulkan Mauna Loa (Hawaii) die CO₂-Konzentration gemessen. Starte die Aufzeichnung — an wichtigen Stellen hält die Kurve an.

+
+ +
+ + +
+
+ + +
+

Kurve vereinfacht nachgebildet: Jahresmittel von 315 ppm (1958) auf rund 430 ppm (2025), Sägezahn ±3 ppm durch die Jahreszeiten der Nordhalbkugel. Quelle: Scripps CO₂ Program / NOAA Global Monitoring Laboratory, Mauna Loa.

+
+ `; + const svg = root.querySelector('.ge-track'); + const playBtn = root.querySelector('[data-act="play"]'); + const nextBtn = root.querySelector('[data-act="next"]'); + const milestoneEl = root.querySelector('[data-ref="milestone"]'); + const seasonEl = root.querySelector('[data-ref="season"]'); + + // Plot-Geometrie + const X0 = 62, X1 = 580, Y0 = 275, Y1 = 30; + const YEAR0 = 1958, YEAR1 = 2025.5, PPM0 = 300, PPM1 = 445; + const xOf = year => X0 + (year - YEAR0) / (YEAR1 - YEAR0) * (X1 - X0); + const yOf = ppm => Y0 - (ppm - PPM0) / (PPM1 - PPM0) * (Y0 - Y1); + // Vereinfachtes Kurvenmodell (an Scripps/NOAA-Jahresmittel angelehnt) + const ppmAt = year => { + const t = year - 1958; + const annual = 315 + 0.55 * t + 0.0175 * t * t; + const frac = year - Math.floor(year); + return annual + 3.0 * Math.cos(2 * Math.PI * (frac - 0.30)); + }; + + // Achsen + Gitter + [320, 360, 400, 440].forEach(p => { + svgEl('line', { x1: X0, y1: yOf(p), x2: X1, y2: yOf(p), stroke: '#dae8ec', 'stroke-width': '1' }, svg); + const t = svgEl('text', { x: X0 - 6, y: yOf(p) + 4, 'text-anchor': 'end', 'font-size': '10', fill: '#4a4a4a' }, svg); + t.textContent = p; + }); + const yTitle = svgEl('text', { x: X0 - 6, y: Y1 - 8, 'text-anchor': 'end', 'font-size': '10', 'font-weight': '700', fill: '#4a4a4a' }, svg); + yTitle.textContent = 'ppm'; + [1960, 1980, 2000, 2020].forEach(yr => { + svgEl('line', { x1: xOf(yr), y1: Y0, x2: xOf(yr), y2: Y0 + 5, stroke: '#4a4a4a', 'stroke-width': '1' }, svg); + const t = svgEl('text', { x: xOf(yr), y: Y0 + 18, 'text-anchor': 'middle', 'font-size': '10', fill: '#4a4a4a' }, svg); + t.textContent = yr; + }); + svgEl('line', { x1: X0, y1: Y0, x2: X1, y2: Y0, stroke: '#1f4e5a', 'stroke-width': '1.2' }, svg); + svgEl('line', { x1: X0, y1: Y0, x2: X0, y2: Y1, stroke: '#1f4e5a', 'stroke-width': '1.2' }, svg); + + // Datenpunkte (monatlich) + const pts = []; + for (let y = YEAR0; y <= YEAR1; y += 1 / 12) { + pts.push({ year: y, ppm: ppmAt(y), x: xOf(y), y: yOf(ppmAt(y)) }); + } + const line = svgEl('polyline', { points: '', fill: 'none', stroke: '#c85c4a', 'stroke-width': '2', 'stroke-linejoin': 'round' }, svg); + const head = svgEl('circle', { cx: X0, cy: yOf(315), r: 4, fill: '#c85c4a', opacity: '0' }, svg); + const readout = svgEl('text', { x: X1, y: Y1 + 4, 'text-anchor': 'end', 'font-size': '13', 'font-weight': '800', fill: '#1f4e5a' }, svg); + const markerG = svgEl('g', {}, svg); + + const milestones = [ + { year: 1968, txt: '🌲 Der Sägezahn ist die „Atmung" der Vegetation: Jeden Nordsommer nimmt sie CO₂ auf (Kurve sinkt), jeden Winter gibt sie es wieder ab (Kurve steigt).' }, + { year: 1990, txt: '📋 Um 354 ppm — der erste IPCC-Bericht (1990) warnt vor der Erwärmung. Die Kurve steigt immer schneller.' }, + { year: 2015, txt: '🌍 400 ppm überschritten — im Jahr des Pariser Klimaabkommens. So viel CO₂ war seit Millionen Jahren nicht in der Luft.' }, + { year: 2025.4, txt: '🏁 Heute: rund 430 ppm — gut ein Drittel mehr als 1958. Der Sägezahn bleibt, der Anstieg leider auch.' } + ]; + let idx = 0, state = 'idle', ptStrings = [], msIdx = 0; + + function showMilestone(m) { + state = 'paused'; + milestoneEl.textContent = m.txt; + milestoneEl.style.display = ''; + milestoneEl.dataset.state = 'now'; + nextBtn.disabled = false; + nextBtn.classList.add('ge-btn-primary'); + svgEl('circle', { cx: xOf(m.year), cy: yOf(ppmAt(m.year)), r: 5, fill: 'none', stroke: '#1f4e5a', 'stroke-width': '2' }, markerG); + } + function updateSeason() { + if (idx < 3) return; + const rising = pts[idx - 1].ppm > pts[idx - 3].ppm; + seasonEl.style.display = ''; + seasonEl.dataset.state = rising ? 'warn' : 'good'; + seasonEl.textContent = rising + ? '🍂 Kurve steigt gerade: Nordwinter — Laub verrottet, wenig Photosynthese' + : '🌱 Kurve sinkt gerade: Nordsommer — die Vegetation nimmt CO₂ auf'; + } + function tick() { + if (!root.isConnected || state !== 'playing') return; + for (let s = 0; s < 2 && idx < pts.length; s++) { + const p = pts[idx++]; + ptStrings.push(p.x.toFixed(1) + ',' + p.y.toFixed(1)); + } + line.setAttribute('points', ptStrings.join(' ')); + const cur = pts[Math.min(idx, pts.length) - 1]; + head.setAttribute('cx', cur.x.toFixed(1)); + head.setAttribute('cy', cur.y.toFixed(1)); + head.setAttribute('opacity', '1'); + readout.textContent = Math.floor(cur.year) + ' · ' + fmtDE(cur.ppm, 0) + ' ppm'; + updateSeason(); + if (msIdx < milestones.length && cur.year >= milestones[msIdx].year) { + showMilestone(milestones[msIdx++]); + return; + } + if (idx >= pts.length) { state = 'done'; return; } + requestAnimationFrame(tick); + } + function start() { + idx = 0; msIdx = 0; ptStrings = []; + markerG.innerHTML = ''; + line.setAttribute('points', ''); + milestoneEl.style.display = 'none'; + seasonEl.style.display = 'none'; + nextBtn.disabled = true; + nextBtn.classList.remove('ge-btn-primary'); + playBtn.textContent = '↺ Von vorn'; + state = 'playing'; + requestAnimationFrame(tick); + } + function resume() { + if (state !== 'paused') return; + nextBtn.disabled = true; + nextBtn.classList.remove('ge-btn-primary'); + milestoneEl.style.display = 'none'; + if (idx >= pts.length) { state = 'done'; return; } + state = 'playing'; + requestAnimationFrame(tick); + } + playBtn.addEventListener('click', start); + nextBtn.addEventListener('click', resume); + } + + // ===================================================================== + // Experiment: Pegel / HQ100 — Regen aufdrehen, Pegel verzögert beobachten + // ===================================================================== + function riverGauge(root) { + root.innerHTML = ` +
+
+

🌧 Regen aufdrehen — was macht der Pegel?

+

Stelle die Regen-Intensität ein und beobachte die Pegellatte. Der Fluss reagiert verzögert — genau wie in echt.

+
+ +
+ + +
trockenLandregenStarkregenExtremereignis
+
+
+
+
+
+

HQ30 / HQ100 = Hochwasser, das im langjährigen Mittel statistisch einmal in 30 bzw. 100 Jahren erreicht oder überschritten wird (Quelle: eHYD, BML Österreich). Die Marken hier sind Beispielwerte — jeder echte Pegel hat eigene Grenzwerte. Die Verzögerung entsteht, weil Regen erst durch Boden, Bäche und Zuflüsse wandern muss, bis er am Pegel ankommt.

+
+ `; + const svg = root.querySelector('.ge-track'); + const rng = root.querySelector('#ge-rain-range'); + const rainValEl = root.querySelector('[data-ref="rainval"]'); + const levelEl = root.querySelector('[data-ref="level"]'); + const trendEl = root.querySelector('[data-ref="trend"]'); + + // cm → y (Flussbett bei y=290, 400 cm bei y=60) + const BED_Y = 290, CM_SCALE = (290 - 60) / 400; + const yOfCm = cm => BED_Y - cm * CM_SCALE; + const BANK_CM = 280; // Uferoberkante + const MARKS = [ + { cm: 220, label: 'Vorwarnstufe', color: '#e8c547' }, + { cm: 300, label: 'HQ30', color: '#e8833a' }, + { cm: 360, label: 'HQ100', color: '#c85c4a' } + ]; + + // Himmel + const sky = svgEl('rect', { x: 0, y: 0, width: 600, height: 320, fill: '#dae8ec', rx: 8 }, svg); + // Wasser (Polygon, dynamisch) + const water = svgEl('polygon', { points: '', fill: '#4a7c8a', opacity: '.85' }, svg); + const floodL = svgEl('rect', { x: 0, y: 0, width: 0, height: 0, fill: '#4a7c8a', opacity: '.7' }, svg); + const floodR = svgEl('rect', { x: 0, y: 0, width: 0, height: 0, fill: '#4a7c8a', opacity: '.7' }, svg); + // Ufer-Profil: links Flur — Böschung — Flussbett — Böschung — rechts Flur + const bankY = yOfCm(BANK_CM); // = 129 + svgEl('polygon', { points: `0,320 0,${bankY} 90,${bankY} 150,${BED_Y} 150,320`, fill: '#5a8a5e' }, svg); + svgEl('polygon', { points: `600,320 600,${bankY} 410,${bankY} 350,${BED_Y} 350,320`, fill: '#5a8a5e' }, svg); + svgEl('rect', { x: 150, y: BED_Y, width: 200, height: 30, fill: '#6b4a2e' }, svg); + // Wolke + Regen + const cloud = svgEl('g', {}, svg); + svgEl('ellipse', { cx: 150, cy: 42, rx: 46, ry: 20, fill: '#8aa4b0' }, cloud); + svgEl('ellipse', { cx: 195, cy: 50, rx: 38, ry: 17, fill: '#8aa4b0' }, cloud); + svgEl('ellipse', { cx: 110, cy: 52, rx: 32, ry: 15, fill: '#8aa4b0' }, cloud); + const rainG = svgEl('g', { stroke: '#4a7c8a', 'stroke-width': '2', 'stroke-linecap': 'round' }, svg); + // Marken-Linien über dem Wasserbereich + MARKS.forEach(m => { + const y = yOfCm(m.cm); + svgEl('line', { x1: 60, y1: y, x2: 470, y2: y, stroke: m.color, 'stroke-width': '2', 'stroke-dasharray': '6 4' }, svg); + const t = svgEl('text', { x: 478, y: y + 4, 'font-size': '11', 'font-weight': '800', fill: m.color }, svg); + t.textContent = m.label + ' · ' + m.cm + ' cm'; + }); + // Pegellatte + const LATTE_X = 430; + svgEl('rect', { x: LATTE_X - 7, y: yOfCm(400), width: 14, height: BED_Y - yOfCm(400), fill: '#fff', stroke: '#1f4e5a', 'stroke-width': '1.2', rx: 2 }, svg); + for (let cm = 0; cm <= 400; cm += 50) { + const w = cm % 100 === 0 ? 10 : 6; + svgEl('line', { x1: LATTE_X - 7, y1: yOfCm(cm), x2: LATTE_X - 7 + w, y2: yOfCm(cm), stroke: '#1f4e5a', 'stroke-width': '1' }, svg); + if (cm % 100 === 0 && cm > 0) { + const t = svgEl('text', { x: LATTE_X + 12, y: yOfCm(cm) + 3, 'font-size': '9', fill: '#1f4e5a' }, svg); + t.textContent = cm; + } + } + // Ablese-Pfeil an der Latte + const pointer = svgEl('polygon', { points: '', fill: '#1f4e5a' }, svg); + + // Böschungs-Geometrie fürs Wasser-Polygon + const slope = (BED_Y - bankY) / 60; // px pro px (150-90 bzw. 350-410) + function waterPoly(levelCm) { + const yW = yOfCm(Math.min(levelCm, BANK_CM)); + const lxx = 150 - (BED_Y - yW) / slope; + const rxx = 350 + (BED_Y - yW) / slope; + return `${lxx.toFixed(1)},${yW.toFixed(1)} ${rxx.toFixed(1)},${yW.toFixed(1)} 350,${BED_Y} 150,${BED_Y}`; + } + function drawRain(intensity) { + rainG.innerHTML = ''; + const n = Math.round(intensity / 7); + for (let i = 0; i < n; i++) { + const x = 80 + Math.random() * 150; + const y = 70 + Math.random() * 50; + svgEl('line', { x1: x, y1: y, x2: x - 3, y2: y + 12, opacity: '.8' }, rainG); + } + cloud.setAttribute('opacity', intensity > 0 ? 1 : 0.45); + sky.setAttribute('fill', intensity > 60 ? '#b8c9cf' : '#dae8ec'); + } + + let inflow = 10, level = 130, lastRedraw = 0; + function statusFor(cm) { + if (cm >= 360) return { s: 'bad', t: '🔴 HQ100 erreicht — Jahrhunderthochwasser' }; + if (cm >= 300) return { s: 'warn', t: '🟠 HQ30 überschritten — großes Hochwasser' }; + if (cm >= 220) return { s: 'now', t: '🟡 Vorwarnstufe überschritten' }; + return { s: 'good', t: '🟢 Normaler Wasserstand' }; + } + function tick() { + if (!root.isConnected) return; + const rain = +rng.value; + // Zweistufige Verzögerung: Boden/Zufluss-Speicher → Pegel + inflow += (rain - inflow) * 0.008; + const target = 100 + inflow * 3.0; + const before = level; + level += (target - level) * 0.015; + const cm = Math.max(0, Math.min(400, level)); + water.setAttribute('points', waterPoly(cm)); + // Ausuferung über die Uferkante + if (cm > BANK_CM) { + const h = (cm - BANK_CM) * CM_SCALE; + floodL.setAttribute('x', 0); floodL.setAttribute('y', bankY - h); + floodL.setAttribute('width', 150); floodL.setAttribute('height', h); + floodR.setAttribute('x', 350); floodR.setAttribute('y', bankY - h); + floodR.setAttribute('width', 250); floodR.setAttribute('height', h); + } else { + floodL.setAttribute('width', 0); floodL.setAttribute('height', 0); + floodR.setAttribute('width', 0); floodR.setAttribute('height', 0); + } + const y = yOfCm(cm); + pointer.setAttribute('points', `${LATTE_X - 22},${y - 5} ${LATTE_X - 22},${y + 5} ${LATTE_X - 10},${y}`); + // UI-Texte gedrosselt aktualisieren + const now = performance.now(); + if (now - lastRedraw > 180) { + lastRedraw = now; + const st = statusFor(cm); + levelEl.textContent = 'Pegel: ' + fmtDE(cm, 0) + ' cm — ' + st.t; + levelEl.dataset.state = st.s; + const d = level - before; + trendEl.textContent = d > 0.05 ? '↗ Pegel steigt (verzögert)' : d < -0.05 ? '↘ Pegel fällt (verzögert)' : '→ Pegel stabil'; + } + requestAnimationFrame(tick); + } + rng.addEventListener('input', () => { + rainValEl.textContent = rng.value; + drawRain(+rng.value); + }); + drawRain(+rng.value); + requestAnimationFrame(tick); + } + + // ===================================================================== + // Experiment: Wärmeausdehnung — wärmeres Meer braucht mehr Platz + // ===================================================================== + function thermalExpansion(root) { + root.innerHTML = ` +
+
+

🌡 Wärmeres Wasser braucht mehr Platz

+

Erwärme das Meer mit dem Regler. Der Meeresspiegel steigt hier allein durch die Ausdehnung des Wassers — noch ganz ohne Gletscherschmelze.

+
+ +
+ + +
heute+1 °C+2 °C+3 °C+4 °C
+
+
+
+
+
+

Vereinfachung: Auf lange Sicht dehnt sich das Meerwasser um rund 0,26 m je °C Erwärmung aus (Hieronymus 2019, Environ. Res. Lett. — Update zur IPCC-AR5-Schätzung von bis zu 0,42 m je °C nach Levermann et al. 2013). Schmelzwasser von Gletschern und Eisschilden kommt zusätzlich dazu. Darstellung stark überhöht.

+
+ `; + const svg = root.querySelector('.ge-gh-svg'); + const rng = root.querySelector('#ge-thx-range'); + const dtEl = root.querySelector('[data-ref="dt"]'); + const riseEl = root.querySelector('[data-ref="rise"]'); + const statusEl = root.querySelector('[data-ref="status"]'); + + const M_PER_DEG = 0.26; // m Anstieg je °C (nur Ausdehnung, Langfrist-Näherung) + const PX_PER_M = 45; // Überhöhung: 1 m = 45 px + const Y_SEA0 = 180; // heutiger Meeresspiegel + + // Strand-Profil: flaches Vorland links, Böschung nach rechts oben + const G0 = { x: 90, y: 236 }, G1 = { x: 600, y: 110 }; + const gSlope = (G0.y - G1.y) / (G1.x - G0.x); // px sinken je px nach rechts: 0.247 + const groundY = x => x <= G0.x ? 238 : G0.y - gSlope * (x - G0.x); + const shoreX = yW => G0.x + (G0.y - yW) / gSlope; + + // Boden + svgEl('polygon', { points: `0,300 0,240 ${G0.x},${G0.y} ${G1.x},${G1.y} 600,300`, fill: '#e8d5b5' }, svg); + // Referenz-Objekte am Strand (Höhe über heutigem Meer) + const refs = [ + { m: 0.3, label: 'Strandhütte', emoji: '🛖' }, + { m: 0.6, label: 'Strandweg', emoji: '🚏' }, + { m: 1.2, label: 'Haus an der Düne', emoji: '🏠' } + ]; + refs.forEach(r => { + const gy = Y_SEA0 - r.m * PX_PER_M; + const gx = shoreX(gy); + r.x = gx; r.groundY = gy; + const e = svgEl('text', { x: gx, y: gy - 4, 'text-anchor': 'middle', 'font-size': '22' }, svg); + e.textContent = r.emoji; + const t = svgEl('text', { x: gx, y: gy - 30, 'text-anchor': 'middle', 'font-size': '9', 'font-weight': '700', fill: '#4a4a4a' }, svg); + t.textContent = r.label + ' · +' + fmtDE(r.m, 1) + ' m'; + }); + // Wasser + const water = svgEl('polygon', { points: '', fill: '#4a7c8a', opacity: '.85' }, svg); + const waterLine = svgEl('line', { x1: 0, y1: Y_SEA0, x2: 0, y2: Y_SEA0, stroke: '#1f4e5a', 'stroke-width': '1.5' }, svg); + // Heutiger Meeresspiegel als Referenzlinie + svgEl('line', { x1: 0, y1: Y_SEA0, x2: shoreX(Y_SEA0) + 40, y2: Y_SEA0, stroke: '#1f4e5a', 'stroke-width': '1', 'stroke-dasharray': '5 4', opacity: '.7' }, svg); + const refLbl = svgEl('text', { x: 8, y: Y_SEA0 + 14, 'font-size': '9', fill: '#1f4e5a' }, svg); + refLbl.textContent = 'Meeresspiegel heute'; + // Maßstabs-Lineal links + [0, 0.5, 1].forEach(m => { + const y = Y_SEA0 - m * PX_PER_M; + svgEl('line', { x1: 30, y1: y, x2: 42, y2: y, stroke: '#1f4e5a', 'stroke-width': '1.5' }, svg); + const t = svgEl('text', { x: 46, y: y + 3, 'font-size': '9', fill: '#1f4e5a' }, svg); + t.textContent = m === 0 ? '±0' : '+' + fmtDE(m, 1) + ' m'; + }); + svgEl('line', { x1: 36, y1: Y_SEA0, x2: 36, y2: Y_SEA0 - PX_PER_M, stroke: '#1f4e5a', 'stroke-width': '1' }, svg); + // Wärme-Symbol im Wasser + const heat = svgEl('text', { x: 150, y: 250, 'text-anchor': 'middle', 'font-size': '18', opacity: '0' }, svg); + heat.textContent = '♨'; + + function update() { + const dT = +rng.value; + const riseM = M_PER_DEG * dT; + const yW = Y_SEA0 - riseM * PX_PER_M; + const xs = shoreX(yW); + water.setAttribute('points', `0,${yW.toFixed(1)} ${xs.toFixed(1)},${yW.toFixed(1)} ${G0.x},${G0.y} 0,240`); + waterLine.setAttribute('y1', yW.toFixed(1)); + waterLine.setAttribute('y2', yW.toFixed(1)); + waterLine.setAttribute('x2', xs.toFixed(1)); + heat.setAttribute('opacity', Math.min(1, dT / 2).toFixed(2)); + water.setAttribute('fill', dT > 2 ? '#5a7c8a' : '#4a7c8a'); + dtEl.textContent = '+' + fmtDE(dT, 1) + ' °C'; + riseEl.textContent = 'Anstieg nur durch Ausdehnung: +' + fmtDE(riseM, 2) + ' m (0,26 m · ' + fmtDE(dT, 1) + ')'; + riseEl.dataset.state = dT < 1 ? 'good' : dT < 2.5 ? 'warn' : 'bad'; + const flooded = refs.filter(r => r.groundY > yW).map(r => r.label); + if (flooded.length === 0) { statusEl.textContent = '🏖 Der Strand wird schmaler, alles bleibt trocken.'; statusEl.dataset.state = 'good'; } + else { statusEl.textContent = '🌊 Unter Wasser: ' + flooded.join(' und '); statusEl.dataset.state = flooded.length > 1 ? 'bad' : 'warn'; } + } + rng.addEventListener('input', update); + update(); + } + + // ===================================================================== + // Experiment: Klimaträgheit — nach Netto-Null geht es trotzdem weiter + // ===================================================================== + function climateInertia(root) { + root.innerHTML = ` +
+
+

🐌 Das Klima ist träge — teste es selbst

+

Lass die Zeit laufen und stelle die Emissionen ein. Drücke dann „Emissionen sofort auf null" — und beobachte, was Temperatur und Meeresspiegel trotzdem machen.

+
+ +
+ + +
+
+ + + +
+ +
+
Drücke ▶ Start, um die Zeit laufen zu lassen.
+
+

Vereinfachtes Anschauungs-Modell, keine Klimasimulation (relative Skalen). Kernaussage nach IPCC AR6 (WG1, Kap. 9): CO₂ bleibt Jahrhunderte in der Atmosphäre, die träge Tiefsee erwärmt sich nach — deshalb steigt der Meeresspiegel selbst bei Netto-Null-Emissionen noch über Jahrhunderte bis Jahrtausende weiter.

+
+ `; + const svg = root.querySelector('.ge-track'); + const rng = root.querySelector('#ge-inertia-range'); + const eValEl = root.querySelector('[data-ref="eval"]'); + const insightEl = root.querySelector('[data-ref="insight"]'); + const playBtn = root.querySelector('[data-act="play"]'); + const zeroBtn = root.querySelector('[data-act="zero"]'); + const resetBtn = root.querySelector('[data-act="reset"]'); + + // Plot-Geometrie + const X0 = 55, X1 = 580, Y_BASE = 280, Y_TOP = 30; + const T_END = 160; // Modell-Jahre + const xOf = yr => X0 + (yr / T_END) * (X1 - X0); + // Achsen + svgEl('line', { x1: X0, y1: Y_BASE, x2: X1, y2: Y_BASE, stroke: '#1f4e5a', 'stroke-width': '1.2' }, svg); + svgEl('line', { x1: X0, y1: Y_BASE, x2: X0, y2: Y_TOP, stroke: '#1f4e5a', 'stroke-width': '1.2' }, svg); + [0, 40, 80, 120, 160].forEach(yr => { + svgEl('line', { x1: xOf(yr), y1: Y_BASE, x2: xOf(yr), y2: Y_BASE + 5, stroke: '#4a4a4a', 'stroke-width': '1' }, svg); + const t = svgEl('text', { x: xOf(yr), y: Y_BASE + 18, 'text-anchor': 'middle', 'font-size': '10', fill: '#4a4a4a' }, svg); + t.textContent = 'Jahr ' + yr; + }); + const axisLbl = svgEl('text', { x: X0, y: Y_TOP - 8, 'font-size': '9', fill: '#4a4a4a' }, svg); + axisLbl.textContent = 'relative Skalen ↑'; + // Kurven + Netto-Null-Markierung + const lineE = svgEl('polyline', { points: '', fill: 'none', stroke: '#8a857a', 'stroke-width': '2' }, svg); + const lineT = svgEl('polyline', { points: '', fill: 'none', stroke: '#c85c4a', 'stroke-width': '2.5' }, svg); + const lineS = svgEl('polyline', { points: '', fill: 'none', stroke: '#4a7c8a', 'stroke-width': '2.5' }, svg); + const zeroMark = svgEl('g', { opacity: '0' }, svg); + const zeroLine = svgEl('line', { x1: 0, y1: Y_TOP, x2: 0, y2: Y_BASE, stroke: '#1f4e5a', 'stroke-width': '1.5', 'stroke-dasharray': '5 4' }, zeroMark); + const zeroTxt = svgEl('text', { x: 0, y: Y_TOP + 12, 'font-size': '10', 'font-weight': '800', fill: '#1f4e5a' }, zeroMark); + zeroTxt.textContent = 'Netto-Null'; + + // Skalen: E 0..1 → unteres Band, T 0..2 °C-Index, S 0..160 Einheiten + const yE = e => Y_BASE - e * 55; + const yT = t => Y_BASE - (t / 2.0) * 200; + const yS = s => Y_BASE - (s / 160) * 230; + + // Modell-Zustand + let sim, running = false; + function freshSim() { + return { year: 0, C: 0, T: 0, S: 0, zeroYear: null, pE: [], pT: [], pS: [], lastTxt: '' }; + } + sim = freshSim(); + + function setInsight(txt, state) { + if (txt === sim.lastTxt) return; + sim.lastTxt = txt; + insightEl.textContent = txt; + insightEl.dataset.state = state; + } + function step(dt) { + const E = +rng.value / 100; + // CO₂ reichert sich an, wird nur sehr langsam abgebaut (Ozeane, Verwitterung) + sim.C += (E * 0.012 - sim.C * 0.0015) * dt; + // Temperatur folgt der Gleichgewichts-Temperatur mit Jahrzehnte-Verzögerung + const Teq = sim.C * 1.6; + const dT = (Teq - sim.T) / 45; + sim.T += dT * dt; + // Meeresspiegel integriert die Erwärmung (Tiefsee + Eis reagieren am trägsten) + sim.S += Math.max(0, sim.T) * 0.85 * dt; + sim.year += dt; + return dT; + } + function pushPoints() { + const x = xOf(sim.year).toFixed(1); + sim.pE.push(x + ',' + yE(+rng.value / 100).toFixed(1)); + sim.pT.push(x + ',' + yT(sim.T).toFixed(1)); + sim.pS.push(x + ',' + yS(Math.min(sim.S, 160)).toFixed(1)); + lineE.setAttribute('points', sim.pE.join(' ')); + lineT.setAttribute('points', sim.pT.join(' ')); + lineS.setAttribute('points', sim.pS.join(' ')); + } + function tick() { + if (!root.isConnected || !running) return; + let dTLast = 0; + for (let i = 0; i < 2; i++) dTLast = step(0.15); + pushPoints(); + if (sim.zeroYear === null) { + setInsight('Solange emittiert wird, steigen CO₂, Temperatur und Meeresspiegel.', 'now'); + } else if (dTLast > 0.0015) { + setInsight('⚠ Emissionen sind null — die Temperatur steigt trotzdem noch weiter! Die Ozeane holen die Erwärmung erst nach.', 'warn'); + } else { + setInsight('Erst nach Jahrzehnten stabilisiert sich die Temperatur — der Meeresspiegel steigt sogar noch Jahrhunderte weiter. Das ist Klimaträgheit.', 'bad'); + } + if (sim.year >= T_END) { + running = false; + playBtn.textContent = '▶ Start'; + if (sim.zeroYear === null) { + setInsight('Zeit abgelaufen — probiere es noch einmal und drücke unterwegs „Emissionen sofort auf null".', 'now'); + } + return; + } + requestAnimationFrame(tick); + } + playBtn.addEventListener('click', () => { + if (running) { running = false; playBtn.textContent = '▶ Weiter'; return; } + if (sim.year >= T_END) { sim = freshSim(); zeroMark.setAttribute('opacity', '0'); rng.value = 80; eValEl.textContent = '80 %'; } + running = true; + playBtn.textContent = '⏸ Pause'; + requestAnimationFrame(tick); + }); + zeroBtn.addEventListener('click', () => { + rng.value = 0; + eValEl.textContent = '0 %'; + if (running && sim.zeroYear === null) { + sim.zeroYear = sim.year; + const x = xOf(sim.year); + zeroLine.setAttribute('x1', x.toFixed(1)); zeroLine.setAttribute('x2', x.toFixed(1)); + zeroTxt.setAttribute('x', (x > 480 ? x - 5 : x + 5).toFixed(1)); + zeroTxt.setAttribute('text-anchor', x > 480 ? 'end' : 'start'); + zeroMark.setAttribute('opacity', '1'); + } + }); + resetBtn.addEventListener('click', () => { + running = false; + sim = freshSim(); + lineE.setAttribute('points', ''); lineT.setAttribute('points', ''); lineS.setAttribute('points', ''); + zeroMark.setAttribute('opacity', '0'); + rng.value = 80; eValEl.textContent = '80 %'; + playBtn.textContent = '▶ Start'; + insightEl.textContent = 'Drücke ▶ Start, um die Zeit laufen zu lassen.'; + insightEl.dataset.state = 'now'; + sim.lastTxt = ''; + }); + rng.addEventListener('input', () => { eValEl.textContent = rng.value + ' %'; }); + } + + // Registry — Keys entsprechen key_slug aus der DB. + // pegel und hq100 teilen sich bewusst dasselbe Widget. + window.GlossarExperiments = Object.assign(window.GlossarExperiments || {}, { + 'gebundene-rotation': tidalLock, + 'kernschatten': umbraCones, + 'keeling-kurve': keelingCurve, + 'pegel': riverGauge, + 'hq100': riverGauge, + 'waermeausdehnung': thermalExpansion, + 'klimatraegheit': climateInertia + }); +})(); diff --git a/App/assets/js/glossar-experiments-wirtschaft.js b/App/assets/js/glossar-experiments-wirtschaft.js new file mode 100644 index 0000000..186aa75 --- /dev/null +++ b/App/assets/js/glossar-experiments-wirtschaft.js @@ -0,0 +1,741 @@ +/** + * Glossar-Experimente — Wirtschaft & Energie. + * + * Registrierung wie in glossar-experiments.js: + * window.GlossarExperiments[key_slug] = function (root) { … } + * Der Renderer (glossar.php) hängt einen leeren Container ein und ruft die + * Funktion mit diesem Container als einzigem Argument auf. + * + * Richtlinien: + * - Keine externen Libraries, Vanilla JS + SVG. + * - Mobile-/Tap-freundlich: grosse Buttons, keine Hover-Abhängigkeit. + * - Zahlen quellenbar, kurze Begründung in der UI sichtbar (.ge-note). + * - Rechenzeichen: Malpunkt · und Doppelpunkt : (nie ×, ÷, *). + */ + +(function () { + 'use strict'; + + const NS = 'http://www.w3.org/2000/svg'; + const svgEl = (tag, attrs, parent) => { + const el = document.createElementNS(NS, tag); + if (attrs) for (const k in attrs) el.setAttribute(k, attrs[k]); + if (parent) parent.appendChild(el); + return el; + }; + // Ganzzahl mit Tausenderpunkt: 56250 → "56.250" + const fmtInt = n => Math.round(n).toLocaleString('de-AT'); + // Dezimalzahl mit Komma: 22.5 → "22,50" (digits Nachkommastellen) + const fmtDec = (n, digits) => n.toLocaleString('de-AT', { + minimumFractionDigits: digits, maximumFractionDigits: digits + }); + + // ===================================================================== + // Experiment: Preiselastizität — der beste Skipass-Preis + // ===================================================================== + function priceElasticity(root) { + root.innerHTML = ` +
+
+

🎿 Finde den besten Skipass-Preis

+

Je teurer der Skipass, desto weniger Gäste kommen — die Nachfrage reagiert auf den Preis. + Der Umsatz ist Preis · Gäste. Wo ist er am größten?

+
+
+ + +
15 €30 €45 €60 €
+
+ +
+
Rechnung: 25 € · 2.000 Gäste = 50.000 €
+
+
+

Vereinfachtes lineares Modell wie in der Tourismustal-Simulation: + Gäste = 3.000 − 40 · Preis. Echte Nachfragekurven sind komplizierter, aber das Prinzip + der Preiselastizität gilt überall: Der höchste Preis bringt nicht automatisch den + höchsten Umsatz.

+
+ `; + const svg = root.querySelector('.ge-bal-svg'); + const rng = root.querySelector('#ge-pe-range'); + const priceOut = root.querySelector('#ge-pe-price'); + const calcOut = root.querySelector('#ge-pe-calc'); + const verdict = root.querySelector('#ge-pe-verdict'); + + const BAR_X = 120, BAR_W = 400; + const MAX_GUESTS = 2400, MAX_REV = 60000, BEST_REV = 56250; // Maximum bei 37,50 € + + // Zeile 1: Gäste + svgEl('text', { x: BAR_X - 10, y: 50, 'text-anchor': 'end', 'font-size': '13', 'font-weight': '700', fill: '#1f4e5a' }, svg).textContent = 'Gäste'; + svgEl('rect', { x: BAR_X, y: 32, width: BAR_W, height: 26, fill: '#eff5f6', rx: '6' }, svg); + const guestBar = svgEl('rect', { x: BAR_X, y: 32, width: 0, height: 26, fill: '#4a7c8a', rx: '6' }, svg); + const guestTxt = svgEl('text', { x: BAR_X, y: 50, 'font-size': '13', 'font-weight': '800', fill: '#1f4e5a' }, svg); + + // Zeile 2: Umsatz + svgEl('text', { x: BAR_X - 10, y: 118, 'text-anchor': 'end', 'font-size': '13', 'font-weight': '700', fill: '#1f4e5a' }, svg).textContent = 'Umsatz'; + svgEl('rect', { x: BAR_X, y: 100, width: BAR_W, height: 26, fill: '#eff5f6', rx: '6' }, svg); + const revBar = svgEl('rect', { x: BAR_X, y: 100, width: 0, height: 26, fill: '#5a8a5e', rx: '6' }, svg); + const revTxt = svgEl('text', { x: BAR_X, y: 118, 'font-size': '13', 'font-weight': '800', fill: '#1f4e5a' }, svg); + // Markierung: bestmöglicher Umsatz + const bestX = BAR_X + (BEST_REV / MAX_REV) * BAR_W; + svgEl('line', { x1: bestX, y1: 88, x2: bestX, y2: 138, stroke: '#c85c4a', 'stroke-width': '2', 'stroke-dasharray': '4 3' }, svg); + const bestLbl = svgEl('text', { x: bestX, y: 82, 'text-anchor': 'middle', 'font-size': '11', 'font-weight': '700', fill: '#c85c4a' }, svg); + bestLbl.textContent = 'Maximum: 56.250 €'; + + function update() { + const p = +rng.value; + const guests = Math.max(0, 3000 - 40 * p); + const rev = p * guests; + priceOut.textContent = p + ' €'; + calcOut.textContent = p + ' € · ' + fmtInt(guests) + ' Gäste = ' + fmtInt(rev) + ' €'; + + const gw = (guests / MAX_GUESTS) * BAR_W; + guestBar.setAttribute('width', gw); + guestTxt.setAttribute('x', BAR_X + gw + 8); + guestTxt.textContent = fmtInt(guests); + + const rw = (rev / MAX_REV) * BAR_W; + revBar.setAttribute('width', rw); + revTxt.setAttribute('x', BAR_X + rw + 8); + revTxt.textContent = fmtInt(rev) + ' €'; + // Text nicht mit der Maximum-Linie kollidieren lassen + revTxt.setAttribute('opacity', (BAR_X + rw + 75 > bestX && BAR_X + rw < bestX + 10) ? '0.35' : '1'); + + let v, state; + if (Math.abs(p - 37.5) <= 2) { v = '🎯 Fast genau das Maximum!'; state = 'good'; } + else if (p < 30) { v = '🟡 Zu billig — volle Pisten, wenig Umsatz'; state = 'warn'; } + else if (p <= 45) { v = '🟢 Guter Bereich'; state = 'now'; } + else { v = '🔴 Zu teuer — die Gäste bleiben aus'; state = 'bad'; } + verdict.textContent = v; + verdict.dataset.state = state; + } + rng.addEventListener('input', update); + update(); + } + + // ===================================================================== + // Experiment: Engpass — die Kette ist so stark wie ihr schwächstes Glied + // ===================================================================== + function bottleneckChain(root) { + root.innerHTML = ` +
+
+

⛓ Wo klemmt es im Urlaubsort?

+

Gäste durchlaufen drei Stationen: Anreise → Betten → Personal. + Stelle die Kapazitäten ein und beobachte, wo sich die Punkte stauen.

+
+ +
+ + +
+
+ + +
+
+ + +
+
+
Zufriedene Gäste: Minimum(160; 80; 120) = 80 pro Tag
+
Engpass: Betten
+
+

Prinzip der Engpass-Theorie („Theory of Constraints", E. M. Goldratt 1984): + Der Durchsatz einer Kette wird allein vom schwächsten Glied bestimmt. Mehr Kapazität an + anderen Stellen bringt nichts, solange der Engpass bleibt. Modellzahlen vereinfacht.

+
+ `; + const svg = root.querySelector('.ge-bal-svg'); + const ROAD_Y = 185; + const stations = [ + { key: 'anreise', label: 'Anreise', emoji: '🚌', x: 150 }, + { key: 'betten', label: 'Betten', emoji: '🛏', x: 310 }, + { key: 'personal', label: 'Personal', emoji: '👩‍🍳', x: 470 } + ]; + const caps = { anreise: 160, betten: 80, personal: 120 }; + + // Straße + svgEl('line', { x1: 10, y1: ROAD_Y, x2: 590, y2: ROAD_Y, stroke: '#dae8ec', 'stroke-width': '14', 'stroke-linecap': 'round' }, svg); + svgEl('text', { x: 14, y: ROAD_Y - 16, 'font-size': '11', fill: '#4a4a4a', 'font-weight': '600' }, svg).textContent = 'Gäste →'; + svgEl('text', { x: 588, y: ROAD_Y - 16, 'text-anchor': 'end', 'font-size': '11', fill: '#5a8a5e', 'font-weight': '700' }, svg).textContent = 'zufrieden 😊'; + + // Stations-Boxen über der Straße + stations.forEach(s => { + s.box = svgEl('rect', { x: s.x - 55, y: 30, width: 110, height: 92, rx: '10', fill: '#ffffff', stroke: '#b5c9cf', 'stroke-width': '2' }, svg); + const em = svgEl('text', { x: s.x, y: 66, 'text-anchor': 'middle', 'font-size': '26' }, svg); + em.textContent = s.emoji; + const lbl = svgEl('text', { x: s.x, y: 90, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '800', fill: '#1f4e5a' }, svg); + lbl.textContent = s.label; + s.capTxt = svgEl('text', { x: s.x, y: 108, 'text-anchor': 'middle', 'font-size': '11', 'font-weight': '600', fill: '#4a4a4a' }, svg); + // Schranke auf der Straße + svgEl('line', { x1: s.x, y1: ROAD_Y - 12, x2: s.x, y2: ROAD_Y + 12, stroke: '#4a7c8a', 'stroke-width': '3', 'stroke-dasharray': '4 3' }, svg); + }); + const dotGroup = svgEl('g', {}, svg); + + // --- Mini-Verkehrssimulation ------------------------------------- + const DAY_MS = 12000; // 12 s entsprechen einem Tag + const PER_DOT = 10; // 1 Punkt entspricht 10 Gästen + const INFLOW = 240; // Interessierte Gäste pro Tag (Nachfrage) + const SPEED = 0.085; // px pro ms + const GAP = 14; // Mindestabstand der Punkte + let particles = []; // { x, el } + let lastSpawn = 0; + const lastPass = { anreise: 0, betten: 0, personal: 0 }; + let animId = null, lastT = 0; + + function bottleneck() { + let minKey = 'anreise'; + for (const k in caps) if (caps[k] < caps[minKey]) minKey = k; + return minKey; + } + + function refreshUI() { + const minKey = bottleneck(); + const minVal = caps[minKey]; + const bLabel = stations.find(s => s.key === minKey).label; + root.querySelector('#ge-en-out').textContent = + 'Minimum(' + caps.anreise + '; ' + caps.betten + '; ' + caps.personal + ') = ' + minVal; + const verdict = root.querySelector('#ge-en-verdict'); + verdict.textContent = 'Engpass: ' + bLabel; + verdict.dataset.state = minVal >= 160 ? 'good' : (minVal >= 80 ? 'warn' : 'bad'); + stations.forEach(s => { + s.capTxt.textContent = caps[s.key] + ' / Tag'; + const isMin = s.key === minKey; + s.box.setAttribute('stroke', isMin ? '#c85c4a' : '#b5c9cf'); + s.box.setAttribute('stroke-width', isMin ? '3' : '2'); + }); + } + + function spawn(now) { + const interval = DAY_MS / (INFLOW / PER_DOT); + if (now - lastSpawn < interval || particles.length >= 70) return; + // Startplatz frei? + if (particles.some(p => p.x < 24)) return; + lastSpawn = now; + const el = svgEl('circle', { cx: 10, cy: ROAD_Y + (Math.random() * 8 - 4), r: 5, fill: '#4a7c8a', opacity: '0.9' }, dotGroup); + particles.push({ x: 10, el }); + } + + function step(now, dt) { + spawn(now); + // vorderste zuerst (größtes x) + particles.sort((a, b) => b.x - a.x); + for (let i = 0; i < particles.length; i++) { + const p = particles[i]; + let nx = p.x + SPEED * dt; + // Nicht auf den Vordermann auffahren + if (i > 0) nx = Math.min(nx, particles[i - 1].x - GAP); + // Nächste Schranke vor uns? + for (const s of stations) { + if (p.x < s.x && nx >= s.x) { + const interval = DAY_MS / (caps[s.key] / PER_DOT); + if (now - lastPass[s.key] >= interval) { + lastPass[s.key] = now; // durchgelassen + } else { + nx = s.x - 0.5; // warten → Stau bildet sich + } + break; + } + } + if (nx > p.x) p.x = nx; // nur vorwärts, nie rückwärts + p.el.setAttribute('cx', p.x); + } + // Ziel erreicht + particles = particles.filter(p => { + if (p.x > 585) { p.el.remove(); return false; } + return true; + }); + } + + function tick(now) { + if (!root.isConnected) { cancelAnimationFrame(animId); return; } + const dt = lastT ? Math.min(50, now - lastT) : 16; + lastT = now; + step(now, dt); + animId = requestAnimationFrame(tick); + } + animId = requestAnimationFrame(tick); + + stations.forEach(s => { + const rng = root.querySelector('#ge-en-' + s.key); + rng.addEventListener('input', () => { + caps[s.key] = +rng.value; + root.querySelector('#ge-en-' + s.key + '-val').textContent = rng.value; + refreshUI(); + }); + }); + refreshUI(); + } + + // ===================================================================== + // Experiment: Skaleneffekt — Fixkosten verteilen sich auf mehr Gäste + // ===================================================================== + function scaleEffect(root) { + root.innerHTML = ` +
+
+

🏠 Vier Gasthäuser — einzeln oder zusammengelegt?

+

Küche, Verwaltung und Werbung kosten 120.000 € im Jahr — egal ob für + ein Haus oder für vier. Lege Gasthäuser zu einem Betrieb zusammen und beobachte die + Kosten pro Gast.

+
+
+ + +
1234
+
+ +
+
Rechnung:
+
+
+

Modellzahlen: zentrale Fixkosten (Küche, Verwaltung, Werbung) 120.000 € pro Jahr, + Gebäudekosten 60.000 € je Haus, 4.000 Gäste je Haus. Dieses Sinken der Stückkosten bei + wachsender Betriebsgröße heißt Skaleneffekt (Fixkostendegression) — ein Hauptgrund, warum + sich Betriebe zusammenschließen.

+
+ `; + const svg = root.querySelector('.ge-bal-svg'); + const rng = root.querySelector('#ge-sk-range'); + const nOut = root.querySelector('#ge-sk-n'); + const calcOut = root.querySelector('#ge-sk-calc'); + const verdict = root.querySelector('#ge-sk-verdict'); + + const CENTRAL = 120000, PER_HOUSE = 60000, GUESTS = 4000; + const costPerGuest = n => (CENTRAL + n * PER_HOUSE) / (n * GUESTS); // 45 / 30 / 25 / 22,50 + + function drawHouse(parent, x, y, w, h, joined) { + svgEl('rect', { x, y, width: w, height: h, fill: '#e8d5b5', stroke: '#1f4e5a', 'stroke-width': '1.5' }, parent); + svgEl('polygon', { points: (x - 3) + ',' + y + ' ' + (x + w / 2) + ',' + (y - 16) + ' ' + (x + w + 3) + ',' + y, fill: joined ? '#4a7c8a' : '#c85c4a' }, parent); + } + + // Linke Hälfte: 4 einzelne Häuser (statisch), jedes mit eigener Küche + svgEl('text', { x: 150, y: 22, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '800', fill: '#1f4e5a' }, svg).textContent = 'Jedes Haus für sich'; + for (let i = 0; i < 4; i++) { + const hx = 45 + i * 56; + drawHouse(svg, hx, 48, 46, 34, false); + svgEl('text', { x: hx + 23, y: 72, 'text-anchor': 'middle', 'font-size': '15' }, svg).textContent = '🍳'; + } + // Rechte Hälfte: zusammengelegter Betrieb (dynamisch) + svgEl('text', { x: 450, y: 22, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '800', fill: '#1f4e5a' }, svg).textContent = 'Zusammengelegt'; + const mergedG = svgEl('g', {}, svg); + + // Balken: Stückkosten je Gast (Skala 0–50 €, Höhe 110 px) + const BAR_BASE = 240, BAR_MAXH = 110, SCALE = 50; + svgEl('line', { x1: 30, y1: BAR_BASE, x2: 570, y2: BAR_BASE, stroke: '#b5c9cf', 'stroke-width': '1.5' }, svg); + // Referenzbalken links: 45 € (statisch) + const refH = 45 / SCALE * BAR_MAXH; + svgEl('rect', { x: 120, y: BAR_BASE - refH, width: 60, height: refH, fill: '#c85c4a', rx: '6', opacity: '0.85' }, svg); + svgEl('text', { x: 150, y: BAR_BASE - refH - 8, 'text-anchor': 'middle', 'font-size': '13', 'font-weight': '800', fill: '#c85c4a' }, svg).textContent = '45,00 € je Gast'; + // Dynamischer Balken rechts + const dynBar = svgEl('rect', { x: 420, y: BAR_BASE, width: 60, height: 0, fill: '#5a8a5e', rx: '6' }, svg); + const dynTxt = svgEl('text', { x: 450, y: BAR_BASE - 8, 'text-anchor': 'middle', 'font-size': '13', 'font-weight': '800', fill: '#5a8a5e' }, svg); + + function update() { + const n = +rng.value; + nOut.textContent = n + (n === 1 ? ' Gasthaus' : ' Gasthäuser'); + // Zusammengelegte Häuser zeichnen: n Häuser ohne Lücke, EINE Küche + mergedG.innerHTML = ''; + const w = 46, totalW = n * w; + const startX = 450 - totalW / 2; + for (let i = 0; i < n; i++) drawHouse(mergedG, startX + i * w, 48, w, 34, true); + svgEl('text', { x: 450, y: 72, 'text-anchor': 'middle', 'font-size': '15' }, mergedG).textContent = '🍳'; + const cap = svgEl('text', { x: 450, y: 100, 'text-anchor': 'middle', 'font-size': '10', fill: '#4a4a4a' }, mergedG); + cap.textContent = n === 1 ? 'eine Küche, eine Verwaltung' : 'eine Küche, eine Verwaltung für ' + n + ' Häuser'; + + const c = costPerGuest(n); + const h = c / SCALE * BAR_MAXH; + dynBar.setAttribute('y', BAR_BASE - h); + dynBar.setAttribute('height', h); + dynTxt.setAttribute('y', BAR_BASE - h - 8); + dynTxt.textContent = fmtDec(c, 2) + ' € je Gast'; + + calcOut.textContent = '(120.000 € + ' + n + ' · 60.000 €) : ' + fmtInt(n * GUESTS) + ' Gäste = ' + fmtDec(c, 2) + ' €'; + if (n === 1) { + verdict.textContent = 'Ausgangslage: jedes Haus trägt alle Fixkosten allein'; + verdict.dataset.state = 'now'; + } else if (n < 4) { + verdict.textContent = '🟢 Stückkosten sinken: Fixkosten verteilen sich auf ' + fmtInt(n * GUESTS) + ' Gäste'; + verdict.dataset.state = 'good'; + } else { + verdict.textContent = '🎯 4 kleine: 45,00 € — 1 großes: 22,50 € je Gast, also halbiert!'; + verdict.dataset.state = 'good'; + } + } + rng.addEventListener('input', update); + update(); + } + + // ===================================================================== + // Experiment: Modal Split — Verkehrsmittel-Mix und CO₂ + // ===================================================================== + function modalSplit(root) { + root.innerHTML = ` +
+
+

🚦 Wer fährt womit in den Urlaub?

+

Verteile die Anreisen auf Auto, Bus und Bahn — die Summe bleibt automatisch 100 %. + Beobachte, wie sich der CO₂-Ausstoß je Person verändert.

+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+
nur Bahn: 26 gnur Bus: 30 gnur Auto: 164 g
+
+
Ø CO₂: je Personen-km
+
Anreise 400 km: je Person
+
+
+

Durchschnittswerte je Personen-Kilometer: Pkw 164 g · Reisebus 30 g · + Bahn 26 g CO₂. Quelle: Umweltbundesamt (DE), Emissionsdaten Personenverkehr 2024. + Die Aufteilung der Wege auf Verkehrsmittel heißt Modal Split — Besucherlenkung Richtung + Bus und Bahn ist einer der größten Klimahebel im Tourismus.

+
+ `; + const FACTORS = { auto: 164, bus: 30, bahn: 26 }; + const shares = { auto: 60, bus: 20, bahn: 20 }; + const keys = ['auto', 'bus', 'bahn']; + const sliders = {}, labels = {}; + keys.forEach(k => { + sliders[k] = root.querySelector('#ge-ms-' + k); + labels[k] = root.querySelector('#ge-ms-' + k + '-val'); + }); + const stack = root.querySelector('#ge-ms-stack'); + const co2bar = root.querySelector('#ge-ms-co2bar'); + const gkmOut = root.querySelector('#ge-ms-gkm'); + const tripOut = root.querySelector('#ge-ms-trip'); + const verdict = root.querySelector('#ge-ms-verdict'); + + function render() { + keys.forEach(k => { + sliders[k].value = shares[k]; + labels[k].textContent = shares[k] + ' %'; + stack.querySelector('[data-seg="' + k + '"]').style.width = shares[k] + '%'; + }); + const gkm = (shares.auto * FACTORS.auto + shares.bus * FACTORS.bus + shares.bahn * FACTORS.bahn) / 100; + gkmOut.textContent = fmtDec(gkm, 0) + ' g'; + tripOut.textContent = fmtDec(gkm * 400 / 1000, 1) + ' kg CO₂'; + co2bar.style.width = Math.max(3, gkm / FACTORS.auto * 100) + '%'; + if (gkm < 55) { verdict.textContent = '🟢 Klimafreundlicher Mix'; verdict.dataset.state = 'good'; } + else if (gkm < 110) { verdict.textContent = '🟠 Mittelfeld — Bahn hilft'; verdict.dataset.state = 'warn'; } + else { verdict.textContent = '🔴 Fast alles Auto'; verdict.dataset.state = 'bad'; } + } + + function onInput(key) { + const val = Math.max(0, Math.min(100, Math.round(+sliders[key].value))); + const others = keys.filter(k => k !== key); + const rest = 100 - val; + const oldSum = shares[others[0]] + shares[others[1]]; + let a; + if (oldSum <= 0) a = Math.round(rest / 2); + else a = Math.round(rest * shares[others[0]] / oldSum); + shares[key] = val; + shares[others[0]] = a; + shares[others[1]] = rest - a; + render(); + } + keys.forEach(k => sliders[k].addEventListener('input', () => onInput(k))); + render(); + } + + // ===================================================================== + // Experiment: Netzfrequenz — der Pulsschlag des Stromnetzes + // ===================================================================== + function gridFrequency(root) { + root.innerHTML = ` +
+
+

⚡ Halte das Netz bei 50 Hertz

+

Im Stromnetz müssen Erzeugung und Verbrauch in jeder Sekunde gleich groß + sein. Passen sie nicht zusammen, driftet die Netzfrequenz weg von 50 Hz. Probiere es!

+
+ +
+ + +
+
+ + +
+
+
Bilanz: Erzeugung − Verbrauch = 0 GW
+
🟢 Netz stabil
+
+
+ +
+

Sollfrequenz im europäischen Verbundnetz: 50 Hz. Sinkt sie unter 49,8 Hz, + greift der 5-Stufen-Plan der Netzbetreiber: Erste Verbraucher werden automatisch + abgeworfen (Lastabwurf), um einen Blackout zu verhindern. Quellen: ENTSO-E · + VDE-Netzregeln. Vereinfachtes Modell — echte Netze steuern mit Regelreserven binnen + Sekunden dagegen.

+
+ `; + const svg = root.querySelector('.ge-gh-svg'); + const CX = 300, CY = 245, R = 185; + const rad = a => a * Math.PI / 180; + const pt = (a, r) => [CX + r * Math.sin(rad(a)), CY - r * Math.cos(rad(a))]; + const freqToAngle = f => Math.max(-80, Math.min(80, (f - 50) / 0.2 * 80)); + const arcPath = (a1, a2, r) => { + const [x1, y1] = pt(a1, r), [x2, y2] = pt(a2, r); + return 'M ' + x1 + ' ' + y1 + ' A ' + r + ' ' + r + ' 0 0 1 ' + x2 + ' ' + y2; + }; + // Farbzonen + [ + { a1: -80, a2: -40, c: '#c85c4a' }, // 49,80–49,90 + { a1: -40, a2: -20, c: '#e8833a' }, // 49,90–49,95 + { a1: -20, a2: 20, c: '#5a8a5e' }, // 49,95–50,05 + { a1: 20, a2: 40, c: '#e8833a' }, + { a1: 40, a2: 80, c: '#c85c4a' } + ].forEach(z => svgEl('path', { d: arcPath(z.a1, z.a2, R), stroke: z.c, 'stroke-width': '20', fill: 'none', 'stroke-linecap': 'butt', opacity: '0.9' }, svg)); + // Skala + [[49.8, '49,8'], [49.9, '49,9'], [50.0, '50,0'], [50.1, '50,1'], [50.2, '50,2']].forEach(([f, lbl]) => { + const a = freqToAngle(f); + const [x1, y1] = pt(a, R - 14), [x2, y2] = pt(a, R + 14); + svgEl('line', { x1, y1, x2, y2, stroke: '#1f4e5a', 'stroke-width': '2' }, svg); + const [tx, ty] = pt(a, R + 30); + const t = svgEl('text', { x: tx, y: ty + 4, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '700', fill: '#1f4e5a' }, svg); + t.textContent = lbl; + }); + svgEl('text', { x: CX, y: 60, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '600', fill: '#4a4a4a' }, svg).textContent = 'Hertz (Hz) = Schwingungen pro Sekunde'; + // Zeiger + const needle = svgEl('g', { transform: 'rotate(0, ' + CX + ', ' + CY + ')' }, svg); + svgEl('line', { x1: CX, y1: CY, x2: CX, y2: CY - R + 30, stroke: '#1f4e5a', 'stroke-width': '5', 'stroke-linecap': 'round' }, needle); + svgEl('circle', { cx: CX, cy: CY, r: 10, fill: '#1f4e5a' }, svg); + // Digitalanzeige + const digital = svgEl('text', { x: CX, y: CY + 34, 'text-anchor': 'middle', 'font-size': '22', 'font-weight': '900', fill: '#1f4e5a' }, svg); + + const genRng = root.querySelector('#ge-nf-gen'); + const loadRng = root.querySelector('#ge-nf-load'); + const genVal = root.querySelector('#ge-nf-gen-val'); + const loadVal = root.querySelector('#ge-nf-load-val'); + const diffOut = root.querySelector('#ge-nf-diff'); + const status = root.querySelector('#ge-nf-status'); + + let freq = 50.0; + const K = 0.0055; // Hz pro (GW · Sekunde) — bewusst anschaulich skaliert + let animId = null, lastT = 0; + + function refreshLabels() { + genVal.textContent = genRng.value; + loadVal.textContent = loadRng.value; + const d = genRng.value - loadRng.value; + diffOut.textContent = (d > 0 ? '+' : '') + d + ' GW'; + } + function tick(now) { + if (!root.isConnected) { cancelAnimationFrame(animId); return; } + const dt = lastT ? Math.min(60, now - lastT) : 16; + lastT = now; + const imbalance = (+genRng.value) - (+loadRng.value); + freq = Math.max(49.78, Math.min(50.22, freq + imbalance * K * dt / 1000)); + needle.setAttribute('transform', 'rotate(' + freqToAngle(freq).toFixed(2) + ', ' + CX + ', ' + CY + ')'); + digital.textContent = freq.toFixed(3).replace('.', ',') + ' Hz'; + if (freq <= 49.8) { + status.textContent = '🔴 Unter 49,8 Hz: Lastabwurf! Verbraucher werden abgetrennt'; + status.dataset.state = 'bad'; + } else if (freq >= 50.2) { + status.textContent = '🔴 Über 50,2 Hz: Kraftwerke müssen sofort drosseln'; + status.dataset.state = 'bad'; + } else if (Math.abs(freq - 50) > 0.05) { + status.textContent = '🟠 Warnzone — Regelenergie nötig'; + status.dataset.state = 'warn'; + } else { + status.textContent = '🟢 Netz stabil'; + status.dataset.state = 'good'; + } + animId = requestAnimationFrame(tick); + } + genRng.addEventListener('input', refreshLabels); + loadRng.addEventListener('input', refreshLabels); + root.querySelector('[data-act="reset"]').addEventListener('click', () => { + freq = 50.0; + genRng.value = 80; + loadRng.value = 80; + refreshLabels(); + }); + refreshLabels(); + animId = requestAnimationFrame(tick); + } + + // ===================================================================== + // Experiment: Lageenergie / Pumpspeicher — Strom als gehobenes Wasser + // ===================================================================== + function pumpedStorage(root) { + root.innerHTML = ` +
+
+

🏔 Der Stromspeicher im Berg

+

Bei Stromüberschuss pumpt das Kraftwerk Wasser ins Oberbecken — Strom wird zu + Lageenergie. Bei Strommangel rauscht das Wasser durch die Turbine + wieder hinunter. Aber: Ein Teil der Energie geht verloren.

+
+ +
+ + +
+
+
Strom eingesetzt: 0 kWh
+
Strom zurückgewonnen: 0 kWh
+
Verlust (Wärme, Reibung): 0 kWh
+
Das Unterbecken ist voll — pumpe Wasser hinauf!
+
+

Pumpspeicherkraftwerke sind bis heute der einzige großtechnische + Stromspeicher: Aus 100 kWh Pumpstrom kommen rund 75–80 kWh wieder heraus + (Gesamtwirkungsgrad, hier gerechnet mit 78 %). Quellen: VERBUND (Malta- und + Kaprun-Kraftwerke) · Fraunhofer ISE.

+
+ `; + const svg = root.querySelector('.ge-gh-svg'); + const EFF = 0.78; // Gesamtwirkungsgrad + const STEP_UNITS = 20; // Wasser-Einheiten je Klick; 1 Einheit ≙ 1 kWh Pumpstrom + + // --- Szene --------------------------------------------------------- + // Berg links mit Plateau für das Oberbecken + svgEl('polygon', { points: '0,330 0,150 60,80 250,80 290,160 360,310 600,310 600,330', fill: '#5a8a5e' }, svg); + svgEl('polygon', { points: '0,330 0,240 120,200 300,260 600,315 600,330', fill: '#4a7050', opacity: '.6' }, svg); + // Oberbecken (Behälter) + svgEl('rect', { x: 66, y: 82, width: 168, height: 48, fill: '#3f5f52', rx: '4' }, svg); + const upperWater = svgEl('rect', { x: 70, y: 126, width: 160, height: 0, fill: '#4a7c8a' }, svg); + svgEl('text', { x: 150, y: 74, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '800', fill: '#1f4e5a' }, svg).textContent = 'Oberbecken'; + // Fallhöhe-Markierung + svgEl('line', { x1: 320, y1: 130, x2: 320, y2: 250, stroke: '#1f4e5a', 'stroke-width': '1.2', 'stroke-dasharray': '4 3', opacity: '.6' }, svg); + svgEl('text', { x: 328, y: 195, 'font-size': '10', fill: '#1f4e5a', opacity: '.8' }, svg).textContent = 'Fallhöhe'; + // Druckrohr Oberbecken → Krafthaus + const pipeA = { x: 226, y: 124 }, pipeB = { x: 408, y: 262 }; + svgEl('line', { x1: pipeA.x, y1: pipeA.y, x2: pipeB.x, y2: pipeB.y, stroke: '#4a4a4a', 'stroke-width': '12', 'stroke-linecap': 'round' }, svg); + svgEl('line', { x1: pipeA.x, y1: pipeA.y, x2: pipeB.x, y2: pipeB.y, stroke: '#dae8ec', 'stroke-width': '6', 'stroke-linecap': 'round' }, svg); + // Krafthaus mit Pumpe/Turbine + svgEl('rect', { x: 385, y: 252, width: 76, height: 58, fill: '#e8d5b5', stroke: '#1f4e5a', 'stroke-width': '1.5', rx: '4' }, svg); + svgEl('polygon', { points: '382,253 423,235 464,253', fill: '#c85c4a' }, svg); + const gear = svgEl('text', { x: 423, y: 288, 'text-anchor': 'middle', 'font-size': '20' }, svg); + gear.textContent = '⚙'; + const modeLbl = svgEl('text', { x: 423, y: 326, 'text-anchor': 'middle', 'font-size': '11', 'font-weight': '800', fill: '#1f4e5a' }, svg); + modeLbl.textContent = 'Pumpe / Turbine'; + // Unterbecken rechts vom Krafthaus + svgEl('rect', { x: 476, y: 252, width: 112, height: 56, fill: '#3f5f52', rx: '4' }, svg); + const lowerWater = svgEl('rect', { x: 480, y: 304, width: 104, height: 0, fill: '#4a7c8a' }, svg); + svgEl('text', { x: 532, y: 244, 'text-anchor': 'middle', 'font-size': '12', 'font-weight': '800', fill: '#1f4e5a' }, svg).textContent = 'Unterbecken'; + // Wasser-Punkte im Rohr (nur während der Animation sichtbar) + const flowDots = []; + for (let i = 0; i < 4; i++) flowDots.push(svgEl('circle', { r: 4.5, fill: '#7fb3c4', opacity: '0' }, svg)); + + // --- Zustand --------------------------------------------------------- + let upper = 0, lower = 100; // Wasser-Einheiten + let energyIn = 0, energyOut = 0; // kWh + let animId = null, animating = false; + + const inOut = root.querySelector('#ge-ps-in'); + const outOut = root.querySelector('#ge-ps-out'); + const lossOut = root.querySelector('#ge-ps-loss'); + const status = root.querySelector('#ge-ps-status'); + const btnPump = root.querySelector('[data-act="pump"]'); + const btnTurb = root.querySelector('[data-act="turbine"]'); + + function setWater(u) { + // Oberbecken: max 44 px, Unterbecken: max 48 px + const uh = u / 100 * 44; + upperWater.setAttribute('y', 126 - uh); + upperWater.setAttribute('height', uh); + const lh = (100 - u) / 100 * 48; + lowerWater.setAttribute('y', 304 - lh); + lowerWater.setAttribute('height', lh); + } + function refreshAccount() { + inOut.textContent = fmtDec(energyIn, 0) + ' kWh'; + outOut.textContent = fmtDec(energyOut, 1).replace(',0', '') + ' kWh'; + const stored = upper * EFF; // noch abrufbarer Strom + const loss = Math.max(0, energyIn - energyOut - stored); + lossOut.textContent = fmtDec(loss, 1).replace(',0', '') + ' kWh'; + } + function refreshButtons() { + btnPump.disabled = animating || lower < STEP_UNITS; + btnTurb.disabled = animating || upper < STEP_UNITS; + btnPump.style.opacity = btnPump.disabled ? '.45' : '1'; + btnTurb.style.opacity = btnTurb.disabled ? '.45' : '1'; + } + + function animate(mode) { + if (animating) return; + if (mode === 'pump' && lower < STEP_UNITS) return; + if (mode === 'turbine' && upper < STEP_UNITS) return; + animating = true; + refreshButtons(); + modeLbl.textContent = mode === 'pump' ? 'Pumpe läuft ▲' : 'Turbine läuft ▼'; + const startU = upper; + const targetU = mode === 'pump' ? upper + STEP_UNITS : upper - STEP_UNITS; + const DUR = 1400; + const t0 = performance.now(); + function frame(now) { + if (!root.isConnected) { cancelAnimationFrame(animId); return; } + const t = Math.min(1, (now - t0) / DUR); + const e = 1 - Math.pow(1 - t, 3); + setWater(startU + (targetU - startU) * e); + // Wasser-Punkte im Rohr + flowDots.forEach((d, i) => { + let k = (t * 2.2 + i / flowDots.length) % 1; + if (mode === 'turbine') k = 1 - k; // bergab + d.setAttribute('cx', pipeA.x + (pipeB.x - pipeA.x) * k); + d.setAttribute('cy', pipeA.y + (pipeB.y - pipeA.y) * k); + d.setAttribute('opacity', '0.95'); + }); + if (t < 1) { animId = requestAnimationFrame(frame); return; } + // fertig + flowDots.forEach(d => d.setAttribute('opacity', '0')); + upper = targetU; + lower = 100 - upper; + if (mode === 'pump') { + energyIn += STEP_UNITS; // 20 kWh Strom hinein + status.textContent = '⚡ 20 kWh Strom als Lageenergie gespeichert'; + status.dataset.state = 'now'; + } else { + const gain = STEP_UNITS * EFF; // 15,6 kWh zurück + energyOut += gain; + status.textContent = '💡 ' + fmtDec(gain, 1) + ' kWh zurückgewonnen — ' + fmtDec(STEP_UNITS - gain, 1) + ' kWh verloren (78 %)'; + status.dataset.state = 'good'; + } + modeLbl.textContent = 'Pumpe / Turbine'; + animating = false; + refreshAccount(); + refreshButtons(); + } + animId = requestAnimationFrame(frame); + } + + btnPump.addEventListener('click', () => animate('pump')); + btnTurb.addEventListener('click', () => animate('turbine')); + setWater(upper); + refreshAccount(); + refreshButtons(); + } + + // Registry — Keys entsprechen key_slug aus der Tabelle `glossar` + window.GlossarExperiments = Object.assign(window.GlossarExperiments || {}, { + 'preiselastizitaet': priceElasticity, + 'engpass': bottleneckChain, + 'skaleneffekt': scaleEffect, + 'modal-split': modalSplit, + 'netzfrequenz': gridFrequency, + 'hertz': gridFrequency, + 'lageenergie': pumpedStorage, + 'pumpspeicher': pumpedStorage + }); +})(); diff --git a/App/assets/js/glossar-experiments.js b/App/assets/js/glossar-experiments.js index 50962b6..2c8534d 100644 --- a/App/assets/js/glossar-experiments.js +++ b/App/assets/js/glossar-experiments.js @@ -534,8 +534,10 @@ update(); } - // Registry — Key entspricht key_slug aus DB - window.GlossarExperiments = { + // Registry — Key entspricht key_slug aus DB. + // Object.assign, damit weitere Dateien (glossar-experiments-*.js) unabhängig + // von der Ladereihenfolge dazuregistrieren können. + window.GlossarExperiments = Object.assign(window.GlossarExperiments || {}, { 'kilowattstunde': kwhRace, 'ppm': ppmGrid, 'albedo': albedoSlider, @@ -543,5 +545,5 @@ 'treibhauseffekt': greenhouseSlider, 'methan': methaneBalance // 'windenergie' bewusst raus — redundant mit windrad-groessenvergleich.svg - }; + }); })(); diff --git a/App/pages/_partials/buch_helpers.php b/App/pages/_partials/buch_helpers.php index 8e5926f..0f5f812 100644 --- a/App/pages/_partials/buch_helpers.php +++ b/App/pages/_partials/buch_helpers.php @@ -38,6 +38,16 @@ function buchBild(string $slug, string $vorschlag, string $unterschrift = '', bo return "
📷Foto gesucht" . htmlspecialchars($vorschlag) . "assets/img/buch/" . BUCH_SIM . "/{$slug}.jpg
"; } +/** Kapitel-Symbol: generiertes Icon-Bild, solange keins da ist das Emoji. */ +function buchKapIcon(string $emoji): string { + global $bp; + $rel = 'assets/img/buch/icon-' . BUCH_SIM . '.webp'; + if (is_file(__DIR__ . '/../../' . $rel)) { + return ''; + } + return $emoji; +} + /** Glossar-Begriff mit Tooltip */ function g(string $slug, string $label): string { return "{$label}"; diff --git a/App/pages/buch-busfahrt.php b/App/pages/buch-busfahrt.php index 9ff70c2..3764110 100644 --- a/App/pages/buch-busfahrt.php +++ b/App/pages/buch-busfahrt.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';
BUSFAHRT · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🚌 Mit dem Bus durch Europa

+

Mit dem Bus durch Europa

Wie gut kennst du Europa?
diff --git a/App/pages/buch-energiemanager.php b/App/pages/buch-energiemanager.php index 28c3166..472199c 100644 --- a/App/pages/buch-energiemanager.php +++ b/App/pages/buch-energiemanager.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

ENERGIEMANAGER · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

⚡ Strom rund um die Uhr

+

Strom rund um die Uhr

Du drückst den Licht-Schalter. Das Licht geht an.
diff --git a/App/pages/buch-eu-werkstatt.php b/App/pages/buch-eu-werkstatt.php index 177baa0..b4ef313 100644 --- a/App/pages/buch-eu-werkstatt.php +++ b/App/pages/buch-eu-werkstatt.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

EU-WERKSTATT · KAPITEL-START

Geografie und wirtschaftliche Bildung · Politische Bildung · Sek I

-

🇪🇺 Wie ein EU-Gesetz entsteht

+

Wie ein EU-Gesetz entsteht

Wer entscheidet in Europa?
diff --git a/App/pages/buch-farmer.php b/App/pages/buch-farmer.php index eee85b5..3e031f1 100644 --- a/App/pages/buch-farmer.php +++ b/App/pages/buch-farmer.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

LANDWIRTSCHAFT · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🌾 Landwirtschaft weltweit

+

Landwirtschaft weltweit

Warum wächst die Banane in Ecuador?
diff --git a/App/pages/buch-fluss.php b/App/pages/buch-fluss.php index 15c9d8a..743b148 100644 --- a/App/pages/buch-fluss.php +++ b/App/pages/buch-fluss.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

FLUSS · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🌊 Der Fluss und das Hochwasser

+

Der Fluss und das Hochwasser

Warum tritt ein Fluss über das Ufer?
diff --git a/App/pages/buch-heli.php b/App/pages/buch-heli.php index 8fe0fa9..b6db767 100644 --- a/App/pages/buch-heli.php +++ b/App/pages/buch-heli.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

HELI-NAVIGATION · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🚁 Mit Karte und Koordinaten

+

Mit Karte und Koordinaten

Ein Mensch ist in den Bergen verletzt.
diff --git a/App/pages/buch-klima.php b/App/pages/buch-klima.php index eafa1cc..0645461 100644 --- a/App/pages/buch-klima.php +++ b/App/pages/buch-klima.php @@ -42,7 +42,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

KLIMAWÄCHTER · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🌍 Klimawandel an der Küste

+

Klimawandel an der Küste

Die Erde wird wärmer. Das Meer steigt.
diff --git a/App/pages/buch-kofferdetektiv.php b/App/pages/buch-kofferdetektiv.php index 56c2d76..b355100 100644 --- a/App/pages/buch-kofferdetektiv.php +++ b/App/pages/buch-kofferdetektiv.php @@ -43,7 +43,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

KOFFERDETEKTIV · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🧳 Dem Reisen auf der Spur

+

Dem Reisen auf der Spur

Ein Koffer bleibt am Flughafen liegen.
diff --git a/App/pages/buch-logistik.php b/App/pages/buch-logistik.php index 7163232..cc8be84 100644 --- a/App/pages/buch-logistik.php +++ b/App/pages/buch-logistik.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

LOGISTIK · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🚚 Waren auf Reisen

+

Waren auf Reisen

Wie kommt die Ware in den Super-Markt?
diff --git a/App/pages/buch-sonnensystem.php b/App/pages/buch-sonnensystem.php index b5686a9..f3b7b20 100644 --- a/App/pages/buch-sonnensystem.php +++ b/App/pages/buch-sonnensystem.php @@ -42,7 +42,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

SONNENSYSTEM · KAPITEL-START

Geografie und wirtschaftliche Bildung · Physik · Sek I

-

🪐 Sonne, Erde, Mond

+

Sonne, Erde, Mond

Warum gibt es Tag und Nacht?
diff --git a/App/pages/buch-tourismusregion.php b/App/pages/buch-tourismusregion.php index 8152e50..4df4897 100644 --- a/App/pages/buch-tourismusregion.php +++ b/App/pages/buch-tourismusregion.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

TOURISMUSREGION · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🗺️ Besucherströme lenken

+

Besucherströme lenken

Warum sind an manchen Orten so viele Menschen?
diff --git a/App/pages/buch-tourismustal.php b/App/pages/buch-tourismustal.php index d036c2e..835a84b 100644 --- a/App/pages/buch-tourismustal.php +++ b/App/pages/buch-tourismustal.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

TOURISMUSTAL · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🏔️ Ein Tal wird Tourismusregion

+

Ein Tal wird Tourismusregion

Wie wird aus einem stillen Berg-Tal ein Urlaubs-Ort?
diff --git a/App/pages/buch-weltkueche.php b/App/pages/buch-weltkueche.php index 468809f..2d7b52b 100644 --- a/App/pages/buch-weltkueche.php +++ b/App/pages/buch-weltkueche.php @@ -41,7 +41,7 @@ require __DIR__ . '/_partials/buch_helpers.php';

WELTKÜCHE · KAPITEL-START

Geografie und wirtschaftliche Bildung · Sek I

-

🍲 Was die Welt isst

+

Was die Welt isst

Woher kommt das Essen auf deinem Teller?
diff --git a/App/pages/buch.php b/App/pages/buch.php index 23615e3..d938ff1 100644 --- a/App/pages/buch.php +++ b/App/pages/buch.php @@ -72,6 +72,7 @@ $KAPITEL = [ text-decoration: none; color: inherit; } .kap:hover { box-shadow: 0 6px 22px rgba(47,62,70,.18); } .kap .ic { font-size: 34px; } + .kap img.ic { width: 58px; height: 58px; border-radius: 12px; object-fit: cover; flex-shrink: 0; } .kap b { font-size: 18px; display: block; } .kap small { color: #6b6659; display: block; margin-top: 3px; line-height: 1.5; } .kap .pill { margin-left: auto; align-self: center; font-size: 11px; font-weight: 800; @@ -102,7 +103,11 @@ $KAPITEL = [

- + + + + + Zur Simulation „" · diff --git a/App/pages/glossar.php b/App/pages/glossar.php index bdb6f0d..e926846 100644 --- a/App/pages/glossar.php +++ b/App/pages/glossar.php @@ -644,6 +644,8 @@ include __DIR__ . '/_partials/erkundungs_subnav.php';
+ +