feat(v3): Bürger:innen-Modus visuell ausgebaut — Wort-Etikett, 5-Werte-Bars, Glossar, Collapsibles

v2 unangetastet — v3 überschreibt nur Sub-Blocks. Neue v2-Blocks
für Override-Punkte: antrag_id_section, score_hero_section,
matrix_section, verbesserungen_section, aktions_section,
comments_section.

v3-Anpassungen:
1. Drucksache-ID: "Antrag im Landtag NRW · Drucksache 18/18246" —
   "Drucksache" als Glossar-Hinweis klickbar.
2. Score-Hero: großes Wort-Etikett ("Stark gemeinwohlfördernd" /
   "Gemischt" / "Widerspricht dem Gemeinwohl") aus verdict_title oder
   abgeleitet. Score-Zahl als kleiner Untertitel mit Glossar-Link.
   Akzentfarbe links (grün/blau/rot je nach Score).
3. Matrix: 5 Werte als Diverging-Bars (-5..+5) sofort sichtbar;
   volle 5×5-Matrix in <details>. Aggregation = Spalten-Mittel über
   die 5 Berührungsgruppen.
4. Verbesserungsvorschläge: <details> default zu, Hint-Text mit Anzahl.
5. Aktions-Links: JSON-Export raus — nur PDF + Permalink.
6. Kommentare: <details> default zu (für Erst-Leser:innen unwichtig).

Glossar-System: 6 Begriffe (Drucksache, Fraktion, GWÖ-Score,
GWÖ-Matrix, Heuchelei-Marker, Opportunismus-Marker) mit Klick/Focus-
Tooltip via Modal. Trigger: Element mit class="v3-glossar"
data-glossar="<key>".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dotty Dotter 2026-05-07 10:15:50 +02:00
parent acda3cdb3a
commit 895187ac36
3 changed files with 541 additions and 26 deletions

View File

@ -7,12 +7,10 @@
*
* Konvention:
* - Klassen mit Präfix `v3-` sind v3-spezifisch.
* - v2-Klassen werden nur überschrieben, wenn das Citizen-Bedürfnis es
* verlangt (Wort-Etiketten statt Symbol, weniger Tiefe als Default).
* - Inline-Styles in v3-Templates sind verboten (Lint-Hook folgt in #184).
* - Inline-Styles in v3-Templates möglichst vermeiden (Lint-Hook folgt in #184).
*/
/* ── v3-Beta-Indikator in der Topbar ────────────────────────────────── */
/* ── Topbar: Beta-Pill + Modus-Toggle ──────────────────────────────── */
.v3-beta-badge {
font-family: var(--font-mono);
font-size: 9px;
@ -24,8 +22,6 @@
color: #fff;
font-weight: 700;
}
/* ── Modus-Toggle: zwischen Profi (/antrag/...) und Bürgerin (/v3/...) ── */
.v3-modus-toggle {
display: inline-flex;
align-items: center;
@ -38,9 +34,261 @@
opacity: 0.85;
border-bottom: 1px solid rgba(0, 157, 165, 0.35);
padding-bottom: 1px;
margin-left: auto;
}
.v3-modus-toggle:hover { opacity: 1; color: var(--ecg-blue); }
/* ── 1. Drucksache-ID: ruhiger Untertitel ──────────────────────────── */
.v3-antrag-id {
/* erbt v2-antrag-id; nichts zu ändern auf der Ebene */
}
.v3-modus-toggle:hover {
opacity: 1;
/* ── 2. Score-Hero: Wort-Etikett vor Zahl ──────────────────────────── */
.v3-score-hero {
background: var(--surface);
border: 1px solid var(--hairline);
border-left: 6px solid var(--ecg-blue);
border-radius: 6px;
padding: 18px 20px;
margin: 8px 0 18px;
}
.v3-score-hero.good { border-left-color: var(--ecg-green); }
.v3-score-hero.mid { border-left-color: var(--ecg-blue); }
.v3-score-hero.low { border-left-color: var(--redline-contra, #cf222e); }
.v3-score-label {
font-family: var(--font-sans);
font-size: 22px;
font-weight: 900;
line-height: 1.1;
color: var(--ecg-dark);
margin-bottom: 4px;
}
.v3-score-hero.good .v3-score-label { color: #1a7f37; }
.v3-score-hero.low .v3-score-label { color: #a40e26; }
.v3-score-body {
font-size: 14px;
line-height: 1.5;
color: var(--ecg-dark);
margin: 6px 0 10px;
}
.v3-score-meta {
font-family: var(--font-mono);
font-size: 11px;
color: var(--ecg-dark);
opacity: 0.75;
border-top: 1px dashed var(--hairline);
padding-top: 8px;
}
.v3-score-meta strong { font-weight: 700; }
/* ── 3. 5-Werte-Bars (Matrix-Vereinfachung) ────────────────────────── */
.v3-werte-list {
display: flex;
flex-direction: column;
gap: 6px;
margin: 10px 0 16px;
}
.v3-wert-row {
display: grid;
grid-template-columns: minmax(140px, 1fr) 2.5fr auto;
align-items: center;
gap: 10px;
font-size: 13px;
}
.v3-wert-label {
color: var(--ecg-dark);
font-weight: 600;
line-height: 1.3;
}
.v3-wert-bar {
position: relative;
height: 10px;
}
.v3-wert-track {
position: absolute;
inset: 0;
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: 5px;
overflow: hidden;
}
.v3-wert-mid {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 1px;
background: var(--hairline);
}
.v3-wert-fill {
position: absolute;
top: 0;
bottom: 0;
border-radius: 3px;
min-width: 2px;
}
.v3-wert-fill.pos { background: var(--ecg-green); }
.v3-wert-fill.neu { background: var(--ecg-dark); opacity: 0.3; }
.v3-wert-fill.neg { background: var(--redline-contra, #cf222e); }
.v3-wert-num {
font-family: var(--font-mono);
font-size: 12px;
font-weight: 700;
color: var(--ecg-dark);
min-width: 36px;
text-align: right;
}
.v3-matrix-details {
margin-top: 10px;
padding: 8px 12px;
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: 5px;
}
.v3-matrix-details > summary {
cursor: pointer;
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: 0.03em;
color: var(--ecg-dark);
user-select: none;
list-style: none;
}
.v3-matrix-details > summary::-webkit-details-marker { display: none; }
.v3-matrix-details > summary::before {
content: "▸ ";
display: inline-block;
margin-right: 4px;
transition: transform 0.15s ease;
}
.v3-matrix-details[open] > summary::before {
transform: rotate(90deg);
}
/* ── 4. Glossar-Tooltips ───────────────────────────────────────────── */
.v3-glossar {
display: inline;
border-bottom: 1px dotted var(--ecg-blue);
cursor: help;
color: var(--ecg-blue);
}
.v3-glossar:hover,
.v3-glossar:focus-visible {
outline: none;
background: rgba(0, 157, 165, 0.12);
border-bottom-style: solid;
}
.v3-glossar-modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.45);
z-index: 9100;
align-items: center;
justify-content: center;
}
.v3-glossar-card {
background: var(--ecg-card-bg, #fff);
border: 1px solid var(--ecg-border, #ddd);
border-radius: 8px;
padding: 22px 26px;
min-width: 280px;
max-width: 480px;
font-family: var(--font-sans);
color: var(--ecg-dark);
box-shadow: 0 8px 32px rgba(0,0,0,0.18);
}
.v3-glossar-head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 10px;
}
.v3-glossar-head strong {
font-family: var(--font-display, inherit);
font-size: 16px;
font-weight: 900;
color: var(--ecg-teal, #009da5);
letter-spacing: 0.03em;
}
.v3-glossar-close {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
color: var(--ecg-dark);
opacity: 0.55;
padding: 0;
line-height: 1;
}
.v3-glossar-card p {
margin: 0;
font-size: 14px;
line-height: 1.55;
}
/* ── 5. Collapsible-Sections (Verbesserungen, Kommentare default zu) ─ */
.v3-collapsible {
margin-top: 24px;
padding: 8px 0;
border-top: 1px solid var(--hairline);
}
.v3-collapsible > summary {
cursor: pointer;
list-style: none;
user-select: none;
display: flex;
align-items: baseline;
gap: 12px;
padding: 4px 0;
}
.v3-collapsible > summary::-webkit-details-marker { display: none; }
.v3-collapsible > summary > h3 {
margin: 0;
display: inline-flex;
align-items: baseline;
gap: 8px;
}
.v3-collapsible > summary > h3::before {
content: "▸";
display: inline-block;
font-family: var(--font-mono);
font-size: 12px;
color: var(--ecg-dark);
opacity: 0.55;
transition: transform 0.15s ease;
}
.v3-collapsible[open] > summary > h3::before {
transform: rotate(90deg);
}
.v3-collapsible-hint {
font-family: var(--font-mono);
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--ecg-dark);
opacity: 0.5;
}
.v3-comments {
margin-top: 40px;
padding-top: 20px;
}
/* ── 6. Aktions-Links ──────────────────────────────────────────────── */
.v3-aktions {
margin-top: 24px;
font-family: var(--font-mono);
font-size: 11px;
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.v3-aktions a {
color: var(--ecg-blue);
border-bottom: 1px solid rgba(0, 157, 165, 0.35);
}

View File

@ -126,12 +126,14 @@
{# ── Linke Spalte: Redaktionelle Analyse ── #}
<div class="left">
{% block antrag_id_section %}
<div class="v2-antrag-id">
{{ antrag.bundesland | default("") }}
{% if antrag.drucksache %} · Drs. {{ antrag.drucksache }}{% endif %}
{% if antrag.typ %} · {{ antrag.typ }}{% endif %}
{% if antrag.datum %} · eingebracht {{ antrag.datum }}{% endif %}
</div>
{% endblock %}
<h1 class="v2-big-title">{{ antrag.title | default("Antrag") }}</h1>
@ -183,6 +185,7 @@
</div>
{% endif %}
{% block verbesserungen_section %}
{# Verbesserungsvorschläge: alle verbesserungen rendern wenn vorhanden #}
{% if antrag.verbesserungen %}
<h3 class="v2-h3" style="margin-top:24px;">Verbesserungsvorschläge</h3>
@ -211,6 +214,7 @@
{% from "v2/components/redline.html" import redline %}
{{ redline(segments=antrag.redline.segments) }}
{% endif %}
{% endblock %}
</div>{# .left #}
@ -230,7 +234,9 @@
</button>
</div>
{% block score_hero_section %}
{{ score_hero(antrag.score | default(0), antrag.verdict_title | default(""), antrag.verdict_body | default("")) }}
{% endblock %}
{# ── Namentliche Abstimmung (#106 Phase 1) ── #}
{% if antrag.abstimmungsverhalten %}
@ -377,10 +383,12 @@
</div>
{% endif %}{# plenum_votes #}
{% block matrix_section %}
{% if antrag.matrix %}
<h3 class="v2-h3">Matrix 2.0 · 25 Felder</h3>
{{ matrix_mini(antrag.matrix) }}
{% endif %}
{% endblock %}
{# Programm-Treue im BELEGE-Layout: pro Partei zwei <details>-Blöcke
(Wahlprogramm + Parteiprogramm). Summary zeigt Bewertung,
@ -441,6 +449,7 @@
</div>
</div>
{% block aktions_section %}
{# Aktions-Links #}
<div style="margin-top:24px;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);opacity:0.85;display:flex;gap:16px;flex-wrap:wrap;">
<a href="/api/assessment/pdf?drucksache={{ antrag.drucksache | urlencode }}"
@ -456,6 +465,7 @@
Permalink
</a>
</div>
{% endblock %}
{# ── Voting-Block ─────────────────────────────────────────────── #}
<div style="margin-top:24px;">
@ -526,6 +536,7 @@
</div>{# .v2-detail #}
{% block comments_section %}
{# ── Kommentare ───────────────────────────────────────────────────────── #}
<div style="margin-top:40px;border-top:1px solid var(--hairline);padding-top:28px;">
<h3 class="v2-h3" style="margin-bottom:16px;">Kommentare</h3>
@ -562,6 +573,7 @@
</button>
</div>
</div>
{% endblock %}
{# ── Matrix-Feld-Info-Modal ───────────────────────────────────────────── #}
<div id="v2-matrix-field-modal"

View File

@ -1,47 +1,302 @@
{# ─────────────────────────────────────────────────────────────────────
v3/screens/antrag_detail.html — Bürgerinnen-Modus, Schritt 0
v3/screens/antrag_detail.html — Bürger:innen-Modus
Initial extendet diese Datei das v2-Antrag-Detail unverändert und
fügt nur den v3-Beta-Indikator + Modus-Toggle in die Topbar ein.
Folgende Iterationen ersetzen Profi-Blöcke durch Bürgerinnen-
Varianten (siehe #185):
- Score-Hero: Wort-Etikett statt 010-Zahl
- Matrix 5×5 → 5 Werte (Berührungsgruppen kollabiert)
- Heuchelei/Opportunismus-Marker mit Klartext-Tooltip
- Verbesserungsvorschläge default kollabiert
- Glossar-Tooltips auf Schlüsselbegriffen
Override-Strategie: extendet v2-Screen, ersetzt nur die Sub-Blocks,
die in v3 vereinfacht werden. Block-Liste:
- antrag_id_section — entschärfte Drucksache-Sprache mit Glossar
- score_hero_section — Wort-Etikett groß, Zahl klein darunter
- matrix_section — 5 Werte default + <details> für 5×5
- verbesserungen_section — default kollabiert
- aktions_section — JSON-Export raus, nur PDF + Permalink
- comments_section — default kollabiert
───────────────────────────────────────────────────────────────────── #}
{% extends "v2/screens/antrag_detail.html" %}
{# v3-Indikator + Toggle: erscheint im topbar-Slot, der in v2/base.html
aktuell nicht als Block exponiert ist. Wir nutzen daher head_extra
als Eingangstor und injizieren via JS einen kleinen Topbar-Pill.
Das vermeidet ein Refactor von v2/base.html, der v2 beruehren wuerde. #}
{% block head_extra %}
{{ super() }}
<link rel="stylesheet" href="/static/v3/v3.css?v={{ app_version|default('1') }}">
{% endblock %}
{# ─── 1. Drucksache-ID: weniger Behörden-Sprache, Glossar-Hinweise ─── #}
{% block antrag_id_section %}
<div class="v2-antrag-id v3-antrag-id">
Antrag im
{% if antrag.bundesland == "BU" %}Bundestag
{% elif antrag.bundesland %}Landtag {{ antrag.bundesland }}
{% else %}Parlament{% endif %}
{% if antrag.drucksache %}
· <span class="v3-glossar" data-glossar="drucksache" tabindex="0" role="button"
aria-label="Glossar: Drucksache">Drucksache</span>
{{ antrag.drucksache }}
{% endif %}
{% if antrag.datum %} · eingebracht {{ antrag.datum }}{% endif %}
</div>
{% endblock %}
{# ─── 2. Score-Hero: Wort-Etikett groß, Zahl klein ──────────────────── #}
{% block score_hero_section %}
{% set s = (antrag.score | default(0)) | float %}
{% if s >= 7 %}
{% set v3_label = antrag.verdict_title or "Stark gemeinwohlfördernd" %}
{% set v3_class = "good" %}
{% elif s >= 4 %}
{% set v3_label = antrag.verdict_title or "Gemischt" %}
{% set v3_class = "mid" %}
{% else %}
{% set v3_label = antrag.verdict_title or "Widerspricht dem Gemeinwohl" %}
{% set v3_class = "low" %}
{% endif %}
<div class="v3-score-hero {{ v3_class }}"
role="region" aria-label="Bewertung: {{ v3_label }} ({{ '%.1f'|format(s) }} von 10)">
<div class="v3-score-label">{{ v3_label }}</div>
{% if antrag.verdict_body %}
<div class="v3-score-body">{{ antrag.verdict_body }}</div>
{% endif %}
<div class="v3-score-meta">
<span class="v3-glossar" data-glossar="gwoe-score" tabindex="0" role="button"
aria-label="Glossar: GWÖ-Score">Gemeinwohl-Score</span>:
<strong>{{ "%.1f"|format(s) }} von 10</strong>
</div>
</div>
{% endblock %}
{# ─── 3. Matrix: 5 Werte default, volle 5×5 in <details> ─────────────── #}
{% block matrix_section %}
{% if antrag.matrix %}
<h3 class="v2-h3">Beitrag zu den 5 Gemeinwohl-Werten</h3>
{# Pro Wert (Spalte 1..5) Durchschnitt aus den 5 Berührungsgruppen-Zellen.
Skala bleibt -5..+5 wie in der DB. #}
{% set v3_werte = [
("1", "Menschenwürde"),
("2", "Solidarität"),
("3", "Ökologische Nachhaltigkeit"),
("4", "Soziale Gerechtigkeit"),
("5", "Transparenz & Demokratie"),
] %}
<div class="v3-werte-list">
{% for col, label in v3_werte %}
{% set ns = namespace(sum=0, cnt=0) %}
{% for row in ["A","B","C","D","E"] %}
{% set cell = antrag.matrix[row ~ col] | default(none) %}
{% if cell %}
{% set ns.sum = ns.sum + (cell.rating | int) %}
{% set ns.cnt = ns.cnt + 1 %}
{% endif %}
{% endfor %}
{% set avg = (ns.sum / ns.cnt) if ns.cnt else 0 %}
{% set pct = ((avg + 5) / 10 * 100) %}
<div class="v3-wert-row">
<div class="v3-wert-label">{{ label }}</div>
<div class="v3-wert-bar" aria-hidden="true">
<div class="v3-wert-track">
<div class="v3-wert-mid"></div>
<div class="v3-wert-fill {% if avg >= 1 %}pos{% elif avg <= -1 %}neg{% else %}neu{% endif %}"
style="left: {{ 'calc(50% - ' ~ ((-avg / 5 * 50)) ~ '%)' if avg < 0 else '50%' }};
width: {{ ((avg if avg > 0 else -avg) / 5 * 50) }}%;"></div>
</div>
</div>
<div class="v3-wert-num"
title="Durchschnitt der 5 Berührungsgruppen — Skala 5 bis +5">
{% if avg > 0 %}+{% endif %}{{ "%.1f"|format(avg) }}
</div>
</div>
{% endfor %}
</div>
<details class="v3-matrix-details">
<summary>
Volle <span class="v3-glossar" data-glossar="gwoe-matrix" tabindex="0" role="button"
aria-label="Glossar: GWÖ-Matrix">GWÖ-Matrix 2.0</span>
· 25 Felder (5 Werte × 5 Berührungsgruppen)
</summary>
<div style="margin-top:8px;">
{% from "v2/components/matrix_mini.html" import matrix_mini %}
{{ matrix_mini(antrag.matrix) }}
</div>
</details>
{% endif %}
{% endblock %}
{# ─── 4. Verbesserungsvorschläge: default kollabiert ──────────────────── #}
{% block verbesserungen_section %}
{% if antrag.verbesserungen %}
<details class="v3-collapsible">
<summary>
<h3 class="v2-h3">Verbesserungsvorschläge</h3>
<span class="v3-collapsible-hint">{{ antrag.verbesserungen | length }} Vorschlag{{ "" if antrag.verbesserungen | length == 1 else "e" }} · klicken zum Aufklappen</span>
</summary>
<div style="margin-top:12px;">
{% for v in antrag.verbesserungen %}
<div style="margin-bottom:16px;">
{% if antrag.verbesserungen | length > 1 %}
<div style="font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);opacity:0.65;margin-bottom:4px;">
Vorschlag {{ loop.index }} von {{ antrag.verbesserungen | length }}
</div>
{% endif %}
{% from "v2/components/redline.html" import redline %}
{% if v.segments %}
{{ redline(original=v.original | default(""), segments=v.segments) }}
{% else %}
{{ redline(original=v.original | default(""), vorschlag=v.vorschlag | default("")) }}
{% endif %}
{% if v.begruendung %}
<p style="font-size:12px;color:var(--ecg-dark);opacity:0.75;margin:4px 0 0;font-family:var(--font-mono);">
{{ v.begruendung }}
</p>
{% endif %}
</div>
{% endfor %}
</div>
</details>
{% endif %}
{% endblock %}
{# ─── 5. Aktions-Links: nur PDF + Permalink ──────────────────────────── #}
{% block aktions_section %}
<div class="v3-aktions">
<a href="/api/assessment/pdf?drucksache={{ antrag.drucksache | urlencode }}">
PDF-Bericht
</a>
<a href="/antrag/{{ antrag.drucksache }}">
Permalink
</a>
</div>
{% endblock %}
{# ─── 6. Kommentare: default kollabiert ──────────────────────────────── #}
{% block comments_section %}
<details class="v3-collapsible v3-comments">
<summary>
<h3 class="v2-h3">Kommentare</h3>
<span class="v3-collapsible-hint">klicken zum Aufklappen · Anmeldung erforderlich</span>
</summary>
<div style="margin-top:16px;">
<div id="v2-comments-list" style="margin-bottom:20px;">
<span style="font-family:var(--font-mono);font-size:12px;color:var(--ecg-dark);opacity:0.5;">Lade…</span>
</div>
<div id="v2-comment-form" style="display:none;">
<div style="font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:0.07em;color:var(--ecg-dark);opacity:0.6;margin-bottom:8px;">Kommentar hinzufügen</div>
<textarea id="v2-comment-input"
rows="3"
placeholder="Kommentar…"
style="width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--hairline);border-radius:4px;font-family:var(--font-sans);font-size:13px;background:var(--surface);color:var(--ecg-dark);resize:vertical;margin-bottom:8px;outline:none;"></textarea>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<select id="v2-comment-visibility"
style="padding:5px 8px;border:1px solid var(--hairline);border-radius:4px;font-family:var(--font-mono);font-size:11px;background:var(--surface);color:var(--ecg-dark);">
<option value="all">Öffentlich</option>
<option value="authenticated">Nur Angemeldete</option>
<option value="private">Nur ich</option>
</select>
<button onclick="v2DetailAddComment('{{ antrag.drucksache | e }}')"
style="padding:5px 14px;border:none;border-radius:4px;background:var(--ecg-blue);color:#fff;cursor:pointer;font-family:var(--font-mono);font-size:11px;font-weight:700;">
Absenden
</button>
</div>
</div>
<div id="v2-comment-login-hint" style="display:none;">
<button onclick="v2AuthModalOpen()"
style="padding:5px 12px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-blue);">
Anmelden um zu kommentieren
</button>
</div>
</div>
</details>
{% endblock %}
{# ─── Topbar-Pill + Toggle + Glossar-Tooltips (JS) ───────────────────── #}
{% block body_scripts %}
{{ super() }}
<script>
/* v3-Topbar-Pill + Toggle zurueck zu Profi-Modus injizieren */
/* Topbar: Beta-Pill + Toggle zurueck zu Profi-Modus */
(function () {
var bar = document.querySelector('.v2-topbar');
if (!bar) return;
var pill = document.createElement('span');
pill.className = 'v3-beta-badge';
pill.textContent = 'Bürger:innen-Modus · Beta';
pill.title = 'Vereinfachte Ansicht für Erst-Leser:innen. v3 ist eine frühe Vorschau.';
pill.title = 'Vereinfachte Ansicht für Erst-Leser:innen.';
var toggle = document.createElement('a');
toggle.className = 'v3-modus-toggle';
toggle.href = '/antrag/' + encodeURIComponent({{ antrag.drucksache | tojson }});
toggle.textContent = '→ Profi-Modus';
toggle.title = 'Volle GWÖ-Detailansicht (v2) öffnen';
bar.appendChild(pill);
bar.appendChild(toggle);
})();
/* Glossar-Tooltips: Klick/Focus öffnet Pop-up mit Alltags-Definition. */
window._v3Glossar = {
"drucksache": {
titel: "Drucksache",
text: "Eine Drucksache ist die offizielle Nummer eines Antrags im Parlament. Format: <Wahlperiode>/<laufende Nummer>. Beispiel: '18/18246' = 18. Wahlperiode, Nummer 18246. Über diese Nummer findest du den Antrag in den Parlamentsakten."
},
"fraktion": {
titel: "Fraktion",
text: "Eine Fraktion ist die Gruppe der Abgeordneten einer Partei im Parlament. Sie ist nicht dasselbe wie die Partei selbst — die Partei ist die Organisation außerhalb, die Fraktion sind die gewählten Abgeordneten innerhalb."
},
"gwoe-score": {
titel: "Gemeinwohl-Score (010)",
text: "Der GWÖ-Score bewertet, wie stark der Antrag dem Gemeinwohl dient — auf einer Skala von 0 bis 10. Höher = besser für die Allgemeinheit. Der Wert ist ein gewichteter Durchschnitt aus 25 Bewertungs-Feldern (5 Werte × 5 Berührungsgruppen). Mehr unter /methodik."
},
"gwoe-matrix": {
titel: "GWÖ-Matrix 2.0",
text: "Die Gemeinwohl-Matrix ist ein Bewertungsraster mit 25 Feldern: 5 Werte (Menschenwürde, Solidarität, Nachhaltigkeit, Gerechtigkeit, Transparenz) × 5 Berührungsgruppen (Lieferant:innen, Finanzen, Verwaltung, Bürger:innen, Gesellschaft & Natur). Jedes Feld bekommt eine Bewertung von 5 (stark widersprechend) bis +5 (stark fördernd)."
},
"heuchelei": {
titel: "Heuchelei-Marker (⚠)",
text: "Wird angezeigt, wenn eine Fraktion mit Nein gestimmt hat, obwohl der Antrag inhaltlich gut zu ihrem eigenen Wahlprogramm passt (Wahlprogramm-Score ≥ 7 von 10). Der Marker macht die Lücke zwischen Wahlversprechen und Abstimmungsverhalten sichtbar."
},
"opportunismus": {
titel: "Opportunismus-Marker (!)",
text: "Wird angezeigt, wenn eine Fraktion mit Ja gestimmt hat, obwohl der Antrag schlecht zum eigenen Wahlprogramm passt (Wahlprogramm-Score < 3 von 10). Mögliches Anzeichen für taktisches Stimmverhalten."
}
};
window.v3OpenGlossar = function (key) {
var data = window._v3Glossar[key];
if (!data) return;
var modal = document.getElementById('v3-glossar-modal');
if (!modal) return;
document.getElementById('v3-glossar-title').textContent = data.titel;
document.getElementById('v3-glossar-body').textContent = data.text;
modal.style.display = 'flex';
};
document.addEventListener('click', function (e) {
var t = e.target.closest('.v3-glossar');
if (t) {
e.preventDefault();
window.v3OpenGlossar(t.dataset.glossar);
}
});
document.addEventListener('keydown', function (e) {
if ((e.key === 'Enter' || e.key === ' ') && document.activeElement && document.activeElement.classList.contains('v3-glossar')) {
e.preventDefault();
window.v3OpenGlossar(document.activeElement.dataset.glossar);
}
if (e.key === 'Escape') {
var m = document.getElementById('v3-glossar-modal');
if (m && m.style.display === 'flex') { m.style.display = 'none'; }
}
});
</script>
{# Glossar-Modal #}
<div id="v3-glossar-modal" class="v3-glossar-modal" role="dialog" aria-modal="true"
aria-labelledby="v3-glossar-title"
onclick="if(event.target===this)this.style.display='none'">
<div class="v3-glossar-card">
<div class="v3-glossar-head">
<strong id="v3-glossar-title"></strong>
<button class="v3-glossar-close"
onclick="document.getElementById('v3-glossar-modal').style.display='none'"
aria-label="Schließen">×</button>
</div>
<p id="v3-glossar-body"></p>
</div>
</div>
{% endblock %}