diff --git a/app/main.py b/app/main.py index bcaee73..606a0c9 100644 --- a/app/main.py +++ b/app/main.py @@ -3515,7 +3515,7 @@ async def scorecard_template( } width, height = dimensions.get(format, dimensions["og"]) - return templates.TemplateResponse("v2/screens/scorecard.html", { + response = templates.TemplateResponse("v2/screens/scorecard.html", { "request": request, "assessment": assessment, "bundesland": bundesland, @@ -3526,6 +3526,10 @@ async def scorecard_template( "width": width, "height": height, }) + # No-cache fuer die Live-Preview, sonst zeigt der Browser nach Layout- + # Aenderungen die alte HTML-Variante an. + response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate" + return response async def _render_scorecard_pdf( diff --git a/app/templates/v2/screens/scorecard.html b/app/templates/v2/screens/scorecard.html index 836f98d..cc0bbcc 100644 --- a/app/templates/v2/screens/scorecard.html +++ b/app/templates/v2/screens/scorecard.html @@ -154,29 +154,17 @@ /* ── portrait Layout — ausbalancierte vertikale Komposition. - Sektions-Hierarchie (top → bottom): - 1. Header-Bar (kicker + meta) ~50 px - 2. Title (kompakt, 3 Zeilen max) ~150 px - 3. Fraktionen-Pills ~40 px - 4. Score-Hero (full-width Farbband) ~280 px - 5. Matrix-Block (Grid + Legende) ~480 px - 6. Begründung (4 Zeilen) ~140 px - 7. Footer (absolut, ~50 px vom unteren Rand) - Summe ~1190 + Padding 58 + Gaps ~30 = 1280 / 1350 → ~70 px Slack, - gleichmaessig per justify-content space-between auf die fuenf - inneren Sektionen verteilt. - - Visuelle Hierarchie: Score-Hero ist optisch prominent (groesster - Farbblock + groesste Zahl), Matrix als datenreiches Zentrum, Title - deskriptiv aber zurueckhaltend, Begruendung als Ausklang. */ + Statt justify-content: space-between (verteilt Slack-Raum unkontrol- + liert) absorbiert .portrait-matrix-block per flex-grow:1 die ueber- + schuessige Hoehe. Matrix bleibt visuell zentriert, andere Sektionen + in natuerlicher Groesse oben/unten. */ .portrait-body { flex: 1; display: flex; flex-direction: column; - justify-content: space-between; - gap: 18px; - margin-top: 18px; - padding-bottom: 28px; + gap: 14px; + margin-top: 16px; + padding-bottom: 32px; } .portrait-title { @@ -253,65 +241,83 @@ line-height: 1.08; } - /* ── Matrix-Block: Grid links, Legende rechts, vertikal zentriert ── */ + /* ── Matrix-Block: Grid mit beschrifteten Achsen, vertikal zentriert. + flex-grow:1 absorbiert allen verbleibenden Slack der Karte. */ .portrait-matrix-block { + flex-grow: 1; display: flex; + flex-direction: column; align-items: center; - gap: 28px; + justify-content: center; + gap: 12px; } - .portrait-matrix { + .portrait-matrix-grid { + /* 5 Werte als Spalten + 1 Spalte fuer die Zeilen-Labels */ display: grid; - grid-template-columns: repeat(5, 1fr); - grid-template-rows: repeat(5, 1fr); + grid-template-columns: 130px repeat(5, 88px); + grid-template-rows: 36px repeat(5, 88px); gap: 4px; - width: 480px; - height: 480px; - flex-shrink: 0; - /* Kein weisser Frame — der Karten-Hintergrund (Gradient) wird - durch die gap-Zwischenraeume sichtbar, die Cells stehen klar - als Farbflaechen heraus. */ + align-items: stretch; } - .portrait-matrix-legend { - flex: 1; + .portrait-matrix-grid .col-label { font-family: 'Source Code Pro', monospace; - font-size: 12pt; - color: #444; - line-height: 1.55; - } - .portrait-matrix-legend .l-title { + font-size: 9.5pt; font-weight: 700; - text-transform: uppercase; color: #009DA5; - margin-bottom: 14px; - letter-spacing: 0.08em; - font-size: 12pt; + text-transform: uppercase; + letter-spacing: 0.04em; + display: flex; + align-items: end; + justify-content: center; + padding-bottom: 4px; + text-align: center; + line-height: 1.1; } - .portrait-matrix-legend ul { - list-style: none; - padding: 0; - margin: 0; - } - .portrait-matrix-legend li { + .portrait-matrix-grid .row-label { + font-family: 'Source Code Pro', monospace; + font-size: 10pt; + font-weight: 700; + color: #009DA5; + text-transform: uppercase; + letter-spacing: 0.04em; display: flex; align-items: center; - gap: 10px; - margin-bottom: 7px; + padding-right: 8px; + line-height: 1.15; } - .portrait-matrix-legend .swatch { - width: 22px; height: 22px; border-radius: 2px; flex-shrink: 0; - border: 1px solid rgba(0,0,0,0.08); + .portrait-matrix-grid .corner { + /* leere Ecke oben links */ + } + .portrait-legend-row { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px 18px; + font-family: 'Source Code Pro', monospace; + font-size: 10.5pt; + color: #444; + margin-top: 4px; + } + .portrait-legend-row .legend-item { + display: inline-flex; + align-items: center; + gap: 6px; + } + .portrait-legend-row .swatch { + width: 18px; height: 18px; border-radius: 2px; flex-shrink: 0; } .portrait-summary { font-size: 13pt; - line-height: 1.55; + line-height: 1.5; color: #333; display: -webkit-box; - -webkit-line-clamp: 4; + -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; border-top: 1px solid rgba(0,0,0,0.08); padding-top: 14px; + flex-shrink: 0; } .portrait-summary-label { display: block; @@ -369,8 +375,25 @@