Files
geograsim/App/pages/_partials/modul_detail.php
T
Adminator 95e19818fd Lehrplan: Country-Default überall AT, übergreifend land-agnostisch
Auftrag von Thomas: Default-Filter überall auf Österreich, andere
Länder weiterhin wählbar.

Modul-Detailseiten (gemeinsamer Partial):
- Filter-Chip mit data-country=Country::current() bekommt Klasse
  active server-seitig (statt "🌐 Alle Länder")
- Country.php in Partial eingebunden
- JS-Filter-Logik überarbeitet: bei konkretem Land werden NUR
  anchor_type='fach' Anker streng nach Land gefiltert; übergreifende
  Themen und andere Fächer bleiben sichtbar (sind primär aus dem
  AT-Lehrplan abgeleitet, didaktisch land-agnostisch nutzbar)
- applyFilter() wird beim Page-Load mit dem aktiven Chip ausgeführt

Lehrplan.php:
- gleiche Filter-Logik gespiegelt (war vorher streng auch für
  übergreifend/andere_fach)
- Default war schon Country::current(), bleibt unverändert

Verifiziert: alle 10 aktiven modul-*.php-Seiten zeigen AT als
Default-active, Lehrplan-Seite ebenfalls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 02:16:04 +02:00

732 lines
30 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Modul-Detailseiten — gemeinsamer Partial
* -----------------------------------------
* Wird von modul-klima.php, modul-fluss.php, modul-heli.php, modul-stadt.php
* eingebunden. Erwartet im includierenden Scope:
*
* $MODULE_ID string — module_info.module_id (z.B. 'klima')
*
* Quellen:
* - module_info (Metadaten, inkl. Easy-Varianten)
* - glossar + glossar_modules (Begriffe)
* - kompetenzen + kompetenz_modules
* + lehrplan_anchors (Lehrplan-Bezug, gruppiert nach Typ)
* - EasyLang-Helper (pickt Normal- oder Easy-Text)
*
* Design: iPad Landscape (1180×820) als Hauptreferenz (siehe
* module-interface.md Abschnitt 4c).
*/
if (!isset($MODULE_ID) || !is_string($MODULE_ID)) {
http_response_code(500);
echo 'modul_detail.php: $MODULE_ID fehlt.';
exit;
}
require_once __DIR__ . '/../../php/config/app.php';
require_once __DIR__ . '/../../php/config/db.php';
require_once __DIR__ . '/../../php/lib/EasyLang.php';
require_once __DIR__ . '/../../php/lib/Country.php';
$db = getDB();
$module = $db->prepare('SELECT * FROM module_info WHERE module_id = ?');
$module->execute([$MODULE_ID]);
$module = $module->fetch();
if (!$module) {
http_response_code(404);
echo 'Modul nicht gefunden.';
exit;
}
// Easy-Varianten per Helper (Fallback: Normalform)
$shortDesc = EasyLang::pick($module['short_desc'] ?? null, $module['short_desc_easy'] ?? null);
$longDesc = EasyLang::pick($module['long_desc'] ?? null, $module['long_desc_easy'] ?? null);
$goalsRaw = EasyLang::pick($module['learning_goals'] ?? null, $module['learning_goals_easy'] ?? null);
// Lernziele — JSON-Array mit Strings
$learningGoals = [];
if ($goalsRaw) {
$decoded = json_decode($goalsRaw, true);
if (is_array($decoded)) $learningGoals = $decoded;
}
// Glossar-Begriffe zum Modul
$stmt = $db->prepare('
SELECT g.key_slug, g.title, g.short, g.category
FROM glossar g
INNER JOIN glossar_modules m ON m.glossar_id = g.id
WHERE m.module_id = ?
ORDER BY g.title
');
$stmt->execute([$MODULE_ID]);
$glossarTerms = $stmt->fetchAll();
// Kompetenzen + Lehrplan-Anker
$stmt = $db->prepare('
SELECT k.id, k.key_slug, k.title, k.description, k.category,
km.strength, km.level
FROM kompetenzen k
INNER JOIN kompetenz_modules km ON km.kompetenz_id = k.id
WHERE km.module_id = ?
ORDER BY km.strength, k.sort_order, k.title
');
$stmt->execute([$MODULE_ID]);
$kompetenzen = $stmt->fetchAll();
$ankerStmt = $db->prepare("
SELECT anchor_type, country, region, school_type, grade, subject,
title, reference, reference_url, quote
FROM lehrplan_anchors
WHERE kompetenz_id = ?
ORDER BY FIELD(anchor_type, 'fach', 'uebergreifendes_thema', 'anderes_fach'),
country, sort_order
");
foreach ($kompetenzen as &$k) {
$ankerStmt->execute([$k['id']]);
$rows = $ankerStmt->fetchAll();
$k['anchors_fach'] = array_values(array_filter($rows, fn($r) => $r['anchor_type'] === 'fach'));
$k['anchors_uebergreifend'] = array_values(array_filter($rows, fn($r) => $r['anchor_type'] === 'uebergreifendes_thema'));
$k['anchors_andere_faecher'] = array_values(array_filter($rows, fn($r) => $r['anchor_type'] === 'anderes_fach'));
}
unset($k);
$bp = BASE_PATH;
$api = BASE_URL . '/php/api/glossar.php';
$pageTitle = htmlspecialchars($module['title']) . ' — Lehrplan geograsim.at';
$easyActive = EasyLang::isActive();
if (!function_exists('esc')) {
function esc(?string $s): string { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
}
$countryMeta = [
'AT' => ['flag' => '🇦🇹', 'label' => 'Österreich'],
'DE' => ['flag' => '🇩🇪', 'label' => 'Deutschland'],
'CH' => ['flag' => '🇨🇭', 'label' => 'Schweiz'],
'LI' => ['flag' => '🇱🇮', 'label' => 'Liechtenstein'],
];
// Default-Land aus Kaskade Session/Cookie/AT — als initialer Anker-Filter aktiv
$qCountry = Country::current();
?><!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title><?= $pageTitle ?></title>
<meta name="description" content="<?= esc($module['subtitle']) ?> — Lernziele, Begriffe und Lehrplan-Bezug für die GeoGraSim-Simulation <?= esc($module['title']) ?>.">
<link rel="icon" type="image/svg+xml" href="<?= $bp ?>/favicon.svg">
<link rel="icon" type="image/png" href="<?= $bp ?>/favicon-96x96.png" sizes="96x96">
<link rel="stylesheet" href="<?= $bp ?>/assets/fonts/inter.css">
<link rel="stylesheet" href="<?= $bp ?>/assets/css/design-system.css">
<style>
/* Seite ist scrollbar — Design-System-Body ist overflow:hidden, das ueberschreiben wir hier */
body { overflow: auto; height: auto; min-height: 100dvh; background: var(--ggs-bg); }
/* ===== Topbar (identisch zu glossar.php) ===== */
.md-topbar {
background: var(--ggs-white);
padding: .55rem 1.2rem;
display: flex; align-items: center; gap: .8rem;
border-bottom: 1px solid var(--ggs-border);
position: sticky; top: 0; z-index: 50;
}
.md-topbar a { text-decoration: none; }
.md-topbar-brand { display: flex; align-items: center; gap: .5rem; }
.md-topbar-brand img.md-text { height: 40px; display: block; }
.md-topbar .spacer { flex: 1; }
.md-btn-sm {
/* iPad-Touch: min 40px Höhe; padding angepasst */
padding: .5rem .85rem; border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-sm); background: var(--ggs-white);
font-size: .78rem; font-weight: 600; cursor: pointer;
color: var(--ggs-text); font-family: inherit; text-decoration: none;
display: inline-flex; align-items: center; min-height: 40px;
}
.md-btn-sm:hover { background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark); border-color: var(--ggs-fjord); }
.md-btn-sm:active { transform: scale(0.97); }
.md-btn-sm.md-btn-primary { background: var(--ggs-fjord); color: var(--ggs-white); border-color: var(--ggs-fjord); }
.md-btn-sm.md-btn-primary:hover { background: var(--ggs-fjord-dark); }
.md-easy-pill {
background: var(--ggs-moss-light); color: var(--ggs-moss-dark);
border-color: var(--ggs-moss); font-weight: 700;
}
/* ===== Breadcrumb ===== */
.md-breadcrumb {
max-width: 1100px; margin: 0 auto; padding: .9rem 1.2rem .2rem;
font-size: .82rem; color: var(--ggs-text-muted);
}
.md-breadcrumb a { color: var(--ggs-fjord); text-decoration: none; }
.md-breadcrumb a:hover { text-decoration: underline; }
.md-breadcrumb .sep { margin: 0 .4rem; opacity: .5; }
.md-preview-banner {
max-width: 1100px; margin: .8rem auto 0; padding: .8rem 1.2rem;
background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark);
border-left: 4px solid var(--ggs-fjord);
border-radius: var(--ggs-radius-sm);
font-size: .92rem; line-height: 1.5;
}
/* ===== Hero ===== */
.md-hero {
max-width: 1100px; margin: 0 auto; padding: 1.5rem 1.2rem 2rem;
display: grid; grid-template-columns: minmax(220px, 340px) 1fr;
gap: 2rem; align-items: center;
}
.md-hero-card {
background: var(--ggs-white); border-radius: var(--ggs-radius-lg);
overflow: hidden; box-shadow: var(--ggs-shadow-md);
border: 1px solid var(--ggs-border);
}
.md-hero-card img {
width: 100%; aspect-ratio: 1; object-fit: cover; display: block;
}
.md-hero-text h1 {
font-size: clamp(1.8rem, 4vw, 2.6rem);
font-weight: 900; letter-spacing: -.03em;
color: var(--ggs-fjord-dark);
display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
margin-bottom: .4rem;
}
.md-hero-icon { font-size: 1.3em; }
.md-hero-subtitle {
font-size: 1.1rem; color: var(--ggs-text); line-height: 1.5;
margin-bottom: 1.4rem;
}
.md-hero-cta { display: flex; flex-wrap: wrap; gap: .6rem; }
.md-cta-btn {
/* iPad-Touch: generous padding, min 44px */
display: inline-flex; align-items: center; gap: .5rem;
padding: .85rem 1.5rem; border-radius: var(--ggs-radius-sm);
font-weight: 700; font-size: 1rem; text-decoration: none;
border: 1.5px solid transparent; transition: all .2s var(--ggs-ease);
min-height: 48px;
}
.md-cta-primary { background: var(--ggs-fjord); color: var(--ggs-white); }
.md-cta-primary:hover { background: var(--ggs-fjord-dark); transform: translateY(-1px); }
.md-cta-primary:active { transform: scale(0.98); }
.md-cta-secondary {
background: var(--ggs-white); color: var(--ggs-fjord);
border-color: var(--ggs-fjord);
}
.md-cta-secondary:hover { background: var(--ggs-fjord-light); }
.md-cta-secondary:active { transform: scale(0.98); }
/* Geräte-Hinweis unter den CTAs (z.B. WebGL-Hinweis bei Klima 3D) */
.md-device-hint {
margin-top: .9rem; max-width: 560px;
font-size: .85rem; line-height: 1.5; color: var(--ggs-text-muted);
padding: .7rem .9rem;
background: var(--ggs-fjord-light);
border-radius: var(--ggs-radius-sm);
border-left: 3px solid var(--ggs-fjord);
}
.md-device-hint strong { color: var(--ggs-fjord-dark); }
/* ===== Meta-Bar (Dauer, Alter, Status) ===== */
.md-meta {
max-width: 1100px; margin: 0 auto 2rem; padding: 0 1.2rem;
display: flex; flex-wrap: wrap; gap: .6rem;
}
.md-meta-item {
display: inline-flex; align-items: center; gap: .4rem;
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-pill);
padding: .5rem .95rem;
font-size: .88rem; color: var(--ggs-text);
min-height: 36px;
}
.md-meta-icon { font-size: 1rem; }
.md-meta-label { color: var(--ggs-text-muted); font-weight: 600; }
.md-meta-value { font-weight: 700; }
.md-status-pill { padding: 2px 10px; border-radius: var(--ggs-radius-pill); font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.md-status-aktiv { background: var(--ggs-moss-light); color: var(--ggs-moss-dark); }
.md-status-beta { background: var(--ggs-sand); color: #7a6540; }
.md-status-geplant { background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark); }
/* ===== Sections ===== */
.md-section {
max-width: 1100px; margin: 0 auto 2.5rem; padding: 0 1.2rem;
}
.md-section-title {
font-size: .75rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .12em; color: var(--ggs-fjord);
margin-bottom: .4rem;
}
.md-section-h2 {
font-size: 1.7rem; font-weight: 900; color: var(--ggs-fjord-dark);
letter-spacing: -.02em; margin-bottom: .9rem;
}
.md-section-text {
font-size: 1rem; line-height: 1.7; color: var(--ggs-text); max-width: 780px;
}
/* Lernziele-Grid */
.md-goals {
display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1rem; margin-top: 1rem;
}
.md-goal {
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-left: 4px solid var(--ggs-moss);
border-radius: var(--ggs-radius-md); padding: 1rem 1.2rem;
font-size: .95rem; line-height: 1.5;
}
.md-goal-num {
display: inline-block; font-size: .72rem; font-weight: 800;
color: var(--ggs-moss-dark); background: var(--ggs-moss-light);
padding: 2px 8px; border-radius: var(--ggs-radius-pill);
margin-bottom: .4rem;
}
/* Glossar-Chips */
.md-glossar {
display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1rem;
}
.md-glossar-chip {
/* iPad-Touch: min 40px Höhe */
display: inline-flex; align-items: center; gap: .3rem;
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-pill);
padding: .5rem 1rem; min-height: 40px;
font-size: .88rem; font-weight: 600; color: var(--ggs-fjord-dark);
text-decoration: none; transition: all .2s var(--ggs-ease);
cursor: pointer;
}
.md-glossar-chip:hover, .md-glossar-chip:active {
background: var(--ggs-fjord-light); border-color: var(--ggs-fjord);
}
.md-glossar-empty { color: var(--ggs-text-muted); font-size: .9rem; font-style: italic; }
.md-glossar-link {
display: inline-block; margin-top: 1rem;
font-size: .9rem; color: var(--ggs-fjord); text-decoration: none; font-weight: 600;
padding: .4rem 0; /* vergrossertes Touch-Ziel ohne Rahmen */
}
.md-glossar-link:hover { text-decoration: underline; }
/* Lehrplan-Bezug */
.md-lehrplan-filters {
display: flex; flex-wrap: wrap; gap: .5rem; margin: 1rem 0 1.2rem;
}
.md-chip {
/* iPad-Touch: min 40x40 */
display: inline-flex; align-items: center; gap: .3rem;
padding: .55rem 1rem; border-radius: var(--ggs-radius-pill);
background: var(--ggs-white); border: 1.5px solid var(--ggs-border);
font-size: .88rem; font-weight: 600; color: var(--ggs-text-muted);
cursor: pointer; transition: all .2s var(--ggs-ease); font-family: inherit;
min-height: 40px; min-width: 40px;
}
.md-chip:hover { border-color: var(--ggs-fjord); color: var(--ggs-fjord); }
.md-chip:active { transform: scale(0.96); }
.md-chip.active { background: var(--ggs-fjord); color: var(--ggs-white); border-color: var(--ggs-fjord); }
.md-kompetenz {
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-md); padding: 1.2rem 1.4rem 1rem;
margin-bottom: 1rem;
}
.md-kompetenz-header { display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap; margin-bottom: .4rem; }
.md-kompetenz-title { font-size: 1.15rem; font-weight: 800; color: var(--ggs-fjord-dark); }
.md-kompetenz-strength {
font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
padding: 2px 8px; border-radius: var(--ggs-radius-pill);
}
.md-strength-primaer { background: var(--ggs-moss-light); color: var(--ggs-moss-dark); }
.md-strength-sekundaer { background: var(--ggs-bg-dark); color: var(--ggs-text-muted); }
.md-kompetenz-desc {
font-size: .9rem; color: var(--ggs-text); line-height: 1.55;
margin-bottom: .9rem;
}
.md-anchors { display: grid; gap: .55rem; }
.md-anchor {
display: grid; grid-template-columns: 28px 1fr; gap: .6rem; align-items: start;
font-size: .9rem; padding: .6rem .8rem;
background: var(--ggs-bg); border-radius: var(--ggs-radius-sm);
border-left: 3px solid var(--ggs-fjord-light);
}
.md-anchor-flag { font-size: 1.2rem; line-height: 1.3; text-align: center; }
.md-anchor-meta { font-size: .75rem; color: var(--ggs-text-muted); margin-bottom: .15rem; }
.md-anchor-title { font-weight: 700; color: var(--ggs-fjord-dark); margin-bottom: .2rem; }
.md-anchor-quote { font-size: .88rem; color: var(--ggs-text); font-style: italic; line-height: 1.45; }
.md-anchor-ref {
font-size: .72rem; color: var(--ggs-text-muted);
margin-top: .3rem;
}
.md-anchor-link {
color: var(--ggs-fjord); text-decoration: none; font-weight: 600;
border-bottom: 1px dotted var(--ggs-fjord); transition: color .2s var(--ggs-ease);
padding: 2px 0; /* Touch-Ziel leicht vergroessern */
}
.md-anchor-link:hover { color: var(--ggs-fjord-dark); border-bottom-style: solid; }
/* Anker-Gruppen (Fach / Fächerübergreifend / Andere Fächer) */
.md-anchor-group { margin-top: .9rem; }
.md-anchor-group:first-child { margin-top: 0; }
.md-anchor-group-head {
display: flex; align-items: baseline; gap: .6rem;
margin: .2rem 0 .5rem;
flex-wrap: wrap;
}
.md-anchor-group-title {
font-size: .74rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .1em; color: var(--ggs-fjord-dark);
}
.md-anchor-group-sub {
font-size: .72rem; color: var(--ggs-text-muted); font-weight: 500;
}
.md-anchor--fach { border-left-color: var(--ggs-fjord); }
.md-anchor--uebergreifendes_thema { border-left-color: var(--ggs-moss); background: var(--ggs-moss-light); }
.md-anchor--anderes_fach { border-left-color: var(--ggs-sand-dark); background: var(--ggs-bg-dark); }
.md-anchor--uebergreifendes_thema .md-anchor-flag,
.md-anchor--anderes_fach .md-anchor-flag { opacity: .65; }
.md-anchor.hidden { display: none; }
.md-lehrplan-note {
font-size: .82rem; color: var(--ggs-text-muted); font-style: italic;
margin-top: 1rem; max-width: 780px;
}
/* ===== Footer ===== */
.md-footer {
text-align: center; padding: 2rem 1rem 2.5rem;
font-size: .78rem; color: var(--ggs-text-muted);
border-top: 1px solid var(--ggs-border);
background: var(--ggs-white);
margin-top: 2rem;
}
.md-footer img { height: 36px; opacity: .5; margin-bottom: .5rem; }
.md-footer a { color: var(--ggs-fjord); text-decoration: none; padding: .3rem .2rem; }
.md-footer a:hover { text-decoration: underline; }
/* Responsive — Design-System-konforme Breakpoints 900 / 1200 */
@media (max-width: 900px) {
.md-hero { grid-template-columns: 1fr; gap: 1rem; padding-top: 1rem; }
.md-hero-card { max-width: 260px; margin: 0 auto; }
.md-hero-text { text-align: center; }
.md-hero-cta { justify-content: center; }
.md-meta { justify-content: center; }
.md-section-h2 { font-size: 1.35rem; }
}
</style>
</head>
<body>
<!-- Einheitlicher Header -->
<header class="md-topbar">
<a href="<?= $bp ?>/index.html" class="md-topbar-brand" aria-label="GeoGraSim Startseite">
<img class="md-text" src="<?= $bp ?>/assets/img/geograsim_t.svg" alt="GeoGraSim">
</a>
<span class="spacer"></span>
<?php if ($easyActive): ?>
<span class="md-btn-sm md-easy-pill" title="Leichte Sprache ist aktiv">🟢 Leichte Sprache</span>
<?php endif; ?>
<?php include __DIR__ . '/country_picker.php'; ?>
<a href="<?= $bp ?>/pages/simulationen.php" class="md-btn-sm">Alle Simulationen</a>
<a href="<?= $bp ?>/pages/lehrplan.php" class="md-btn-sm">Lehrplan</a>
<a href="<?= $bp ?>/glossar" class="md-btn-sm">Glossar</a>
<a href="<?= $bp ?>/login.html" class="md-btn-sm md-btn-primary">Anmelden</a>
</header>
<nav class="md-breadcrumb" aria-label="Brotkrumen">
<a href="<?= $bp ?>/index.html">Start</a>
<span class="sep"></span>
<a href="<?= $bp ?>/pages/simulationen.php">Simulationen</a>
<span class="sep"></span>
<span><?= esc($module['title']) ?></span>
</nav>
<?php if ($module['status'] === 'geplant'): ?>
<div class="md-preview-banner" role="status">
🔧 <strong>Vorschau</strong> — dieses Modul ist noch in Entwicklung. Lernziele,
Begriffe und Lehrplan-Bezug werden laufend ergänzt. Die Simulation selbst
ist noch nicht verfügbar.
</div>
<?php endif; ?>
<!-- HERO -->
<section class="md-hero">
<div class="md-hero-card">
<img src="<?= $bp ?>/assets/img/<?= esc($module['card_image']) ?>" alt="<?= esc($module['title']) ?>">
</div>
<div class="md-hero-text">
<h1><span class="md-hero-icon"><?= esc($module['icon']) ?></span><?= esc($module['title']) ?></h1>
<p class="md-hero-subtitle"><?= esc($shortDesc ?? $module['subtitle']) ?></p>
<div class="md-hero-cta">
<?php if ($MODULE_ID === 'klima'): ?>
<!-- Sonderfall: Klima hat zwei Varianten (2D + 3D). Beide starten dasselbe Level-
system, sind didaktisch identisch; die 3D-Variante benoetigt WebGL. -->
<a href="<?= $bp ?>/klima-2d?level=1" class="md-cta-btn md-cta-primary">
▶ 2D starten
</a>
<a href="<?= $bp ?>/klima-3d?level=1" class="md-cta-btn md-cta-secondary">
▶ 3D starten
</a>
<?php elseif ($module['status'] === 'aktiv' || $module['status'] === 'beta'): ?>
<a href="<?= $bp ?>/<?= esc($module['play_url']) ?>" class="md-cta-btn md-cta-primary">
▶ Simulation starten
</a>
<?php else: ?>
<a href="<?= $bp ?>/login.html" class="md-cta-btn md-cta-primary">
🔒 In Entwicklung — Newsletter
</a>
<?php endif; ?>
<a href="#lehrplan-bezug" class="md-cta-btn md-cta-secondary">
📘 Lehrplan-Bezug
</a>
</div>
<?php if ($MODULE_ID === 'klima'): ?>
<p class="md-device-hint">
<strong>3D benötigt WebGL</strong> und etwas Rechenleistung. Läuft flüssig
auf iPads ab Generation 8 und auf Laptops ab 2019. Auf älteren Geräten
empfehlen wir die 2D-Variante — didaktisch identisch, gleiches Level-System.
</p>
<?php endif; ?>
</div>
</section>
<!-- META -->
<div class="md-meta">
<?php if (!empty($module['duration_min'])): ?>
<span class="md-meta-item">
<span class="md-meta-icon">⏱️</span>
<span class="md-meta-label">Dauer:</span>
<span class="md-meta-value">ca. <?= (int)$module['duration_min'] ?> Min</span>
</span>
<?php endif; ?>
<?php if (!empty($module['age_min']) && !empty($module['age_max'])): ?>
<span class="md-meta-item">
<span class="md-meta-icon">👧</span>
<span class="md-meta-label">Alter:</span>
<span class="md-meta-value"><?= (int)$module['age_min'] ?><?= (int)$module['age_max'] ?> Jahre</span>
</span>
<?php endif; ?>
<span class="md-meta-item">
<span class="md-meta-icon">🏷️</span>
<span class="md-meta-label">Modul-ID:</span>
<code style="font-size: .82rem;"><?= esc($module['module_id']) ?></code>
</span>
<span class="md-meta-item">
<span class="md-meta-label">Status:</span>
<span class="md-status-pill md-status-<?= esc($module['status']) ?>"><?= esc($module['status']) ?></span>
</span>
<span class="md-meta-item">
<span class="md-meta-icon">📚</span>
<span class="md-meta-label">Begriffe im Glossar:</span>
<span class="md-meta-value"><?= count($glossarTerms) ?></span>
</span>
</div>
<!-- WAS LERNST DU -->
<?php if (!empty($learningGoals)): ?>
<section class="md-section">
<div class="md-section-title">Was lernst du?</div>
<h2 class="md-section-h2">Lernziele dieses Moduls</h2>
<div class="md-goals">
<?php foreach ($learningGoals as $i => $g): ?>
<div class="md-goal">
<span class="md-goal-num"><?= str_pad((string)($i+1), 2, '0', STR_PAD_LEFT) ?></span>
<div><?= esc($g) ?></div>
</div>
<?php endforeach; ?>
</div>
</section>
<?php endif; ?>
<!-- WIE FUNKTIONIERT'S -->
<?php if (!empty($longDesc)): ?>
<section class="md-section">
<div class="md-section-title">Wie funktioniert's?</div>
<h2 class="md-section-h2">Die Simulation</h2>
<p class="md-section-text"><?= nl2br(esc($longDesc)) ?></p>
</section>
<?php endif; ?>
<!-- BEGRIFFE AUS DEM GLOSSAR -->
<section class="md-section">
<div class="md-section-title">Begriffe, die du kennenlernst</div>
<h2 class="md-section-h2">Glossar-Einträge zu diesem Modul</h2>
<?php if (empty($glossarTerms)): ?>
<p class="md-glossar-empty">Noch keine Begriffe zugeordnet — das Glossar wächst laufend weiter.</p>
<?php else: ?>
<div class="md-glossar">
<?php foreach ($glossarTerms as $t): ?>
<a class="md-glossar-chip"
href="<?= $bp ?>/glossar?term=<?= urlencode($t['key_slug']) ?>"
title="<?= esc($t['short']) ?>">
<?= esc($t['title']) ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<a class="md-glossar-link" href="<?= $bp ?>/glossar?module=<?= urlencode($MODULE_ID) ?>">
→ Alle <?= count($glossarTerms) ?> Begriffe im Glossar ansehen
</a>
</section>
<!-- LEHRPLAN-BEZUG -->
<section class="md-section" id="lehrplan-bezug">
<div class="md-section-title">Für Lehrpersonen</div>
<h2 class="md-section-h2">Lehrplan-Bezug</h2>
<p class="md-section-text">
Dieses Modul bedient die folgenden didaktischen Kompetenzbereiche. Für jeden
Bereich haben wir typische Verankerungen in den Lehrplänen für
Österreich, Deutschland, Schweiz und Liechtenstein recherchiert — sie
helfen, das Modul an den eigenen Lehrplan anzudocken.
</p>
<div class="md-lehrplan-filters" id="md-filter-row">
<button type="button" class="md-chip<?= $qCountry === '' ? ' active' : '' ?>" data-country="">🌐 Alle Länder</button>
<?php foreach ($countryMeta as $c => $info): ?>
<button type="button" class="md-chip<?= $qCountry === $c ? ' active' : '' ?>" data-country="<?= esc($c) ?>">
<?= $info['flag'] ?> <?= esc($info['label']) ?>
</button>
<?php endforeach; ?>
</div>
<?php if (empty($kompetenzen)): ?>
<p class="md-glossar-empty">Noch keine Kompetenzen zugeordnet.</p>
<?php else: ?>
<?php foreach ($kompetenzen as $k): ?>
<article class="md-kompetenz">
<header class="md-kompetenz-header">
<div class="md-kompetenz-title"><?= esc($k['title']) ?></div>
<span class="md-kompetenz-strength md-strength-<?= esc($k['strength']) ?>">
<?= $k['strength'] === 'primaer' ? 'Primär' : 'Sekundär' ?>
</span>
</header>
<?php if (!empty($k['description'])): ?>
<p class="md-kompetenz-desc"><?= esc($k['description']) ?></p>
<?php endif; ?>
<?php
$groups = [
['anchors_fach', 'Fachbezug', 'Direkte Zuordnung im Fach-Lehrplan'],
['anchors_uebergreifend', 'Fächerübergreifende Themen', 'Verbindliche Querschnittsthemen des Lehrplans'],
['anchors_andere_faecher', 'Anknüpfungspunkte in anderen Fächern', 'Wo das Thema zusätzlich auftaucht'],
];
foreach ($groups as [$key, $heading, $sub]):
$list = $k[$key] ?? [];
if (empty($list)) continue;
?>
<div class="md-anchor-group">
<div class="md-anchor-group-head">
<span class="md-anchor-group-title"><?= esc($heading) ?></span>
<span class="md-anchor-group-sub"><?= esc($sub) ?></span>
</div>
<div class="md-anchors">
<?php foreach ($list as $a): ?>
<?php $cm = $countryMeta[$a['country']] ?? ['flag' => '🏳️', 'label' => $a['country']]; ?>
<div class="md-anchor md-anchor--<?= esc($a['anchor_type']) ?>"
data-country="<?= esc($a['country']) ?>">
<div class="md-anchor-flag" title="<?= esc($cm['label']) ?>"><?= $cm['flag'] ?></div>
<div>
<div class="md-anchor-meta">
<strong><?= esc($a['country']) ?></strong>
<?= $a['region'] ? ' · ' . esc($a['region']) : '' ?>
<?= $a['school_type'] ? ' · ' . esc($a['school_type']) : '' ?>
<?= $a['grade'] ? ' · ' . esc($a['grade']) : '' ?>
<?= $a['subject'] ? ' · ' . esc($a['subject']) : '' ?>
</div>
<div class="md-anchor-title"><?= esc($a['title']) ?></div>
<?php if (!empty($a['quote'])): ?>
<div class="md-anchor-quote">„<?= esc($a['quote']) ?>"</div>
<?php endif; ?>
<?php if (!empty($a['reference'])): ?>
<div class="md-anchor-ref">
Quelle:
<?php if (!empty($a['reference_url'])): ?>
<a href="<?= esc($a['reference_url']) ?>"
target="_blank" rel="noopener noreferrer"
class="md-anchor-link"><?= esc($a['reference']) ?> ↗</a>
<?php else: ?>
<?= esc($a['reference']) ?>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</article>
<?php endforeach; ?>
<?php endif; ?>
<p class="md-lehrplan-note">
Die Anker sind beispielhaft ausgewählt — bitte mit dem konkreten
Jahres- oder Semesterplan abgleichen. Vollständige Lehrplan-Übersicht:
<a href="<?= $bp ?>/pages/lehrplan.php">Lehrplan-Seite</a>.
</p>
</section>
<!-- Footer -->
<footer class="md-footer">
<img src="<?= $bp ?>/assets/img/bildLogo.png" alt="">
<div>
Lehrplan geograsim.at ·
<a href="<?= $bp ?>/pages/simulationen.php">Simulationen</a> ·
<a href="<?= $bp ?>/pages/lehrplan.php">Lehrplan</a> ·
<a href="<?= $bp ?>/glossar">Glossar</a> ·
<a href="<?= $bp ?>/ueber.html">Über</a> ·
<a href="<?= $bp ?>/impressum.html">Impressum</a> ·
<a href="<?= $bp ?>/datenschutz.html">Datenschutz</a>
</div>
<?php include __DIR__ . '/country_footer.php'; ?>
</footer>
<script>
// Länder-Filter für Lehrplan-Anker. Default ist das aktuell gewählte Land
// (über Country-Helper aus Session/Cookie, Standardwert AT).
//
// Logik:
// - Bei einem konkreten Land (AT/DE/CH/LI):
// • anchor_type='fach' wird nach Land gefiltert (nur passende sichtbar)
// • anchor_type='uebergreifendes_thema' und 'anderes_fach' bleiben
// immer sichtbar — sie sind primär aus dem AT-Lehrplan abgeleitet,
// aber didaktisch land-agnostisch nutzbar
// - "🌐 Alle Länder": alles sichtbar
(function () {
const filterRow = document.getElementById('md-filter-row');
if (!filterRow) return;
function applyFilter(country) {
document.querySelectorAll('.md-anchor').forEach(a => {
const type = a.dataset.anchorType;
const aCountry = a.dataset.country;
let hide = false;
if (country) {
// Konkretes Land gewählt: Fach-Anker streng filtern,
// übergreifende + andere Fächer immer zeigen.
if (type === 'fach') {
hide = aCountry !== country;
}
}
a.classList.toggle('hidden', hide);
});
}
filterRow.addEventListener('click', (e) => {
const btn = e.target.closest('.md-chip');
if (!btn) return;
filterRow.querySelectorAll('.md-chip').forEach(c => c.classList.remove('active'));
btn.classList.add('active');
applyFilter(btn.dataset.country);
});
// Initial-Filter anwenden (für den server-seitig vor-gewählten Default)
const activeChip = filterRow.querySelector('.md-chip.active');
if (activeChip) applyFilter(activeChip.dataset.country);
})();
</script>
</body>
</html>