# Frontend A **hand-authored single-page app** in `index.html` + `static/` — no Gradio Blocks at the root, no `gr.ChatInterface`. The page is served by `build_server()` in `../backend/server.py`, which mounts `static/` and returns `index.html` from `/`. The page connects back to the same origin via the Gradio JS client (`@gradio/client`) and calls the registered `@app.api` endpoints. ## What's on the page - **Hero** with a two-branch entry point: *I'm employed — benchmark my pay* / *I'm job-seeking — prep for an offer*. - **Onboarding wizard** (`#wizard`) — 9 questions, branch-aware, with a per-step help text written in plain language. Salary entry supports either a known total range or `base × (1 + perks%)`. - **Dashboard** (`#dashboard`) — KPI row, comparison cards from real IDA cells, and a "make it visual" toggle that swaps in hand-drawn SVG charts: - Bell curve of your peer group with your pay marked and the percentile computed via a JS-side normal CDF - Circular gauge of your standing - Horizontal comparison bars across all matched IDA cells - **Rights chat** (`#rights`) — seeded with profile-aware suggested questions (e.g. mode-, sector-, headcount-, gender-driven), session-only document upload, inline citations and disclaimer rendered under each reply. - **Language switcher** (EN / DA / FR) wired through `static/i18n.js`. All charts are hand-rolled SVG (no charting library) and degrade gracefully down to a single matched cell. ## Style system `static/styles.css` defines a Scandinavian / Djøf-inspired token system: - Sage hero (`#C4D5D3`), ink near-black (`#15211D`), deep-teal accent (`#1F4A3F`), sage-light alt sections (`#E7EFEE`). - Display: **Bricolage Grotesque**. Body: **Inter**. Both via Google Fonts. - Pill, rounded, and editorial radii (`--radius-md/lg/xl/pill`) plus a custom shadow scale and motion tokens. This is the project's Off-Brand UI; Gradio's own theming engine is **not** used on the served page. ## Start it From the repo root: ```bash uv run python main.py ``` `main.py` calls `build_server().launch(...)`, which serves `index.html` at `/` and the API endpoints alongside it. ## API contract used by the SPA | `api_name` | Used by | |---|---| | `/dashboard` | `submitProfile()` after the wizard | | `/chat` | `sendMessage()` (rights chat) | | `/parse_lonstatistik` | `uploadDocument()` (file upload) | See `../backend/api/endpoints.py` for the registered endpoints and `../backend/schemas.py` for the request/response models. ## Editing - **Layout / wizard / chat behavior:** `static/app.js`. - **Translations:** `static/i18n.js` (`en` populated; `da`/`fr` keys exist with empty values, falling back to EN). - **Style:** `static/styles.css` (token system at the top, sectioned by component below). - **Page shell:** `index.html`.