9937fbf62a
Der Filter-JS liest a.dataset.anchorType, aber die Anker-<div>s setzten kein data-anchor-type (nur data-country). Dadurch war `type === 'fach'` nie wahr → für ein gewähltes Land wurde nie ein Anker ausgeblendet. Fix: data-anchor-type am Anker-div ergänzt. Gilt für alle Modul-Seiten. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
798 lines
33 KiB
PHP
798 lines
33 KiB
PHP
<?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;
|
||
}
|
||
|
||
/* Bildergalerie (modul-spezifisch eingespielt) */
|
||
.md-gallery {
|
||
display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||
gap: 14px; margin-top: 1rem;
|
||
}
|
||
.md-gallery-item {
|
||
margin: 0; background: var(--ggs-white); border: 1px solid var(--ggs-border);
|
||
border-radius: var(--ggs-radius-md); overflow: hidden;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,.05);
|
||
transition: transform .2s, box-shadow .2s;
|
||
}
|
||
.md-gallery-item:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,.12); }
|
||
.md-gallery-item img {
|
||
display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover;
|
||
}
|
||
.md-gallery-item figcaption {
|
||
padding: 10px 14px 14px; font-size: .88rem; line-height: 1.45;
|
||
color: var(--ggs-text-muted);
|
||
}
|
||
|
||
/* 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_ID === 'kofferdetektiv'): ?>
|
||
<!-- Kofferdetektiv: 3D-Hauptvariante (mit Three.js), 2D-Variante in Vorbereitung. -->
|
||
<a href="<?= $bp ?>/kofferdetektiv-3d" class="md-cta-btn md-cta-primary">
|
||
▶ 3D starten
|
||
</a>
|
||
<a href="<?= $bp ?>/kofferdetektiv-2d" class="md-cta-btn md-cta-secondary">
|
||
▶ 2D starten (in Vorbereitung)
|
||
</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 elseif ($MODULE_ID === 'kofferdetektiv'): ?>
|
||
<p class="md-device-hint">
|
||
<strong>3D benötigt WebGL</strong> und ca. 2 MB Download (Flughafen-Modell + Texturen).
|
||
Läuft flüssig auf iPads ab Generation 8 und Laptops ab 2019. Die 2D-Variante
|
||
kommt in einer späteren Phase — sie wird leichtgewichtiger und reine Touch-fokussiert sein.
|
||
</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; ?>
|
||
|
||
<!-- BILDERGALERIE — modul-spezifisch -->
|
||
<?php
|
||
$gallery = [];
|
||
if ($MODULE_ID === 'kofferdetektiv') {
|
||
$simBase = $bp . '/sims/kofferdetektiv/assets/img';
|
||
$gallery = [
|
||
['src' => $simBase . '/intro/intro-koffer.webp', 'caption' => 'Im Koffer warten die Fundsachen darauf, untersucht zu werden.'],
|
||
['src' => $simBase . '/intro/intro-terminal.webp', 'caption' => 'Die nächtliche Gepäckhalle — dein Arbeitsplatz im Spätdienst.'],
|
||
['src' => $simBase . '/intro/intro-radar.webp', 'caption' => 'Per Radar findest du Koffer, die als verloren gemeldet wurden.'],
|
||
['src' => $simBase . '/intro/intro-welt.webp', 'caption' => 'Aus rund 190 Ländern musst du das richtige herausfinden.'],
|
||
['src' => $simBase . '/intro/fall-abgeben.webp', 'caption' => 'Nach jedem Fall fasst dein Endbericht zusammen, was du gelernt hast.'],
|
||
];
|
||
}
|
||
?>
|
||
<?php if (!empty($gallery)): ?>
|
||
<section class="md-section">
|
||
<div class="md-section-title">Einblicke</div>
|
||
<h2 class="md-section-h2">Wie sieht die Simulation aus?</h2>
|
||
<div class="md-gallery">
|
||
<?php foreach ($gallery as $img): ?>
|
||
<figure class="md-gallery-item">
|
||
<img src="<?= esc($img['src']) ?>" alt="<?= esc($img['caption']) ?>" loading="lazy">
|
||
<figcaption><?= esc($img['caption']) ?></figcaption>
|
||
</figure>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</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']) ?>"
|
||
target="_blank" rel="noopener"
|
||
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) ?>"
|
||
target="_blank" rel="noopener">
|
||
→ 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-anchor-type="<?= 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>
|