Files
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

757 lines
32 KiB
PHP
Raw Permalink 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
/**
* Lehrplan-Übersicht
* -------------------
* Gesammelte Lehrplan-Verankerungen für alle Simulationen, gruppiert nach
* didaktischem Kompetenzbereich, mit Filter für Land (AT/DE/CH/LI), Thema
* und Anker-Typ.
*
* URL: http://localhost/geograsim/App/lehrplan (Front-Controller)
* ?country=AT vorgewählter Länder-Filter (Default: AT)
* ?theme=klima vorgewählter Themen-Filter
* ?module=fluss vorgewähltes Modul
*/
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();
// Filter: Default ist das aktuelle Landes-Setting (Kaskade), per URL überschreibbar
$allowedCountries = ['AT', 'DE', 'CH', 'LI'];
if (isset($_GET['country'])) {
$qCountry = strtoupper(trim($_GET['country']));
if (!in_array($qCountry, $allowedCountries, true) && $qCountry !== 'ALL') {
$qCountry = Country::current();
}
} else {
$qCountry = Country::current();
}
$qTheme = preg_replace('/[^a-z0-9_-]/', '', strtolower($_GET['theme'] ?? ''));
$qModule = preg_replace('/[^a-z0-9_-]/', '', strtolower($_GET['module'] ?? ''));
// Wenn `?module=X` gesetzt: Metadaten des Moduls laden (fuer Banner + Titel)
$moduleFocus = null;
if ($qModule !== '') {
$stmt = $db->prepare('SELECT module_id, title, icon, card_image, status, page_url FROM module_info WHERE module_id = ?');
$stmt->execute([$qModule]);
$moduleFocus = $stmt->fetch() ?: null;
if (!$moduleFocus) $qModule = ''; // ungueltiger Slug
}
// Kompetenzen laden — optional gefiltert auf Modul-Zuordnungen
if ($qModule !== '') {
$stmt = $db->prepare('
SELECT k.id, k.key_slug, k.title, k.description, k.category, k.age_min, k.age_max, k.sort_order
FROM kompetenzen k
INNER JOIN kompetenz_modules km ON km.kompetenz_id = k.id
WHERE km.module_id = ?
GROUP BY k.id
ORDER BY k.sort_order, k.title
');
$stmt->execute([$qModule]);
$kompetenzen = $stmt->fetchAll();
} else {
$kompetenzen = $db->query('
SELECT id, key_slug, title, description, category, age_min, age_max, sort_order
FROM kompetenzen
ORDER BY sort_order, title
')->fetchAll();
}
// Module je Kompetenz — nur aktive/beta-Sims, keine geplanten oder archivierten
$modStmt = $db->prepare("
SELECT mi.module_id, mi.title, mi.icon, mi.card_image, mi.status, mi.page_url,
km.strength
FROM kompetenz_modules km
INNER JOIN module_info mi ON mi.module_id = km.module_id
WHERE km.kompetenz_id = ?
AND mi.status IN ('aktiv','beta')
ORDER BY FIELD(km.strength, 'primaer', 'sekundaer'), mi.sort_order
");
// Anker je Kompetenz
$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) {
$modStmt->execute([$k['id']]);
$k['modules'] = $modStmt->fetchAll();
$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'));
$k['anchors_all'] = $rows;
}
unset($k);
// Zählungen (global) für Filter-Badges
$totalAnchors = (int) $db->query('SELECT COUNT(*) FROM lehrplan_anchors')->fetchColumn();
$countsByCountry = [];
foreach ($db->query("SELECT country, COUNT(*) AS n FROM lehrplan_anchors GROUP BY country") as $r) {
$countsByCountry[$r['country']] = (int)$r['n'];
}
$countsByType = [];
foreach ($db->query("SELECT anchor_type, COUNT(*) AS n FROM lehrplan_anchors GROUP BY anchor_type") as $r) {
$countsByType[$r['anchor_type']] = (int)$r['n'];
}
/* N.5.2 — Transparenz-Zähler: wie viele Anker werden für die aktuelle Land-Auswahl
tatsächlich sichtbar (Fach-Anker des Landes + alle übergreifenden Anker land-agnostisch) */
$factForCountryStmt = $db->prepare(
"SELECT COUNT(*) FROM lehrplan_anchors WHERE anchor_type = 'fach' AND country = ?"
);
if ($qCountry !== 'ALL') {
$factForCountryStmt->execute([$qCountry]);
$visibleFach = (int)$factForCountryStmt->fetchColumn();
} else {
$visibleFach = (int)($countsByType['fach'] ?? 0);
}
$visibleUniversal = (int)(($countsByType['uebergreifendes_thema'] ?? 0) + ($countsByType['anderes_fach'] ?? 0));
$bp = BASE_PATH;
$easyActive = EasyLang::isActive();
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'],
];
$categoryMeta = [
'klima' => ['label' => 'Klima'],
'natur' => ['label' => 'Naturgefahren'],
'raum' => ['label' => 'Raum'],
'gesellschaft' => ['label' => 'Gesellschaft'],
];
?><!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><?= $moduleFocus ? 'Lehrplan-Bezug: ' . esc($moduleFocus['title']) : 'Lehrplan-Übersicht' ?> — Lehrplan geograsim.at</title>
<meta name="description" content="<?= $moduleFocus ? 'Lehrplan-Verankerung der Simulation ' . esc($moduleFocus['title']) . ' in Österreich, Deutschland, Schweiz und Liechtenstein.' : 'Alle Lehrplan-Verankerungen der GeoGraSim-Simulationen für Österreich, Deutschland, Schweiz und Liechtenstein — gruppiert nach didaktischem Kompetenzbereich.' ?>">
<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>
body { overflow: auto; height: auto; min-height: 100dvh; background: var(--ggs-bg); }
/* ===== Topbar (wie modul-detail) ===== */
.lp-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;
}
.lp-topbar a { text-decoration: none; }
.lp-topbar-brand img { height: 40px; display: block; }
.lp-topbar .spacer { flex: 1; }
.lp-btn-sm {
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;
}
.lp-btn-sm:hover { background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark); border-color: var(--ggs-fjord); }
.lp-btn-sm.lp-btn-primary { background: var(--ggs-fjord); color: var(--ggs-white); border-color: var(--ggs-fjord); }
.lp-easy-pill { background: var(--ggs-moss-light); color: var(--ggs-moss-dark); border-color: var(--ggs-moss); font-weight: 700; }
/* ===== Modul-Fokus-Banner (bei ?module=X) ===== */
.lp-focus-banner {
background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark);
border-bottom: 1px solid var(--ggs-border);
padding: .9rem 1.5rem;
display: flex; align-items: center; gap: 1rem;
flex-wrap: wrap;
}
.lp-focus-icon { font-size: 1.8rem; line-height: 1; }
.lp-focus-text { flex: 1; min-width: 200px; display: flex; flex-direction: column; gap: 2px; }
.lp-focus-text strong { font-size: 1rem; font-weight: 800; }
.lp-focus-sub { font-size: .82rem; color: var(--ggs-text-muted); }
.lp-focus-action {
display: inline-flex; align-items: center; min-height: 36px;
padding: .4rem .9rem; border-radius: var(--ggs-radius-pill);
background: var(--ggs-white); color: var(--ggs-fjord-dark);
border: 1px solid var(--ggs-fjord);
font-size: .82rem; font-weight: 600; text-decoration: none;
transition: all .2s var(--ggs-ease);
}
.lp-focus-action:hover { background: var(--ggs-fjord); color: var(--ggs-white); }
/* ===== Hero ===== */
.lp-hero {
background: linear-gradient(135deg, var(--ggs-fjord-dark) 0%, var(--ggs-fjord) 100%);
color: var(--ggs-white);
padding: 2.5rem 1.5rem 3rem;
text-align: center;
}
.lp-hero h1 {
font-size: clamp(1.8rem, 4vw, 2.6rem);
font-weight: 900; letter-spacing: -.03em;
margin-bottom: .5rem;
}
.lp-hero p { font-size: 1.02rem; color: rgba(255,255,255,.88); max-width: 640px; margin: 0 auto 1.4rem; }
.lp-hero-stats { display: flex; justify-content: center; gap: 2rem; flex-wrap: wrap; margin-top: 1.2rem; }
.lp-hero-stat { text-align: center; }
.lp-hero-stat-num { font-size: 1.8rem; font-weight: 900; display: block; }
.lp-hero-stat-lbl { font-size: .72rem; opacity: .8; text-transform: uppercase; letter-spacing: .08em; }
/* ===== Transparenz-Zeile (N.5.2) ===== */
.lp-context-line {
max-width: 1100px; margin: 1rem auto .8rem; padding: .7rem 1.1rem;
background: var(--ggs-fjord-light); border-left: 4px solid var(--ggs-fjord);
border-radius: 6px; font-size: .82rem; color: var(--ggs-fjord-dark);
line-height: 1.5;
}
.lp-context-line strong { color: var(--ggs-fjord-dark); font-weight: 800; }
/* ===== Filter-Bar ===== */
.lp-filters {
max-width: 1100px; margin: -1.4rem auto 1.5rem;
padding: 1rem 1.2rem; background: var(--ggs-white);
border-radius: var(--ggs-radius-lg); box-shadow: var(--ggs-shadow-lg);
border: 1px solid var(--ggs-border);
position: relative; z-index: 5;
display: flex; flex-direction: column; gap: .9rem;
}
.lp-filter-row {
display: flex; align-items: center; flex-wrap: wrap; gap: .5rem;
}
.lp-filter-label {
font-size: .72rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .08em; color: var(--ggs-text-muted);
min-width: 60px;
}
.lp-chip {
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;
}
.lp-chip:hover { border-color: var(--ggs-fjord); color: var(--ggs-fjord); }
.lp-chip:active { transform: scale(0.96); }
.lp-chip.active { background: var(--ggs-fjord); color: var(--ggs-white); border-color: var(--ggs-fjord); }
.lp-chip-badge {
font-size: .7rem; padding: 1px 6px; border-radius: var(--ggs-radius-pill);
background: var(--ggs-bg-dark); color: var(--ggs-text-muted);
font-weight: 700;
}
.lp-chip.active .lp-chip-badge {
background: rgba(255,255,255,.22); color: var(--ggs-white);
}
/* ===== Kompetenz-Karten ===== */
.lp-wrap { max-width: 1100px; margin: 0 auto 3rem; padding: 0 1.2rem; }
.lp-results-info {
font-size: .82rem; color: var(--ggs-text-muted);
margin-bottom: 1rem;
}
.lp-kompetenz {
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-md);
padding: 1.4rem 1.6rem;
margin-bottom: 1.2rem;
scroll-margin-top: 80px;
}
.lp-kompetenz-head {
display: flex; flex-wrap: wrap; align-items: flex-start;
gap: .8rem; margin-bottom: .5rem;
}
.lp-kompetenz-title {
font-size: 1.3rem; font-weight: 900; color: var(--ggs-fjord-dark);
letter-spacing: -.02em;
}
.lp-kompetenz-cat {
font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark);
padding: 3px 10px; border-radius: var(--ggs-radius-pill);
}
.lp-kompetenz-age {
font-size: .75rem; color: var(--ggs-text-muted);
background: var(--ggs-bg-dark); padding: 3px 10px;
border-radius: var(--ggs-radius-pill);
}
.lp-kompetenz-desc {
font-size: .93rem; line-height: 1.55; color: var(--ggs-text);
margin-bottom: 1rem;
}
/* Modul-Cards innerhalb einer Kompetenz */
.lp-modules-label {
font-size: .72rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .1em; color: var(--ggs-text-muted);
margin: .4rem 0 .5rem;
}
.lp-modules {
display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1.2rem;
}
.lp-module-card {
display: inline-flex; align-items: center; gap: .55rem;
padding: .55rem .95rem .55rem .7rem;
background: var(--ggs-white); border: 1.5px solid var(--ggs-border);
border-radius: var(--ggs-radius-md);
text-decoration: none; color: var(--ggs-text);
transition: all .2s var(--ggs-ease);
min-height: 44px;
}
.lp-module-card:hover, .lp-module-card:active {
border-color: var(--ggs-fjord); background: var(--ggs-fjord-light);
transform: translateY(-1px);
}
.lp-module-icon { font-size: 1.3rem; line-height: 1; }
.lp-module-name { font-size: .92rem; font-weight: 700; color: var(--ggs-fjord-dark); }
.lp-module-strength {
font-size: .62rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
padding: 1px 6px; border-radius: var(--ggs-radius-sm);
background: var(--ggs-moss-light); color: var(--ggs-moss-dark);
}
.lp-module-strength.sekundaer { background: var(--ggs-bg-dark); color: var(--ggs-text-muted); }
.lp-module-status {
font-size: .6rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
padding: 1px 5px; border-radius: var(--ggs-radius-sm);
}
.lp-module-status.aktiv { background: var(--ggs-moss); color: var(--ggs-white); }
.lp-module-status.beta { background: var(--ggs-sand-dark); color: var(--ggs-white); }
.lp-module-status.geplant { background: var(--ggs-fjord); color: var(--ggs-white); opacity: .7; }
/* Anker — wie modul-detail */
.lp-anchor-group { margin-top: .8rem; }
.lp-anchor-group-head {
display: flex; align-items: baseline; gap: .6rem;
margin: .4rem 0 .5rem; flex-wrap: wrap;
}
.lp-anchor-group-title {
font-size: .72rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .1em; color: var(--ggs-fjord-dark);
}
.lp-anchor-group-sub {
font-size: .72rem; color: var(--ggs-text-muted); font-weight: 500;
}
.lp-anchors { display: grid; gap: .55rem; }
.lp-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);
}
.lp-anchor-flag { font-size: 1.2rem; line-height: 1.3; text-align: center; }
.lp-anchor-meta { font-size: .75rem; color: var(--ggs-text-muted); margin-bottom: .15rem; }
.lp-anchor-title { font-weight: 700; color: var(--ggs-fjord-dark); margin-bottom: .2rem; }
.lp-anchor-quote { font-size: .88rem; color: var(--ggs-text); font-style: italic; line-height: 1.45; }
.lp-anchor-ref { font-size: .72rem; color: var(--ggs-text-muted); margin-top: .3rem; }
.lp-anchor-link {
color: var(--ggs-fjord); text-decoration: none; font-weight: 600;
border-bottom: 1px dotted var(--ggs-fjord); padding: 2px 0;
}
.lp-anchor-link:hover { color: var(--ggs-fjord-dark); border-bottom-style: solid; }
.lp-anchor--fach { border-left-color: var(--ggs-fjord); }
.lp-anchor--uebergreifendes_thema { border-left-color: var(--ggs-moss); background: var(--ggs-moss-light); }
.lp-anchor--anderes_fach { border-left-color: var(--ggs-sand-dark); background: var(--ggs-bg-dark); }
.lp-anchor--uebergreifendes_thema .lp-anchor-flag,
.lp-anchor--anderes_fach .lp-anchor-flag { opacity: .65; }
.lp-anchor.hidden { display: none; }
.lp-kompetenz-empty {
padding: 1rem 0; color: var(--ggs-text-muted); font-style: italic;
font-size: .9rem;
}
.lp-hint {
font-size: .82rem; color: var(--ggs-text-muted); font-style: italic;
margin-top: 1.5rem; max-width: 780px;
}
.lp-toc {
background: var(--ggs-white); border: 1px solid var(--ggs-border);
border-radius: var(--ggs-radius-md);
padding: 1rem 1.2rem;
margin-bottom: 1.2rem;
}
.lp-toc-title {
font-size: .72rem; font-weight: 800; text-transform: uppercase;
letter-spacing: .1em; color: var(--ggs-text-muted);
margin-bottom: .5rem;
}
.lp-toc-list { display: flex; flex-wrap: wrap; gap: .4rem; }
.lp-toc-item {
display: inline-flex; align-items: center; gap: .3rem;
padding: .35rem .75rem; border-radius: var(--ggs-radius-pill);
background: var(--ggs-fjord-light); color: var(--ggs-fjord-dark);
font-size: .82rem; font-weight: 600; text-decoration: none;
transition: background .2s var(--ggs-ease);
min-height: 32px;
}
.lp-toc-item:hover { background: var(--ggs-fjord); color: var(--ggs-white); }
.lp-toc-count { font-size: .7rem; opacity: .7; }
/* Footer */
.lp-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;
}
.lp-footer img { height: 36px; opacity: .5; margin-bottom: .5rem; }
.lp-footer a { color: var(--ggs-fjord); text-decoration: none; padding: .3rem .2rem; }
@media (max-width: 900px) {
.lp-filter-row { flex-direction: column; align-items: flex-start; gap: .3rem; }
.lp-filter-label { min-width: 0; }
}
</style>
</head>
<body>
<?php
/* Standard-Hauptnav + Kontext-Sub-Nav (N.5.1 Vorschlag — umgesetzt 2026-05-28) */
$activeMain = 'lehrplan';
$activeSub = 'lehrplan';
$showCountryPicker = true;
include __DIR__ . '/_partials/public_topnav.php';
include __DIR__ . '/_partials/erkundungs_subnav.php';
?>
<?php if ($moduleFocus): ?>
<!-- Modul-Fokus-Banner: der Link kommt aus einer Simulation oder Modul-Detailseite -->
<div class="lp-focus-banner">
<span class="lp-focus-icon"><?= esc($moduleFocus['icon']) ?></span>
<div class="lp-focus-text">
<strong>Lehrplan-Bezug für <?= esc($moduleFocus['title']) ?></strong>
<span class="lp-focus-sub">Gefiltert auf die Kompetenzbereiche dieser Simulation.</span>
</div>
<?php if (!empty($moduleFocus['page_url'])): ?>
<a href="<?= $bp ?>/<?= esc($moduleFocus['page_url']) ?>" class="lp-focus-action">← Zurück zur Simulation</a>
<?php endif; ?>
<a href="<?= $bp ?>/pages/lehrplan.php" class="lp-focus-action">Alle Module anzeigen</a>
</div>
<?php endif; ?>
<!-- HERO -->
<section class="lp-hero">
<h1><?= $moduleFocus ? 'Lehrplan-Bezug: ' . esc($moduleFocus['title']) : 'Lehrplan-Übersicht' ?></h1>
<p>
<?php if ($moduleFocus): ?>
Diese Ansicht zeigt alle Kompetenzbereiche, die die Simulation
<strong><?= esc($moduleFocus['title']) ?></strong> abdeckt — fachlich,
fächerübergreifend und mit Anknüpfungspunkten in weiteren Fächern.
<?php else: ?>
Alle GeoGraSim-Simulationen sind auf didaktische Kompetenzbereiche
abgebildet. Für jeden Bereich zeigen wir, wo er in den Lehrplänen
für Österreich, Deutschland, Schweiz und Liechtenstein verankert ist —
fachlich, fächerübergreifend und mit Anknüpfungspunkten in weiteren Fächern.
<?php endif; ?>
</p>
<div class="lp-hero-stats">
<div class="lp-hero-stat"><span class="lp-hero-stat-num"><?= count($kompetenzen) ?></span><span class="lp-hero-stat-lbl"><?= $moduleFocus ? 'Kompetenzen für dieses Modul' : 'Kompetenzbereiche' ?></span></div>
<div class="lp-hero-stat"><span class="lp-hero-stat-num"><?= $totalAnchors ?></span><span class="lp-hero-stat-lbl">Lehrplan-Anker gesamt</span></div>
<div class="lp-hero-stat"><span class="lp-hero-stat-num">4</span><span class="lp-hero-stat-lbl">Länder</span></div>
</div>
</section>
<!-- N.5.2 — Transparenz-Zeile (statt redundanter Land-Chip-Reihe; Land kommt vom Picker oben) -->
<div class="lp-context-line">
<strong>Anzeige:</strong>
<?php if ($qCountry === 'ALL'): ?>
🌐 alle Länder · <strong><?= $visibleFach ?></strong> Fach-Anker
<?php else:
$cm = $countryMeta[$qCountry];
?>
<?= $cm['flag'] ?> <strong><?= esc($cm['label']) ?></strong> · <strong><?= $visibleFach ?></strong> Lehrplan-Anker
<?php endif; ?>
+ <strong><?= $visibleUniversal ?></strong> fächerübergreifende Anker
(universell, aus dem österreichischen Lehrplan abgeleitet — didaktisch ländervergreifend nutzbar).
</div>
<!-- FILTER (Land entfernt — wird über den Country-Picker in der Sub-Nav gesetzt) -->
<div class="lp-filters" id="lp-filters">
<div class="lp-filter-row">
<span class="lp-filter-label">Thema</span>
<button type="button" class="lp-chip<?= !$qTheme ? ' active' : '' ?>" data-filter="theme" data-value="">
Alle <span class="lp-chip-badge"><?= count($kompetenzen) ?></span>
</button>
<?php foreach ($kompetenzen as $k): ?>
<?php $slug = esc($k['key_slug']); ?>
<button type="button" class="lp-chip<?= $qTheme === $k['key_slug'] ? ' active' : '' ?>"
data-filter="theme" data-value="<?= $slug ?>">
<?= esc($k['title']) ?>
</button>
<?php endforeach; ?>
</div>
<div class="lp-filter-row">
<span class="lp-filter-label">Typ</span>
<button type="button" class="lp-chip active" data-filter="type" data-value="">
Alle <span class="lp-chip-badge"><?= $totalAnchors ?></span>
</button>
<button type="button" class="lp-chip" data-filter="type" data-value="fach">
Fachbezug <span class="lp-chip-badge"><?= $countsByType['fach'] ?? 0 ?></span>
</button>
<button type="button" class="lp-chip" data-filter="type" data-value="uebergreifendes_thema">
Fächerübergreifend <span class="lp-chip-badge"><?= $countsByType['uebergreifendes_thema'] ?? 0 ?></span>
</button>
<button type="button" class="lp-chip" data-filter="type" data-value="anderes_fach">
Andere Fächer <span class="lp-chip-badge"><?= $countsByType['anderes_fach'] ?? 0 ?></span>
</button>
</div>
</div>
<div class="lp-wrap">
<!-- TOC — Sprung zu Kompetenzen -->
<nav class="lp-toc" aria-label="Sprung zu Kompetenz">
<div class="lp-toc-title">Kompetenzbereiche auf dieser Seite</div>
<div class="lp-toc-list">
<?php foreach ($kompetenzen as $k):
$total = count($k['anchors_all']); ?>
<a class="lp-toc-item" href="#k-<?= esc($k['key_slug']) ?>">
<?= esc($k['title']) ?>
<span class="lp-toc-count"><?= $total ?></span>
</a>
<?php endforeach; ?>
</div>
</nav>
<div class="lp-results-info" id="lp-results-info"></div>
<?php foreach ($kompetenzen as $k): ?>
<article class="lp-kompetenz" id="k-<?= esc($k['key_slug']) ?>"
data-theme="<?= esc($k['key_slug']) ?>">
<header class="lp-kompetenz-head">
<div class="lp-kompetenz-title"><?= esc($k['title']) ?></div>
<?php if (!empty($k['category']) && isset($categoryMeta[$k['category']])): ?>
<span class="lp-kompetenz-cat"><?= esc($categoryMeta[$k['category']]['label']) ?></span>
<?php endif; ?>
<?php if (!empty($k['age_min']) && !empty($k['age_max'])): ?>
<span class="lp-kompetenz-age">👧 <?= (int)$k['age_min'] ?><?= (int)$k['age_max'] ?> Jahre</span>
<?php endif; ?>
</header>
<?php if (!empty($k['description'])): ?>
<p class="lp-kompetenz-desc"><?= esc($k['description']) ?></p>
<?php endif; ?>
<!-- Module, die dieser Kompetenz zugeordnet sind -->
<?php if (!empty($k['modules'])): ?>
<div class="lp-modules-label">Simulationen zu diesem Bereich</div>
<div class="lp-modules">
<?php foreach ($k['modules'] as $m): ?>
<a class="lp-module-card" href="<?= $bp ?>/<?= esc($m['page_url']) ?>">
<span class="lp-module-icon"><?= esc($m['icon']) ?></span>
<span class="lp-module-name"><?= esc($m['title']) ?></span>
<span class="lp-module-strength <?= esc($m['strength']) ?>">
<?= $m['strength'] === 'primaer' ? 'Primär' : 'Sekundär' ?>
</span>
<span class="lp-module-status <?= esc($m['status']) ?>"><?= esc($m['status']) ?></span>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- Anker-Gruppen -->
<?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="lp-anchor-group" data-group-type="<?= esc($key) ?>">
<div class="lp-anchor-group-head">
<span class="lp-anchor-group-title"><?= esc($heading) ?></span>
<span class="lp-anchor-group-sub"><?= esc($sub) ?></span>
</div>
<div class="lp-anchors">
<?php foreach ($list as $a): ?>
<?php
$cm = $countryMeta[$a['country']] ?? ['flag' => '🏳️', 'label' => $a['country']];
/* N.5.3 (a) — Übergreifende + Anderes-Fach-Anker sind land-agnostisch.
🌐-Icon + „Universell"-Label statt Country-Flagge zeigt das visuell. */
$isUniversal = ($a['anchor_type'] !== 'fach');
$iconHtml = $isUniversal ? '🌐' : $cm['flag'];
$iconTitle = $isUniversal ? 'Universell — aus ' . $cm['label'] . '-Lehrplan abgeleitet' : $cm['label'];
?>
<div class="lp-anchor lp-anchor--<?= esc($a['anchor_type']) ?>"
data-country="<?= esc($a['country']) ?>"
data-anchor-type="<?= esc($a['anchor_type']) ?>">
<div class="lp-anchor-flag" title="<?= esc($iconTitle) ?>"><?= $iconHtml ?></div>
<div>
<div class="lp-anchor-meta">
<?php if ($isUniversal): ?>
<strong>Universell</strong> <span style="opacity:.7">(aus <?= esc($a['country']) ?>-Lehrplan)</span>
<?php else: ?>
<strong><?= esc($a['country']) ?></strong>
<?php endif; ?>
<?= $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="lp-anchor-title"><?= esc($a['title']) ?></div>
<?php if (!empty($a['quote'])): ?>
<div class="lp-anchor-quote">„<?= esc($a['quote']) ?>"</div>
<?php endif; ?>
<?php if (!empty($a['reference'])): ?>
<div class="lp-anchor-ref">
Quelle:
<?php if (!empty($a['reference_url'])): ?>
<a href="<?= esc($a['reference_url']) ?>" target="_blank"
rel="noopener noreferrer" class="lp-anchor-link"><?= esc($a['reference']) ?> ↗</a>
<?php else: ?>
<?= esc($a['reference']) ?>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php if (empty($k['anchors_all'])): ?>
<div class="lp-kompetenz-empty">Noch keine Lehrplan-Anker hinterlegt.</div>
<?php endif; ?>
</article>
<?php endforeach; ?>
<p class="lp-hint">
Anker sind Beispiele — bitte mit dem konkreten Jahresplan abgleichen.
<strong>🌐-Anker</strong> sind fächerübergreifend / anderes Fach: aus dem
österreichischen Lehrplan abgeleitet, didaktisch ländervergreifend nutzbar.
</p>
</div>
<footer class="lp-footer">
<img src="<?= $bp ?>/assets/img/bildLogo.png" alt="">
<div>
Lehrplan geograsim.at ·
<a href="<?= $bp ?>/pages/simulationen.php">Simulationen</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__ . '/_partials/country_footer.php'; ?>
</footer>
<script>
// Filter-Logik: Land / Thema / Typ
(function () {
const filterBar = document.getElementById('lp-filters');
const resultsInfo = document.getElementById('lp-results-info');
const state = {
country: <?= json_encode($qCountry) ?>,
theme: <?= json_encode($qTheme) ?>,
type: '',
};
// Chips aktiv-Zustand beim Laden setzen (falls URL-Filter vorgewählt)
function activate(row, value) {
filterBar.querySelectorAll(`.lp-chip[data-filter="${row}"]`).forEach(c => {
c.classList.toggle('active', c.dataset.value === value);
});
}
filterBar.addEventListener('click', (e) => {
const btn = e.target.closest('.lp-chip');
if (!btn) return;
const filter = btn.dataset.filter;
const value = btn.dataset.value;
state[filter] = value;
activate(filter, value);
apply();
// URL aktualisieren, ohne Reload (damit Deep-Links funktionieren)
const params = new URLSearchParams();
if (state.country && state.country !== 'ALL') params.set('country', state.country);
if (state.theme) params.set('theme', state.theme);
const q = params.toString();
history.replaceState(null, '', q ? '?' + q : location.pathname);
});
function apply() {
let shownKomp = 0;
let shownAnchors = 0;
document.querySelectorAll('.lp-kompetenz').forEach(k => {
// Thema-Filter
if (state.theme && k.dataset.theme !== state.theme) {
k.style.display = 'none';
return;
}
k.style.display = '';
shownKomp++;
// Anker-Filter: Land + Typ
k.querySelectorAll('.lp-anchor').forEach(a => {
let hide = false;
// Land-Filter (Default = aktuelles Land aus Country::current(), in der Regel AT):
// - anchor_type='fach' wird strikt nach Land gefiltert
// - uebergreifende Themen + andere Faecher bleiben sichtbar
// (sie sind primaer aus dem AT-Lehrplan abgeleitet, didaktisch
// land-agnostisch nutzbar)
if (state.country && state.country !== 'ALL') {
const anchorCountry = a.dataset.country;
const type = a.dataset.anchorType;
if (type === 'fach') {
if (anchorCountry && anchorCountry !== state.country) hide = true;
}
// anchor_type !== 'fach': land-agnostisch sichtbar lassen
}
if (state.type && a.dataset.anchorType !== state.type) hide = true;
a.classList.toggle('hidden', hide);
if (!hide) shownAnchors++;
});
// Wenn in einer Kompetenz keine Anker sichtbar sind, Kompetenz ausblenden
const visibleInKomp = k.querySelectorAll('.lp-anchor:not(.hidden)').length;
if (visibleInKomp === 0 && (state.country !== 'ALL' || state.type)) {
k.style.display = 'none';
shownKomp--;
}
// Auch Anker-Gruppen ausblenden, wenn sie leer sind
k.querySelectorAll('.lp-anchor-group').forEach(g => {
const v = g.querySelectorAll('.lp-anchor:not(.hidden)').length;
g.style.display = v === 0 ? 'none' : '';
});
});
// Ergebnis-Info aktualisieren
const parts = [`${shownAnchors} Anker sichtbar`];
if (shownKomp !== <?= count($kompetenzen) ?>) parts.push(`${shownKomp} Kompetenzbereich(e)`);
resultsInfo.textContent = parts.join(' · ');
}
// Initial
apply();
})();
</script>
</body>
</html>