diff --git a/backend/main.py b/backend/main.py index 2b66a02..2905e10 100644 --- a/backend/main.py +++ b/backend/main.py @@ -5,6 +5,7 @@ from contextlib import asynccontextmanager from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse, PlainTextResponse from fastapi.staticfiles import StaticFiles +from fastapi.middleware.gzip import GZipMiddleware from pydantic import BaseModel from . import config, montage, pipeline, state @@ -21,6 +22,7 @@ async def lifespan(app: FastAPI): app = FastAPI(title="buchwerk", lifespan=lifespan) +app.add_middleware(GZipMiddleware, minimum_size=1000) # Buchdaten sind 1–2 MB JSON class ThemaNeu(BaseModel): diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 5a0bf38..42434e8 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -102,6 +102,7 @@ function tokens(n) { return n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' : n >= 1e3 ? M diff --git a/frontend/src/style.css b/frontend/src/style.css index 17bd63a..a43e744 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -121,7 +121,7 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; } /* Buch-Ansicht */ .guide { flex: 1; display: flex; min-height: 0; } -.guide-nav { width: 270px; min-width: 240px; overflow-y: auto; padding: 14px 10px; border-right: 1px solid var(--rand); background: var(--panel); font-size: 13px; } +.guide-nav { width: 270px; min-width: 240px; overflow-y: auto; padding: 14px 10px; border-right: 1px solid var(--rand); background: var(--panel); font-size: 14px; } .guide-nav .werkzeuge { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; } .guide-nav .meta { color: var(--dim); font-size: 12px; margin-bottom: 10px; } .guide-nav a.kap { display: flex; align-items: baseline; gap: 6px; padding: 6px 8px; border-radius: 6px; cursor: pointer; color: var(--text); text-decoration: none; font-weight: 600; margin-top: 6px; } @@ -129,7 +129,7 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; } .guide-nav a.kap .t { flex: 1; } .guide-nav a.abs { display: flex; justify-content: space-between; gap: 6px; padding: 3px 8px 3px 24px; border-radius: 6px; cursor: pointer; color: var(--dim); text-decoration: none; } .guide-nav a.aktiv { background: var(--karte); color: var(--text); } -.guide-nav .zeit { color: var(--dim); font-size: 11px; white-space: nowrap; } +.guide-nav .zeit { color: var(--dim); font-size: 12px; white-space: nowrap; } .guide-nav .fortschritt { height: 4px; background: var(--karte); border-radius: 2px; margin: 8px 0 4px; overflow: hidden; } .guide-nav .fortschritt i { display: block; height: 100%; background: var(--gruen); } .guide-nav .leer { color: var(--dim); padding: 8px; } @@ -201,6 +201,12 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; } .lm-fuss button.weiter { background: var(--akzent); color: #fff; border: 0; } kbd { font: 11px system-ui, sans-serif; border: 1px solid var(--rand); border-radius: 4px; padding: 0 5px; margin-left: 6px; color: var(--dim); } +/* Barrierefreiheit: sichtbarer Fokus für Tastatur, Sprunglink, keine Animationen auf Wunsch */ +:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; } +.skip { position: absolute; left: -999px; top: 8px; z-index: 100; background: var(--akzent); color: #fff; padding: 8px 12px; border-radius: 6px; } +.skip:focus { left: 8px; } +@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; } } + @media (max-width: 800px) { .topbar { gap: 8px; padding: 8px 10px; flex-wrap: nowrap; } .topbar .badge { display: none; } @@ -212,8 +218,10 @@ kbd { font: 11px system-ui, sans-serif; border: 1px solid var(--rand); border-ra .burger { display: inline-block; } .guide-nav { display: none; } .guide-nav.offen { display: block; position: fixed; inset: 0 auto 0 0; z-index: 25; width: 82vw; font-size: 14.5px; } - .guide-nav.offen a.kap { padding: 10px 8px; } - .guide-nav.offen a.abs { padding: 8px 8px 8px 24px; } + .guide-nav.offen a.kap { padding: 12px 8px; min-height: 44px; box-sizing: border-box; } + .guide-nav.offen a.abs { padding: 10px 8px 10px 24px; min-height: 44px; box-sizing: border-box; align-items: center; } + .mobil-leiste button, .mobil-leiste a.knopf, .burger, .topbar .tabs button, .lm-kopf button, .guide-nav .schliessen { min-height: 44px; min-width: 44px; padding: 10px 14px; font-size: 14px; } + .mobil-leiste { flex-wrap: wrap; } .buch { padding: 22px 16px 100px; font-size: 1.02rem; } .lm-screen { padding: 24px 16px 60px; font-size: 1.05rem; } .lm-kopf, .lm-fuss { padding: 8px 12px; }