feat(v3): Wortwahl entjargonisiert, Layout-Reorganisation, Score mit Farb-Tint

Wortwahl (User-feedback: "vermeide Konfidenz, neutralere Formulierung
als Heuchelei"):
- "Konfidenz" → "Bewertungs-Sicherheit" (Tooltip behält wissenschaftl. Begriff)
- "Heuchelei-Marker"/"Opportunismus-Marker" → einheitlich
  "Wahlprogramm-Konflikt" (Tooltip behält wissenschaftl. Klassifikation)
- "Mehrheit kontra GWÖ-Empfehlung" → "Mehrheit gegen GWÖ-Empfehlung"
- Marker-Legende-Block entfernt (Tooltip pro Marker reicht)

Layout-Reorganisation:
- Stärkster/Schwächster Wert nach oben — zwischen Bewertung und
  User-Aktionen (vorher in "Rest"). Grid 2-spaltig, responsive.
- Konsistenz-Hinweis ("Mehrheit ... GWÖ-Empfehlung") an die Spitze
  des Abstimmungsergebnis-Blocks (vorher in "Rest").
- Marker-Legende komplett raus.

Visuelles:
- Score x/10 mit Farb-Tint hinterlegt: --score-{high,mid,low}-bg/-fg
  aus tokens.css. Farbe folgt der Score-Schwelle (≥7 grün, 4-6 mittel,
  <4 rot).
- Globale `body.v2 p { max-width: 72ch }` mit höherer Spezifität für
  .v3-page-Children überschrieben — alle Body-Texte nehmen volle Breite.

Programm-Treue Fallback:
- Wenn keine Zitate für ein Programm gefunden: erklärender
  Hinweistext im Body-Bereich, statt leerer Block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dotty Dotter 2026-05-07 11:16:39 +02:00
parent f471586f33
commit 9eaa376fbe
2 changed files with 93 additions and 73 deletions

View File

@ -88,15 +88,22 @@
.v3-score-num {
font-family: var(--font-sans);
font-weight: 900;
font-size: 56px;
font-size: 52px;
line-height: 1;
color: var(--ecg-dark);
padding: 8px 16px 6px;
border-radius: 4px;
display: inline-flex;
align-items: baseline;
background: var(--score-mid-bg);
color: var(--score-mid-fg);
}
.v3-score-num.good { background: var(--score-high-bg); color: var(--score-high-fg); }
.v3-score-num.mid { background: var(--score-mid-bg); color: var(--score-mid-fg); }
.v3-score-num.low { background: var(--score-low-bg); color: var(--score-low-fg); }
.v3-score-slash {
font-size: 30px;
font-size: 26px;
font-weight: 700;
color: var(--ecg-dark);
opacity: 0.4;
opacity: 0.55;
margin-left: 2px;
}
.v3-empfehlung {
@ -774,3 +781,30 @@
font-size: 11px;
color: var(--ecg-blue);
}
/* Volle Breite für Body-Texte: globale `body.v2 p { max-width: 72ch }`
Regel überschreiben (höhere Spezifität durch body.v2 + .v3-page). */
body.v2 .v3-page p { max-width: none; }
/* ── Stärken/Schwächen oben, nebeneinander wenn Platz ────────────── */
.v3-werte-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 12px;
}
.v3-werte-grid .v2-kasten {
margin: 0; /* gridded, kein zusätzlicher Margin */
}
/* ── Fallback-Text wenn keine Zitate gefunden ────────────────────── */
.v3-prog-no-zitate {
font-size: 12.5px;
line-height: 1.55;
color: var(--ecg-dark);
opacity: 0.72;
background: var(--surface);
border-left: 2px dashed var(--hairline);
padding: 8px 12px;
margin: 4px 0 0;
border-radius: 0 2px 2px 0;
}

View File

@ -94,7 +94,8 @@
<section class="v3-section v3-bewertung">
{% set s = (antrag.score | default(0)) | float %}
<div class="v3-bewertung-head">
<div class="v3-score-num">
<div class="v3-score-num
{% if s >= 7 %}good{% elif s >= 4 %}mid{% else %}low{% endif %}">
{{ "%.1f"|format(s) }}<span class="v3-score-slash">/10</span>
</div>
{% if antrag.verdict_title %}
@ -105,8 +106,8 @@
</div>
{% if antrag.konfidenz %}
<span class="v3-konfidenz v3-konfidenz-{{ antrag.konfidenz | lower }}"
title="Bewertungs-Konfidenz: wie sicher ist das LLM in dieser Einschätzung?">
Konfidenz: {{ antrag.konfidenz }}
title="Wie sicher ist die Bewertung des LLM? — wissenschaftlicher Begriff: Konfidenz.">
Bewertungs-Sicherheit: {{ antrag.konfidenz }}
</span>
{% endif %}
</div>
@ -117,6 +118,35 @@
{% endif %}
</section>
{# 3b ── Stärkster + Schwächster Wert (nach Bewertung, vor User-Aktionen) #}
{% if antrag.staerkster_wert or antrag.staerken or antrag.schwaechster_wert or antrag.schwaechen %}
<section class="v3-section v3-werte-grid">
{% if antrag.staerkster_wert and antrag.staerkster_wert.text %}
<div class="v2-kasten outline-green">
<h4>Stärkster Wert{% if antrag.staerkster_wert.titel %} — {{ antrag.staerkster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.staerkster_wert.text }}</p>
</div>
{% elif antrag.staerken %}
<div class="v2-kasten outline-green">
<h4>Stärken</h4>
<ul>{% for s in antrag.staerken %}<li>{{ s }}</li>{% endfor %}</ul>
</div>
{% endif %}
{% if antrag.schwaechster_wert and antrag.schwaechster_wert.text %}
<div class="v2-kasten outline-blue">
<h4>Schwächster Wert{% if antrag.schwaechster_wert.titel %} — {{ antrag.schwaechster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.schwaechster_wert.text }}</p>
</div>
{% elif antrag.schwaechen %}
<div class="v2-kasten outline-blue">
<h4>Schwächen</h4>
<ul>{% for s in antrag.schwaechen %}<li>{{ s }}</li>{% endfor %}</ul>
</div>
{% endif %}
</section>
{% endif %}
{# 4 ── Merken + Bewertung treffend (User-Aktionen) ──────────────── #}
<section class="v3-section v3-userrow">
<button id="v2-merkliste-btn" onclick="v2DetailMerklisteToggle()" class="v3-action-btn">
@ -187,6 +217,13 @@
{{ quote_card(z.text, z.source, True, False, z.pdf_href) }}
{% endfor %}
</div>
{% else %}
<p class="v3-prog-no-zitate">
Keine wörtlich passenden Stellen im {{ prog_label }} gefunden.
Die Bewertung beruht auf inhaltlicher Auslegung — entweder benennt das Programm
das konkrete Thema nicht explizit, oder es bleibt zu allgemein, um wörtlich
zugeordnet zu werden.
</p>
{% endif %}
</div>
</details>
@ -228,6 +265,17 @@
{% if antrag.plenum_votes %}
<section class="v3-section v3-vote-section">
<h3 class="v3-h3">Abstimmungsergebnis</h3>
{# Konsistenz-Hinweis: GWÖ-Empfehlung vs tatsaechlicher Beschluss #}
{% set _state = consistency_state(antrag.verdict_title, antrag.plenum_votes) %}
{% set _decisive = decisive_outcome(antrag.plenum_votes) %}
{% if _state %}
<div class="v3-konsistenz {{ _state }}">
<strong>{% if _state == 'conflict' %}Mehrheit gegen GWÖ-Empfehlung{% else %}Mehrheit deckt sich mit GWÖ-Empfehlung{% endif %}</strong>
— Empfohlen: <em>{{ antrag.verdict_title }}</em>; Beschluss: <em>{{ _decisive | capitalize }}</em>.
</div>
{% endif %}
{% set ergebnis_color = {
"angenommen":"#2da44e","abgelehnt":"#cf222e","überwiesen":"#0969da",
"zurückgezogen":"#8250df","bestätigt":"#2da44e","sammel":"#0969da",
@ -268,7 +316,7 @@
<div><span class="v3-vote-side ja">Ja:</span>
{% for f in v.fraktionen_ja %}
{% set _opp = opportunismus_score(f, antrag.fraktions_scores) %}
<span class="v3-vote-pill ja">{{ f }}{% if _opp is not none %}<span class="v3-marker opp" tabindex="0" role="button" title="Opportunismus-Marker — Ja trotz schwacher Wahlprogramm-Übereinstimmung (WP-Score {{ '%.0f' | format(_opp) }}/10).">!</span>{% endif %}</span>
<span class="v3-vote-pill ja">{{ f }}{% if _opp is not none %}<span class="v3-marker opp" tabindex="0" role="button" title="Wahlprogramm-Konflikt — Diese Fraktion stimmte mit Ja, obwohl der Antrag schlecht zum eigenen Wahlprogramm passt (Wahlprogramm-Score {{ '%.0f' | format(_opp) }}/10). Wissenschaftliche Klassifikation: Opportunismus-Indikator.">!</span>{% endif %}</span>
{% endfor %}
</div>
{% endif %}
@ -276,7 +324,7 @@
<div><span class="v3-vote-side nein">Nein:</span>
{% for f in v.fraktionen_nein %}
{% set _wp = heuchelei_score(f, antrag.fraktions_scores) %}
<span class="v3-vote-pill nein">{{ f }}{% if _wp is not none %}<span class="v3-marker heuchelei" tabindex="0" role="button" title="Heuchelei-Marker — Nein trotz hoher Wahlprogramm-Übereinstimmung (WP-Score {{ '%.0f' | format(_wp) }}/10)."></span>{% endif %}</span>
<span class="v3-vote-pill nein">{{ f }}{% if _wp is not none %}<span class="v3-marker heuchelei" tabindex="0" role="button" title="Wahlprogramm-Konflikt — Diese Fraktion stimmte mit Nein, obwohl der Antrag inhaltlich gut zum eigenen Wahlprogramm passt (Wahlprogramm-Score {{ '%.0f' | format(_wp) }}/10). Wissenschaftliche Klassifikation: Heuchelei-Indikator."></span>{% endif %}</span>
{% endfor %}
</div>
{% endif %}
@ -355,69 +403,7 @@
</div>
</div>
{# 9e Stärken / Schwächen #}
{% if antrag.staerkster_wert and antrag.staerkster_wert.text %}
<div class="v2-kasten outline-green">
<h4>Stärkster Wert{% if antrag.staerkster_wert.titel %} — {{ antrag.staerkster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.staerkster_wert.text }}</p>
</div>
{% elif antrag.staerken %}
<div class="v2-kasten outline-green">
<h4>Stärken</h4>
<ul>
{% for s in antrag.staerken %}<li>{{ s }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{% if antrag.schwaechster_wert and antrag.schwaechster_wert.text %}
<div class="v2-kasten outline-blue">
<h4>Schwächster Wert{% if antrag.schwaechster_wert.titel %} — {{ antrag.schwaechster_wert.titel }}{% endif %}</h4>
<p>{{ antrag.schwaechster_wert.text }}</p>
</div>
{% elif antrag.schwaechen %}
<div class="v2-kasten outline-blue">
<h4>Schwächen</h4>
<ul>
{% for s in antrag.schwaechen %}<li>{{ s }}</li>{% endfor %}
</ul>
</div>
{% endif %}
{# 9f Konsistenz-Hinweis #}
{% if antrag.plenum_votes %}
{% set _state = consistency_state(antrag.verdict_title, antrag.plenum_votes) %}
{% set _decisive = decisive_outcome(antrag.plenum_votes) %}
{% if _state %}
<div class="v3-konsistenz {{ _state }}">
<strong>{% if _state == 'conflict' %}Mehrheit kontra GWÖ-Empfehlung{% else %}Mehrheit deckt sich mit GWÖ-Empfehlung{% endif %}</strong>
— Empfohlen: <em>{{ antrag.verdict_title }}</em>; Beschluss: <em>{{ _decisive | capitalize }}</em>.
</div>
{% endif %}
{% endif %}
{# 9g Marker-Legende — nur wenn ⚠ oder ! im Vote-Block vorkam #}
{% set _legende = namespace(heuchelei=false, opp=false) %}
{% for vv in (antrag.plenum_votes or []) %}
{% for f in (vv.fraktionen_nein or []) %}
{% if heuchelei_score(f, antrag.fraktions_scores) is not none %}{% set _legende.heuchelei = true %}{% endif %}
{% endfor %}
{% for f in (vv.fraktionen_ja or []) %}
{% if opportunismus_score(f, antrag.fraktions_scores) is not none %}{% set _legende.opp = true %}{% endif %}
{% endfor %}
{% endfor %}
{% if _legende.heuchelei or _legende.opp %}
<div class="v3-marker-legend">
{% if _legende.heuchelei %}
<div><span class="v3-marker heuchelei"></span> <strong>Heuchelei:</strong> Nein trotz hoher Wahlprogramm-Übereinstimmung (WP&nbsp;&nbsp;7/10).</div>
{% endif %}
{% if _legende.opp %}
<div><span class="v3-marker opp">!</span> <strong>Opportunismus:</strong> Ja trotz schwacher Wahlprogramm-Übereinstimmung (WP&nbsp;&lt;&nbsp;3/10).</div>
{% endif %}
</div>
{% endif %}
{# 9h News-Box (per JS gefuellt) #}
{# News-Box (per JS gefuellt) #}
<div id="ad-news-box" class="v3-news-box" style="display:none;">
<h3 class="v3-h3">Aktuelle News passend zu diesem Antrag</h3>
<p class="v3-news-meta">Embedding-Match aus den letzten 90 Tagen. Quelle: Tagesschau-API + Bundestag-RSS.</p>